framewright は何をしますか?
あなたは、版画家が版画を制作するように短い動画を作成します。1つのHTMLファイルに、キャンバス、プレートと呼ばれるシーンのリスト、そして任意のフレームを(フレーム番号、シード、幅)から描画するフレーム関数が含まれます。映像素材、画像ファイル、CDNからの読み込みは一切ありません。フレームはヘッドレスChromeでレンダリングされ、ffmpegで結合されます。サウンドは最後に、確定したシーン長に合わせて合成されます。
ユーザーとはその言語で話してください。ユーザーが急いでいる場合でも、以下のルールを守ってください。ここでのショートカットは、すべて節約以上のコストがかかります。
以下のSKILL_DIRは、このファイルが含まれるフォルダを指します(Claude Codeでは ${CLAUDE_SKILL_DIR}、それ以外では .agents/skills/framewright)。ステップ3の後、スクリプトはプロジェクト自身の scripts/ フォルダにも配置されます。
非妥協事項
- フレームは、フレーム番号、シード、出力幅のみに依存します。
Math.random、壁時計、CSSアニメーション、requestAnimationFrameを時間ソースとして使用してはいけません。scripts/check.mjsはフルレンダリングの前にこれを証明します。 - 画像、動画、フォント、ライブラリファイル、base64、CDNは使用禁止です。スクリプトによって写真からトレースされたポリゴンはデータであり、問題ありません。システムフォントで十分です。
- 検証はレンダリングされたフレームを見て行い、コードを読んで想像してはいけません。修正は必ずフレームで確認します。
- 一度に1シーンずつ。プレートを書き、3フレームを撮影し、確認し、修正し、次のプレートに進みます。
- シーンの長さは、最初の草案のビートの倍数です。サウンドは最後に作成します。
- フルレンダリングは、動画全体のコンタクトシートが正しく見えるようになってから行います。
frames/、shots/、*.mp4、*.wav、またはユーザーの写真をコミットしてはいけません。- システムパッケージをインストールする前に確認を取ってください。ユーザーが使用権限を確認していない限り、実在の人物の肖像を公開してはいけません。
ワークフロー概要
| ステップ | 内容 | ユーザーとのチェックポイント |
|---|---|---|
| 0 | 環境チェック | インストールが必要なものがある場合のみ |
| 1 | ブリーフ | 質問票、1ブロック |
| 2 | コンセプト | 3つのオプション、1つを選択 |
| 3 | ストーリーボード + スキャフォールド | 1回の「GO」 |
| 4 | シーン、1つずつ | 2〜3シーンごとにコンタクトシート |
| 5 | アセット(写真、ロゴ) | トレースした肖像のプレビュー |
| 6 | フルシート、レンダリング、ビルド | プレビューMP4 |
| 7 | サウンド | 再ビルドされたMP4 |
| 8 | 納品とバリエーション | 最終 |
標準的な実時間:ブリーフとコンセプト10分、スキャフォールド10分、各シーン10〜20分、1080p動画1分あたりのレンダリング2〜4分、サウンド15分。
ステップ0. 環境
bash SKILL_DIR/scripts/doctor.sh # レポートを表示; --json で機械可読な要約を出力
bash SKILL_DIR/scripts/doctor.sh --install # 不足しているものをインストール、各ステップで確認
必須: Node 20+、npm、libx264対応のffmpeg、プロジェクト内のPuppeteerとChrome。
オプション: 写真をトレースする場合のみ、numpy、scipy、Pillowを含むPython 3。doctorが不足ツールを報告した場合、インストールするものと場所をユーザーに伝え、同意を得てから --install を実行します(ユーザーがすでに同意している場合は --yes を追加)。doctorが失敗している状態でステップ3を開始しないでください。
ステップ1. ブリーフ
references/questionnaire.md から質問票を実行します。ハーネスの構造化質問ツールが存在する場合はそれを使用します(Claude Code: AskUserQuestion、1回の呼び出しにつき最大4つの質問、各質問に2〜4の選択肢、推奨オプションを最初に配置しマークします)。そのようなツールがない場合は、質問を番号付きリストと各質問のアルファベット選択肢、デフォルト値とともに出力し、1b 2a 3c のような簡潔な回答を受け付けます。必ず以下の順序で質問します:
- メッセージ:視聴者が理解または感じるべきことを一文で。画面上に表示しなければならない名前、日付、リンク、正確なフレーズ。
- 再生場所とフォーマット:16:9、9:16、1:1、4:5。
- 長さ:10〜15、20〜25、30〜40、45〜60秒。
- トーン:遊び心、無表情、温かみ、壮大、技術的、ダーク。
- スタイル:あなたに提案させる(デフォルト)か、
references/styles.mdからの系統。 - アセット:写真、ロゴ、スクリーンショット。ファイルはプロジェクトフォルダに配置する必要があります。チャットに貼り付けられた画像は保存できません。実在の人物の権利について質問します。
- サウンド:合成、なし、またはユーザーのトラック用のスペース(その場合はBPMを質問)。
- 成果物と品質:ドラフトか最終版か、追加のカット(縦長、GIF、ポスターフレーム、シードバリエーション)、MP4の最初のフレームとしてのカバー(フィードでプレビューとして表示されます)。
ユーザーが「あなたに決めて」と言った場合は、デフォルト値を採用し、どのデフォルトを採用したかを伝えて先に進みます。
ステップ2. コンセプト
コードを書く前に、正確に3つのコンセプトを提案します。3つの角度から構築します:文字通り(主題を示す)、比喩(状況を表す視覚システム:待機のためのテレビテストカード、計画のためのブループリント、プロセスのためのターミナル)、ジャンルパロディ(ニュース速報、アーケードアトラクトモード、安全カード、天気予報、テレテキスト)。各コンセプトについて以下を提供します:名前、一文のログライン、視覚システムとパレット、3〜5の主要シーン(順序付き)、エンディング、サウンドのスケッチ、適合する理由、主なリスク。コンパクトな表を提示し、1つを推薦し、ユーザーに選択を求めます。方法と実例は references/questionnaire.md にあります。ログラインがカットのない1つの旅(決して持ち上げられない線、詳細から風景への飛行)であるコンセプトは、1つの連続した世界として構築されます(references/world.md)。その行にその旨を記載してください。これはシーンの構築と変更方法を変えるためです。描かれ、ペイントされ、命を吹き込まれる1つのビュー(生き生きとした油絵になる鉛筆画、スタイル13〜16)のコンセプトは、ペインティングフィルムとして構築されます(references/painting.md)。その行にもその旨を記載してください。そのプレートは1つの絵画上の時間の章であり、シーンは作品そのものです。
ステップ3. ストーリーボードとスキャフォールド
storyboard.md を埋めます(テンプレートは assets/storyboard.md):プレートごとに1行、長さを小節数で、ビートグリッド(30 fps、120 BPM:ビート15フレーム、小節60)、メインイベントの秒、合計。合計は合意された長さと等しくなければなりません。後でシーンが追加された場合、別のシーンが1小節を譲ります。表を表示し、1回のGOを求めます。
次にスキャフォールド:
bash SKILL_DIR/scripts/init.sh # index.html、scripts/、audio.mjs、storyboard.md、package.json
bash SKILL_DIR/scripts/init.sh . --world # 同じですが、index.htmlは1つの世界のスケルトン(カットなし)です
bash SKILL_DIR/scripts/init.sh . --painting # ペインティングスケルトン; audio.mjsとnature.mjsが自然音を生成します
npm install # puppeteer(Chromeはキャッシュから取得されるか、一度ダウンロードされます)
node scripts/look.mjs shot 0,30,60 1200 7
画像ビューアでPNGを開いて確認します。スケルトンのデモプレートは、変更する前にレンダリングできる必要があります。その後、デモプレートを最初のシーンに置き換えます。ペインティングフィルムでは、フレーム0は白紙です:代わりに 30,82,200(描画、色の到着、生きている絵画)を撮影し、デモのシーンブロックを交換します。ペインティングキットはそのままにしておきます。
ステップ4. シーン
最初のシーンの前に references/guide.md を一度読んでください。基本事項:
plate('name', {len: 2*BAR}, (S, R) => { ... })。S.tは進行度0..1、S.iはローカルフレーム、S.fはグローバルフレーム、S.gは論理座標(短辺1080)の2Dコンテキスト。Rはプレート全体で安定したジェネレータ。S.bは3フレームごとに再シードされ、生きた線を提供します。S.nzはノイズ用に毎フレーム変化します。シードはプレート名から派生します。- すべてのジオメトリは論理単位で、
CX, CYを中心とします。重要なコンテンツはフレームの中央92%内に保ちます。9:16では、プラットフォームのボタンとキャプションが配置される上部15%と下部20%も避けます。 - プレート内の時間はビート単位:
Math.floor(S.i/BEAT)、span(S.i, a, b)、ease.out(...)。シーン内にグローバルフレーム番号をハードコードしないでください。カットをまたいで続くものは、別のプレートの時間を名前で取得します:at('plate', beats)。サウンドがヒットしなければならない瞬間はCUESに入れ、cue('name')で読み取ります。 - ヘルパーはプレートブロックの上に配置し、プレートの間に置かないでください。
- トランジションはエンジンによってプレートの端で描画されます(
cutIn/cutOutフラグ)。シーンはそれらを認識しません。 - ワールドフィルム(
--world)にはカットがありません。プレートはビルダーbuild(W, {pen, b, R})であり、1つのタイムラインに追加します:b(x)はプレートのビートx、ペンは前のプレートが終わったところから線を続け、camKeyは1つのカメラを移動し、titleはテキストを追加します。最初のビルダーの前にreferences/world.mdを読んでください。 - ペインティングフィルム(
--painting)は、3つのメディアで1つの静止画を描きます。そのプレートはすべてdrawPainting(S)を呼び出します。ビューはSCENEオブジェクトとそのレイヤー(/* ===== scene ===== */と/* ===== end scene ===== */の間)に存在し、その上のペインティングキットはそのままです。最初のレイヤーの前にreferences/painting.mdを読んでください。最初に描画だけを確認し、次にリビール、次にライフを確認します(references/painting.md、セクション13)。
シーンごとに:それを書き、最初のフレーム、中間の1フレーム、終了5フレーム前の1フレームを撮影し、確認し、修正し、再度確認します。2〜3シーンごとに:
node scripts/look.mjs sheet 24 480 7 shots/sheet.png
FROM=240 TO=480 node scripts/look.mjs sheet 12 480 7 shots/sheet-b.png # 1セクション、より密に
シートのチェックリスト、各項目を目で確認:すべてのセルが1.5秒で静止画として読めること。テキストが切れていないこと。隣接する線とパネルが接触していないこと。1つのプレートの隣接する2つのセルが同一に見えないこと。カットが計画通りに着地し、シーンの最初のフレームを食べていないこと。重要なものが外側の8%にないこと。色が濁っていないこと。細い線が崩れていないこと。メインイベントが計画された秒に位置していること。最後のフレームがエンディングのように見えること。同じ場所に2つのタイトルが同時に表示されていないこと。「1.5秒」に不合格のシーンは、装飾ではなく再設計します。空のシーンには、より詳細を追加するのではなく、より大きなオブジェクトかより近いカメラを使用します。混雑したクローズアップは、被写体の周りの装飾を暗くします。ワールドフィルムでは、各プレートの最後のフレームも次のプレートの最初のフレームの隣で撮影します。何もジャンプしてはいけません。
これらのポイントで、ステータスの2文とともにシートをユーザーに送信します。コードについて説明しないでください。
ステップ5. アセット
写真は、ピクセルではなくポスタライズされたポリゴンになります:
bash scripts/portrait.sh photo.jpg --levels 0.14,0.28,0.42,0.56,0.70,0.84 --height 900
node scripts/look.mjs shot <frame in the portrait scene> 1200 7
shots/portrait_preview.png とレンダリングされたフレームを確認します。references/photo.md に従って、レベル、ぼかし、クロップ、背景しきい値を調整します。ファイルがまだフォルダにない間は、スケルトンに同梱されている合成プレースホルダーでシーンを構築し、その旨を伝えます。
ステップ6. フルシート、レンダリング、ビルド
node scripts/look.mjs sheet 24 480 7 shots/sheet.png # 確認、修正、繰り返し
node scripts/check.mjs # 決定論性と自己完結性、OKと表示される必要あり
node scripts/render.mjs frames 7 1920 5 # ディレクトリ、シード、幅(省略時:1920 ランドスケープ、1080 ポートレート)、タブ数
bash scripts/build.sh out.mp4 # フレーム (+ track.wav) -> mp4
チェックは、すべてのプレートの5フレームを7つの順序(新しいタブの最初のフレーム、前方、後方、シャッフル、前のフレームの直後、別の幅の後、レンダリングタブがたどる方法でフィルムをスイープした後)でレンダリングし、同一のピクセルを要求します。また、ソース内の Math.random、Date、performance.now をスキャンし、ページがファイルを要求した場合に失敗し、ビートグリッドと予想レンダリング時間を出力します。レンダリング前にすべてのFAILを修正します。make.sh はチェックを実行し、失敗時に停止します。レンダリング順序によって変化するフレームは、フレームをまたいで存続する状態を示しています:クリアせずに描画されたプールされたキャンバス、プレートが変更するグローバル、すべての入力をキーとしないキャッシュ。
フレームだけでなく、ファイルから確認します:ffprobe フレーム数が look.mjs info の合計と等しいこと、durationがフレーム数÷30に等しいこと、MP4から作成されたタイルがシートと一致すること:
ffmpeg -i out.mp4 -vf "select='not(mod(n\,50))',scale=480:-1,tile=6x4" -frames:v 1 shots/out_sheet.png
最初のMP4が存在したらすぐに、プレースホルダーがあってもユーザーに送信し、何がプレースホルダーかを伝えます。
ステップ7. サウンド
scripts/export-curves.mjs はページから curves.json を書き出します:プレートの開始、キュー、ワールドフィルムのすべてのフレームの線の先端の速度と画面位置、ペインティングフィルムのリビールされたシェア、ライフ、gust、ズーム。audio.mjs はこれからタイムラインを取得するため、画像とずれることはありません(RISO.curves() がないページは、T に手動で look.mjs info から開始位置をコピーする必要があります)。プレートごとに1つのイベントブロックを、references/audio.md のキューマップを使用して記述します。画像がマークするものへのヒットは、ビート番号ではなく、ページのキュー cue('name')(CUES、またはワールドフィルムの W.cues)から時間を取得します。ワールドフィルムでは、線またはキャラクターにカーブに従う声を与えます(follow()、references/audio.md、セクション7)。ペインティングやランドスケープは、ビートの代わりに自然の雰囲気を取得します:風、水、サラサラ音、鳥のさえずりを nature.mjs から、キューとページの gust にタイミングを合わせて、--painting が assets/audio-nature.mjs からコピーする audio.mjs によって(references/audio.md、セクション8、自然の雰囲気)。その後:
node scripts/export-curves.mjs curves.json
node audio.mjs track.wav
ffmpeg -i track.wav -filter_complex "showwavespic=s=1800x300:split_channels=1" -frames:v 1 shots/wave.png
bash scripts/build.sh out.mp4
聞くことはできないので、波形を読み取ります:アクティブなシーン内に偶発的な無音がないこと、シーンが天井に固定されていないこと。シーン長が変更されるたびに、トラックを再生成します。
ステップ8. 納品
out.mp4(1920×1080、H.264、AAC、ノイズの多いスタイルで約0.7MB/秒)を納品し、再ビルド方法を伝えます:bash scripts/make.sh [photo.jpg] [seed] [width]。押し付けずに提案します:別のシード(同じプレートの異なる印象)、縦長カット(AR=9:16 node scripts/render.mjs frames-v 7 1080 5、次に AR=9:16 でシートをチェック。下部のタイトルは高さの70%に配置、TITLE_Y、プラットフォームのボタンに重ならないようにします。GIFは references/gif.md から。--seed で再現性。
ステップ9. プロジェクトの開始(新規からのみ)
既存のプロジェクトの .gitignore または package.json を決して変更しないでください。スキルが最初のinitを実行する新しいプロジェクトでのみ、以下を追加します:
# .gitignore に追加
doctor-report.*
frames*
shots/
*.mp4
*.wav
*.png
SKILL_DIR の内容を .agents/skills/framewright/ にコピーし、プロジェクトのルートでinitスクリプトを実行します。
すべてのスクリプトは以下の場所にあります
SKILL_DIR/scripts/(現在のスキルバージョン)scripts/(ステップ3後に作成されたプロジェクトのコピー)
両方の場所が存在し、必要に応じて使用します。
ユーザーが「もう一度」と言ったり、やり直したい場合は、scripts/、frames/、shots/、storyboard.md、audio.mjs、index.html を削除し、ステップ0からやり直します。写真はそのままにしておきます。