scenario-motion-loops について
scenario-motion-loopsは、ループするCanvas 2Dアニメーションを制作するスキルです。編集可能なブランド演出や動画出力を求める制作者向けに、時間から決定的に描画し、ループの継ぎ目とレンダリング結果を検査します。
主な機能
- 01単一HTMLファイルでアニメーションを描画
- 02時間駆動の決定的なフレーム生成
- 03ループの継ぎ目と一貫性を検査
- 04静止画とMP4をレンダリング
- 05透過PNGの被写体を重ね合わせ
- 06複数のアスペクト比に対応
活用シーン
- 01ブランドカラーのループ背景を制作
- 02透過素材をループ映像に合成
- 03既存MP4のループ継ぎ目を検査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-motion-loopsインストール後、Claude Code で/scenario-motion-loopsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdreferences/loop-craft.mdscripts/loop-template.htmlrender-loop.mjs詳細
Scenario Motion Loops
概要
ループは、1つのHTMLファイル内でCanvas 2Dを使って描画する、時間の純粋関数です。何も生成しないため、変形やちらつきが発生せず、色を1つ変更するだけでブランドを反映でき、どのサイズでもレンダリングできます。
draw(ctx, w, h, t, P)は、t秒時点のフレームを描画します。すべての周期は12秒のループを割り切るため、12秒時点のフレームは0秒時点のフレームと同じです。- scripts/loop-template.html には、ヘルパー(
M.*)、パレット(P)、tile(...)の登録が含まれています。scenario.com の Motion Loops の探索で作成されたタイル(80個のループと、それぞれのコード)は、変更なしで実行できます。 - scripts/render-loop.mjs はページをチェックし、静止画またはMP4をレンダリングして、エンコード済みファイルをチェックします。
- Scenarioで作成するのは被写体だけです。マスコット、製品、キャラクターなどを、アルファチャンネル付きの切り抜きPNGとして作成します。ページはループのクロックに合わせて被写体を描画するため、合成後もモーションブラーが保たれ、ループは静止します。ループ自体に費用はかかりません。
Node 18以降、ffprobeを含むffmpeg 5.1以降、およびスクリプトを実行する場所にPlaywrightが必要です(npm install playwright の後に npx playwright install chromium を実行するか、Google Chromeをインストールしたうえで --channel chrome を指定します)。接続、モデルの検出、アップロード、料金については、scenario スキルを参照してください。切り抜きについては scenario-image-editing を参照してください。動画のショットについては scenario-video、背景の削除については scenario-video-editing を参照してください。ここに記載された関連スキルが利用可能なスキルに見当たらない場合は、ユーザーにインストールを依頼してください(npx skills add scenario-labs/skills --skill <name>)。無人実行の場合は、ツールのスキーマに基づいて処理を進め、不足している点を明示してください。
クイックリファレンス
cp scripts/loop-template.html loop.html # one loop per file: settings, draw(), overlay
# open loop.html in a browser to preview; ?t=3 freezes it, ?tone=accent or ?tone=light switches tone
node scripts/render-loop.mjs loop.html --check # determinism and loop seam, no video
node scripts/render-loop.mjs loop.html --stills look --at 0,3,6,9 # stills to look at
node scripts/render-loop.mjs loop.html --out loop.mp4 # 12 s, 1920x1080, 24 fps
node scripts/render-loop.mjs loop.html --params "overlay=subject.png" --out loop.mp4 # with a cut-out
node scripts/render-loop.mjs loop.html --width 1080 --height 1920 --out loop-9x16.mp4 # vertical
node scripts/render-loop.mjs --qa loop.mp4 composite.mp4 # seam and format check of any MP4
- Playwrightがインストールされているフォルダーから実行してください。
--forceを指定しない限り、既存ファイルは上書きされません。 - ページチェックでは、ある瞬間を2回レンダリングして一致するか確認し、ちょうど12秒時点のフレームと0秒時点のフレームを比較します。また、ループの継ぎ目をまたぐ動きの変化を、その周辺および各サイクル境界での動きと比較します。
- チェックで
PASSが出力されない限り、レンダリングはエンコードを行いません。--ignore-seamは、ループの継ぎ目に配置することを意図したカットに限り使用できます。これを指定すると、両方のチェックで継ぎ目の判定が免除されます。 - デフォルト設定は、同梱の80個のループで使用されている設定です。24 fps、180度シャッターでの8個のモーションブラー用サブフレーム、2倍のスーパーサンプリング、H.264 High、CRF 16、4:2:0、BT.709リミテッドレンジ、faststart。
- 作成時点では、1080pのフルレンダリングに約6分かかりました(1フレームあたり約1.3秒)。長いタイムアウトを設定するか、バックグラウンドで実行してください。
すべてのタイルが守るルール:
- 周期:すべての周期は12秒を割り切ります(1、1.5、2、3、4、6、12)。
M.phase(t, period, offset)を使用してください。 - スクロール:各周期でパターンの繰り返し全体を整数回分移動させます。繰り返し回数が小数だと、継ぎ目でジャンプします。
- 乱数:
M.rand(i, salt)のみを使用してください。Math.random、Date、フレーム間で状態を保持する処理は使用しないでください。モーションブラーとチェックでは、フレームが順不同でレンダリングされます。 - 単位:サイズには
u = h / 100、個数にはwを使用します。これにより、16:9、9:16、1:1、およびサムネイルサイズでもループが成り立ちます。 - 色:
P(bg、fg、fg2、mid、accent、paper、ink)のみを使用します。ブランドの反映にはBRANDを変更してください。コントラストは色を追加せず、トーン(dark、accent、light)を変更して調整してください。 - 複数色相のループ:レインボーまたは色相のスイープは唯一の例外です。
hsl(${360 * M.phase(t, 12)}, ...)のように色相を計算し、周期は12を割り切る値にしてください。また、設定をBRANDにまとめ、1か所の変更でブランドを反映できるようにしてください。 - イージング:予備動作、オーバーシュート、停止を含む
M.easeを使用してください。一定速度にするのは、スクロールと流れだけです。
ループを閉じるパターン、3Dエンジンを使わずに奥行きを表現する方法、レビューの習慣については、
references/loop-craft.md を参照してください。新しい draw() を書く前に読んでください。
作業例:コーディングされたループの上に浮かぶブランドマスコット
目標:ブランドカラーを使った、1920x1080の12秒のシームレスなループと、その中に浮かぶブランドマスコットを作成します。 必要に応じて、マスコットが手を振るバージョンも作成します。
-
まずループを作成します(ローカル、無料)。
cp scripts/loop-template.html mascot-loop.htmlを実行し、BRAND.accentをブランドカラーに設定します。サンプルタイル(Perspective Floor。カメラに向かって流れるグリッド)をそのまま使うか、独自のdraw()を作成します。次に:node scripts/render-loop.mjs mascot-loop.html --check node scripts/render-loop.mjs mascot-loop.html --stills look --at 0,3,6,9--checkの結果がPASSで終わる必要があります。静止画を確認します。 -
切り抜きを作成します。
scenarioスキルに従って接続し、チームとプロジェクトを選択します。ユーザーのマスコット画像がある場合はアップロードします。次の内容でrecommendを実行します:{ "capability": "img2img", "prompt": "The mascot from the reference image, full body, three-quarter view, a light floating pose, cut out on a transparent background with clean edges, no shadow, no text", "limit": 5 }画像ファイルがない場合は、
"capability": "txt2img"を使ってマスコットを説明します。透明な背景に対応したmodel_schema_getスキーマを持つメンバーを優先します。対応していない場合は、scenario-image-editingに従って後から背景を削除します。dry_runで価格を確認し、ユーザーの承認を待ちます。無人実行の場合は、タスクで指定された予算内でのみ実行します。それ以外の場合は停止して価格を報告します。その後、asset_downloadに"format": "png"を指定し、curl -L -o subject.png "<url>"を使ってmascot-loop.htmlのあるフォルダーに保存します。 -
切り抜きを確認します。 ループの背景色に重ねて、PNGを100%表示で確認します。輪郭のハローは暗い色の上で目立つため、隠すのではなく再生成します。背景除去ツールのスキーマには、エッジやしきい値の設定があることがよくあります。再実行時に値を上げてください。
-
キャンバス上で合成してレンダリングします。
node scripts/render-loop.mjs mascot-loop.html --params "overlay=subject.png" --stills look --at 0,0.75,1.5,2.25 --force node scripts/render-loop.mjs mascot-loop.html --params "overlay=subject.png" --out mascot-loop.mp4 --psnr 4ページ内の
drawOverlay()は、接地影を付けながら被写体を3秒周期で上下に揺らし、6秒周期で左右に揺らすため、合成後もループが途切れません。サイズと配置はここで調整します。スクリプトはページを確認し、288フレームをレンダリングしてエンコードした後、ファイルのループポイントをチェックします。--psnrは、エンコードしたフレームと可逆レンダリングしたフレームを比較します。 -
任意:マスコットが動くショット。
scenario-videoに従って生成します。切り抜きを使ったimg2videoに、「the mascot waves and turns its head, plain flat background, locked-off camera, no cuts」と指示します。背景を無地にし、カメラを固定すると、背景をきれいに除去できます。scenario-video-editingに従って背景を削除し、アルファ付きWebM VP9を選びます(編集ソフトウェアではProRes 4444を使用します)。- オーバーレイなしでループをレンダリングし(
--out loop-plain.mp4)、その上にショットを重ねます:
ffmpeg -stream_loop -1 -i loop-plain.mp4 -c:v libvpx-vp9 -i shot.webm \ -filter_complex "[1:v]fps=24,scale=-2:720[s];[0:v][s]overlay=(W-w)/2:(H-h)/2:shortest=1,format=yuv420p,setparams=colorspace=bt709:color_primaries=bt709:color_trc=bt709:range=tv" \ -c:v libx264 -crf 16 -preset slow -colorspace bt709 -color_primaries bt709 -color_trc bt709 \ -color_range tv -movflags +faststart -an composite.mp4合成映像の長さはショットと同じです。ショットがループしない限り、シームレスなループにはなりません。ループさせるものには
--qaを実行します。 -
納品するもの: HTML(ループは引き続き編集可能です)、MP4、静止画、合成映像があればそれも納品します。
よくある間違い
- 12 s の位置で継ぎ目が跳ぶ。 12 を割り切れない周期(5 s の周期など)や、スクロール量が 2.5 回分の繰り返しになっています。
--checkはSEAM JUMPを報告します。周期を修正し、端をクロスフェードしないでください。 - タイル内で状態、
Math.random、またはDateを使う。 同じtでもフレームが異なり、ループを閉じられません。--checkはNOT DETERMINISTICを報告します。 - 16 進数しか読み取れないカラー関数を使う。
P.midとM.mixColorはrgb()文字列を返すため、16 進数専用のパーサーでは、気づかないうちに黒になります。テンプレートのM.rgbaとM.mixColorを使ってください。 - 高速な動きでストロボが発生する。 8 個のサブフレームでは、フレーム全体を押し出す動きに段差状の残像が現れます。ページ全体のスワイプでは 40 個必要でした。非常に速いループでは
--samplesを増やしてください。 - すべての警告をバグとして扱う。 意図したスナップ(ポップやバースト)やループ位置でのホールドでも、継ぎ目チェックが反応することがあります。コードを変更する前にフレームを確認してください。
- カウンターの折り返しが正しくない。 サイクルをインデックスとして使うものは
M.modで折り返してください。そうしないと、ループ位置で「06 / 05」と表示されます。 - フォントの読み込み前にテキストを描画する。 Canvas のテキスト描画は Web フォントの読み込みを待ちません。最初のフレームの前に
document.fonts.load(...)を待つか、テキストを描画しないでください。 file://からページを開いてレンダリングする。 ローカルのオーバーレイ画像によってキャンバスが汚染され、読み戻しに失敗します。render-loop.mjsはフォルダーをローカルアドレスで配信します。ブラウザーのプレビューには影響しません。- ビットレートにこだわる。 ベタ塗りではファイルが小さく見えますが、エンコーダーによる劣化はほとんどありません。実際に劣化するのは、細い彩度の高い線における 4:2:0 の色差です。
--psnrで確認し、線を太くしてください。 setparamsを使わずに色のフラグだけを指定する。 ffmpeg 7 では、-colorspace、-color_primaries、-color_trcだけでは、原色と伝達特性がタグ付けされませんでした。ここにある両方のコマンドのように、フィルターチェーンの最後にsetparamsを追加してください。そうしない場合、--qaはUNTAGGED COLORを報告します。- VP9 のショットのアルファを失う。 ffmpeg 内蔵の VP9 デコーダーはアルファを無視するため、ショットが黒いボックスとして表示されます。
-i shot.webmの前に-c:v libvpx-vp9を指定してください。ffprobe では、このようなファイルはyuv420pとalpha_mode=1として報告されます。アルファは保持されています。 - 動画モデルでループを作る。 生成されたクリップの最終フレームが最初のフレームと合うことはほとんどありません。ループはコードで作り、題材には Scenario を使ってください。