wiggle-that-diagram: 3スタイルで説明するモーション
静止した「仕組み」の図を、短いキャプション付きループアニメーションに変換し、HTMLスライドデッキやレポートに埋め込み、3つのフォーマットで提供します。これにより読者はスタイルを選択できます。この方法は実際のクライアントデッキで練られました(「実践例」参照)。huashu-art-motion をディレクション(ショットリスト、カメラルール、失敗する6つの方法)に使用し、スタイルAとBではレンダリングエンジンとしても使用します。
使用すべき時、使用すべきでない時
使用すべき時:
- スライドデッキやHTMLレポートに機構図(ファイルフロー、ルールチェック、承認フローなど)があり、読者がステップごとにその動作を目で見て、読める文字で理解できるようにしたい場合。
- ユーザーが単なる色違いではなく、本当に異なるフォーマットの選択肢を求めている場合。
- 以前のアニメーションが「速すぎて読めない」、またはキャプションが必要だった場合。
使用すべきでない時: 単一のマイクロインタラクション(animate を使用)、ナレーション付き動画(huashu-art-motion を直接使用)、数値のチャート(dataviz を使用)。
3つのスタイル(フォーマットが異なり、パレットは同じ)
| A · 図解クリップ | B · ホワイトボード | C · ライブSVG | |
|---|---|---|---|
| 絵 | huashuエンジン canvasシーン、t1_3b1b文法、テキストフリーH.264にレンダリング | huashu y3_whiteboard文法、ダークボード、ペンが描き、手書き文字(Kalam)、正方形動画 | 仮想カメラ(GSAP 3.12.5でviewBoxをトゥイーン)で撮影されたインラインSVGワールド |
| 絵の上の文字 | ダンプされたカメラトラックから動画の上に配置されたHTMLラベル(常にシャープ) | 動画に描き込まれる(スマートフォンでも読める大きさが必要) | 実際のSVGテキスト(シャープ、カメラフレームを幅に合わせて変更することでリフロー) |
| ファイルサイズ(実践例) | 360–820 KB(予算900 KB) | 847–886 KB(予算900 KB) | 21–34 KB(予算40 KB) |
| 印象 | クリーンな3Blue1Brown風図解 | ホワイトボードで誰かが説明している感じ | 洗練されたプロダクトアニメーション |
| 主なリスク | シーンが再レンダリングなしで変更されるとラベルがずれる | タイトなサイズ予算;スマホラベルは12–14 px | 面倒なカメラ計算;GSAPのtransformの癖 |
3つすべてが1つのキャプションスクリプト、同じビート、同じ埋め込み契約を共有しているため、スタイルスイッチャーは同じストーリーを3つの方法で表示します。
エンドツーエンドの方法
各ステップの最後には、それが完了したことを確認するチェックがあります。
-
機構と具体例を1つ見つける。 ホストページを読む(読み取り専用)。表示するタイミングと、すべてのビートに通底する1つの実際の例(1行、1レコード、1ケース、その実際の値)を選ぶ。発明してはいけないもの(ID、数字、画像)をリストアップする。→ チェック: 各ビートを「このオブジェクトがこれを実行する」と、名詞と動詞で言えること。
-
最初にキャプションスクリプトを書く。 ビートごとに1つのキャプション文、1つの動画につき3〜6ビート、
beats.jsonに記述(フォーマット:scripts/common/beats.example.json)。キャプションはすべてのスタイルで同一。次にペーシングゲートを実行し、表示される最小時間を確認する:python3 ~/.claude/skills/wiggle-that-diagram/scripts/common/pace_check.py beats.json→ チェック: すべてのビートがOKで、ユーザーが結果のループ長(または短いキャプション)に同意していること。キャプションとは別にループターゲットを設定してはいけません。「ペーシング」を参照。
-
ブリーフを書く。
references/brief-template.mdをSPEC.mdにコピーして埋める:フィードバックの引用、トークン、ペーシングルール、キャプションスクリプト、ビート、埋め込み契約(正確なスニペット)、予算、成果物。→ チェック: 他のコンテキストを持たないエージェントがこれから構築できること。 -
方向性ラウンド(ユーザーがスタイルを見たことがない場合、オプション)。 3つのエージェントを並行して、各スタイルに1つずつ、同じ動画の1つの瞬間(約8〜12秒)をプロトタイプし、1280pxと390pxで静止画を撮影する。静止画を並べて表示し、ユーザーが1つを選ぶか、3つすべてを保持する。→ チェック: ユーザーの選択が文書化されていること。
-
ビルドラウンド。 スタイルごとに1つのエージェント(それぞれ自分のプロトタイプを継続)、そのスタイルのすべての動画を
<work>/<style>/final/以下にのみ書き込む。ブリーフ:references/agent-briefs.md。起動前にエージェント数とティアをユーザーに伝える。→ チェック: 各エージェントがファイル、静止画、NOTES.md、正直な未解決課題リストを返すこと。 -
ビルドレシピ(各スタイルエージェントが実際に行ったこと;スクリプトは
scripts/style-a|b|c/にあり): 2つの中立動画が3つのスタイルすべてで、それぞれbeats.jsonとstyle-a/、style-b/、style-c/として提供される:examples/pizza/(5ビート、シンプル)およびexamples/expenses/(6ビート:カード、色分けされた理由、第2・第3パネルへの矢印)。自分のスタイルのフォルダから開始する。- A.
cp -R ~/.claude/skills/huashu-art-motion/scripts/engine <A>/engineおよびtouch <A>/engine/favicon.ico。engine/ways/way_make.jsを追加(scripts/style-a/から)、beats_js.py beats.json --engine engine --var <VAR>を実行(キャプションとタイミングは共有スクリプトから、手動コピーは禁止)、シーンファイルengine/ways/<film>.js(WAY.make({poster, beats, camBase, cam, labels})を呼び出しSCENES['<film>']を登録)、およびengine/eras_<film>.js(FILM_SIZE=[1280,720]、PUNCH=0(そうしないとエンジンがトランジションに0.03のパンチインを追加する)、SCENE_LIBS=['ways/way_make.js','ways/<film>_beats.js','ways/<film>.js']、SCENE_DIR='ways'、ERAS=[{id:'<film>',dur:1}])。canvasにテキストを描画しない。描画ヘルパー(角丸ボックス、ドット、線、フェード、パスに沿った移動)は動画ごとに記述する;examples/pizza/style-a/pizza.jsにコピーできる小さなセットがある。次にrender_way.py <film> --scale 0.75 --crf 30→build.py <film> --meta meta.json→pace_check.py work/<film>_data.json→test_embed.py final/<film>.html:<verdict beat>(または一度にすべて:make.sh)。シーンを編集した後は、再レンダリングしてmidmove.pyを中間移動時に実行する:ラベルがオブジェクト上にあることを確認する。 - B. エンジンを同じようにコピーし(空の
favicon.icoを使用:実際のChromeでは404がページエラーとしてカウントされ、render.pyは正常な動画を書き込んだ後に終了コード1で終了する)、render.pyにパッチを当ててchromium.launch(channel='chrome', …)とする。kit.jsをengine/demos/_hb/に配置し、engine/demos/<film>/board.js(HB.make()を使用、イベントをBEATS[k].t0 + offsetにアンカー)およびengine/demos/<film>/eras.js(FILM_SIZE=[1080,1080]、PUNCH=0、Kalamフォントフェイス、SCENE_LIBS=['demos/<film>/beats.js','demos/_hb/kit.js','demos/<film>/board.js'])を記述する。次にbuild_beats.py beats.json --engine engine→uv run --with playwright python engine/render.py --film demos/<film> --fps 30 --crf 12 --out work/<film>_master.mp4→build_html.py <film> --beats beats.json(720²、24 fps、収まる最小CRF)→test_contract.py final/<film>.html --beats beats.json。各動画はボード全体へのプルバック、1秒以上のホールド、次に消しゴムワイプで終了する;空のボードはループが再開する場所。beats.jsonの最後のビートのstillはすべてのスタイルで共有され、ワイプが始まる前に配置されなければならない。そうしないと、ポスターとリデュースモーションフレームが半分消去されたボードを表示する。移動するオブジェクト(スクーター、ボックス)は、handed: falseのK.customアイテムで、位置は時間の関数とする;各オブジェクトに終了時間を設定する。そうしないと、作業が終わった後もボード上に残る。 - C.
examples/pizza/style-c/から開始(SVG、タイムライン、テーマ)。src/<film>.svg(`<g id=
- A.