Communitygithub.com

scenario-motion-loops

用於創建無縫循環的動態圖形影片,適用於品牌色彩、AI 鏡頭間的空白秒數、過場動畫等,並可選擇性地將來自 Scenario MCP 的吉祥物、產品或角色合成到循環上。

scenario-motion-loops 是什麼?

此技能引導使用者在一個 HTML 檔案中,以 Canvas 2D 程式碼建立無縫循環的動態圖形。每個循環都是一個純時間函數,其所有週期長度皆可整除循環總長度 (12 秒),因此第 12 秒的影格與第 0 秒完全相同,確保影片循環時沒有任何接縫。此方法完全基於程式碼生成,因此畫面不會扭曲或閃爍,只需更改一個顏色即可重新品牌化,且相同的程式碼能渲染出任何尺寸的影片。為了保證輸出的品質與一致性,腳本會執行確定性檢查(確保相同時間點渲染結果一致)與接縫檢查,確認循環點順暢。最終腳本會渲染出 12 秒、1920x1080、24fps 的 MP4 影片,並套用動態模糊、超取樣與 H.264 BT.709 編碼。若要加入程式碼難以繪製的主體(如吉祥物、產品),此技能會呼叫 Scenario MCP 來生成去背圖像或 AI 影片,並將其合成到循環背景上。它支援多種平台,包括 Claude Code、Coder、Cursor 與 Codex Agent 等工具,只要環境中安裝了 Node 18+、Playwright、ffmpeg 與 ffprobe 即可使用。其中一個關鍵特性是,循環本身無需任何模型且渲染成本為零,只有需要合成主體時才會用到 Scenario MCP 的費用。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/DawitLemmaBalcha/motion-graphics-studio/tree/HEAD/skills/motion-graphics/setup/templates/scenario-motion-loops

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

以程式碼建立無縫運動循環,並從 Scenario MCP 加入您的物件

概述

此處的循環是一個純時間函數。draw(ctx, w, h, t, P) 會在 t 秒時繪製影格,且其中的每個運動的週期長度都能整除循環總長度 (12 秒)。因此,第 12 秒的影格會與第 0 秒完全相同,影片循環時沒有任何接縫。一切都是程式碼生成的:不會扭曲或閃爍,更改一個顏色就能重新品牌化,且相同的程式碼能在任何尺寸下渲染。scenario.com 上的 Motion Loops 探索頁面展示了 80 個以此方式製作的循環(40 個背景、40 個形狀動畫),每個都有其對應的程式碼。scripts/loop-template.html 包含了這些循環所使用到的相同輔助函式 (M.*)、調色盤 (P) 和 tile(...) 註冊方式,因此這些循環的 tile 程式碼可以直接在其中執行,無需修改。

Scenario MCP 負責生成程式碼無法繪製的部分:使用者的主體。吉祥物、產品或角色會以去背的形式從 Scenario 輸出,而循環頁面會使用循環本身的時脈將它繪製在循環背景之上,因此它能獲得相同的動態模糊效果,且合成後的影片依然能無縫循環。對於需要真正移動的主體,則會從該去背圖像生成一個 AI 影片片段,在 Scenario 中移除其背景,然後透過 ffmpeg 將該片段疊加到已渲染的循環影片上。循環本身完全不需要模型,且渲染成本為零。

需要 Node 18 或更新版本、Playwright(執行 npm install playwright,然後執行 npx playwright install chromium;或安裝 Google Chrome 後使用 --channel chrome)、ffmpeg 和 ffprobe。僅在使用主體時才需要 Scenario MCP。關於連線、模型選擇和生成循環的詳細說明:如果已安裝 scenario 技能則使用它,否則請參閱 references/scenario-mcp.md。

快速參考

cp scripts/loop-template.html loop.html            # 每個循環一個檔案:設定、draw()、疊加層
# 在瀏覽器中開啟 loop.html:即時預覽;?t=3 可凍結畫面,?tone=accent 或 ?tone=light 可切換色調
node scripts/render-loop.mjs loop.html --check     # 檢查確定性與循環接縫,不輸出影片
node scripts/render-loop.mjs loop.html --stills look --at 0,3,6,9             # 輸出靜態影像供檢視
node scripts/render-loop.mjs loop.html --out loop.mp4                          # 輸出 12 秒、1920x1080、24 fps 影片
node scripts/render-loop.mjs loop.html --params "overlay=subject.png" --out loop.mp4   # 使用去背圖像
node scripts/render-loop.mjs loop.html --width 1080 --height 1920 --out loop-9x16.mp4  # 直向影片
node scripts/render-loop.mjs --qa loop.mp4 composite.mp4   # 檢查任何 MP4 檔案的接縫與格式

請在已安裝 Playwright 的資料夾中執行。如果沒有使用 --force 參數,現有檔案絕不會被覆蓋。頁面檢查會渲染同一個時間點兩次(兩次結果必須相符),比較第 12 秒與第 0 秒的影格,並比較跨越循環點前後的運動狀態與其他週期邊界處的運動狀態。渲染工作會拒絕編碼,除非看到 PASS 輸出;只有當設計刻意要在循環點產生接縫時,才使用 --ignore-seam。

規則原因
每個週期長度都能整除 12 秒 (1, 1.5, 2, 3, 4, 6, 12);使用 M.phase(t, period, offset)確保第 12 秒的影格與第 0 秒相同
滾動效果在每個週期內移動整數個圖案重複次數移動非整數倍重複次數會在接縫處造成跳躍
隨機性僅來自 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 來重新品牌化;透過更改色調來調整對比度
緩動函數來自 M.ease,可產生預期、 overshoot 和停頓效果;僅滾動效果使用恆定速度呈現經過設計的動畫,而非機械式的運動

這 80 個循環在發布時所使用的渲染設定,也是腳本的預設值:24 fps、8 個動態模糊子影格搭配 180 度快門角、2 倍超取樣、H.264 High Profile、CRF 16、4:2:0 色彩取樣、BT.709 Limited Range、faststart。關於閉合循環、景深技巧以及審查習慣:請參閱 references/loop-craft.md。

Scenario MCP 步驟呼叫的 API
連線、選擇團隊和專案teams_list(如果有多個,請詢問使用者)
匯入使用者自己的素材upload_asset、curl PUT 每個部分、upload_asset_complete
選擇模型recommend(txt2img、img2img、img2video、video2video),或 search
讀取模型的輸入參數model_schema_get
估算價格,使用者同意後再執行先使用 dry_run: true 參數呼叫 model_run,再呼叫 model_run 和 jobs_wait
取得結果asset_download,然後 curl -L -o

實作範例:品牌吉祥物漂浮在程式碼循環之上

目標:製作一個 12 秒、無縫、使用品牌色、並含有品牌吉祥物漂浮其中的 1920x1080 循環影片,以及一個吉祥物會揮手的版本(可選)。

  1. 連線。 呼叫 teams_list。如果返回多個團隊或專案,詢問使用者要使用哪一個,並在後續所有呼叫中傳入其 team_id 和 project_id:使用已登入的帳戶時,search、model_schema_get 和 model_run 若缺少這些參數將拒絕執行。

  2. 先建立循環(本地端、免費)。 執行 cp scripts/loop-template.html mascot-loop.html,將 BRAND.accent 設定為品牌色,保留範例 tile(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 結尾。

  3. 匯入吉祥物。 如果使用者有吉祥物的檔案,請上傳它:

    {
      "file_name": "mascot.png",
      "content_type": "image/png",
      "kind": "image",
      "file_size": 482113
    }
    

    (從 wc -c mascot.png 取得 file_size。)使用 curl 將檔案內容 PUT 到回傳的 URL,然後使用 {"upload_id": "<upload id>"} 呼叫 upload_asset_complete,並記下回傳的 asset id。

  4. 選擇模型。 使用以下參數呼叫 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" 並描述吉祥物。如果 next_step.type 是 ask_user,則顯示選項並等待使用者選擇。優先選擇其 Schema 具有透明背景選項的模型;否則,請計畫在生成後進行去背處理。

  5. 讀取 Schema 並估算價格。 使用 {"model_id": "<id from recommend>"} 呼叫 model_schema_get。根據 Schema 建構參數:參考圖像欄位接收上傳的 asset id(如果 Schema 要求陣列則以陣列形式傳入),並設定透明背景選項。然後:

    {
      "model_id": "<id from recommend>",
      "dry_run": true,
      "parameters": {
        "prompt": "<上述的提示詞>",
        "<參考圖像欄位>": ["<吉祥物 asset id>"],
        "<背景欄位>": "transparent"
      }
    }
    

    告知使用者價格,並等待其確認。

  6. 執行並下載。 使用相同的參數呼叫 model_run,並設定 "wait": false,然後使用 {"job_ids": ["<job id>"]} 呼叫 jobs_wait。接著使用 {"asset_id": "<asset id>", "format": "png"} 呼叫 asset_download,並在 mascot-loop.html 所在的資料夾中執行 curl -L -o subject.png "<url>"。在循環的背景色上以 100% 比例開啟 PNG 檔案:檢查主體輪廓在深色調上是否有光暈;如果有的話,請重新生成,不要試圖隱藏它。

  7. 在 Canvas 中合成並渲染。

    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 秒為週期左右搖擺,同時帶有接觸陰影,所有週期皆可整除 12,因此合成後的影片依然能無縫循環;請在此函式中調整吉祥物的大小和位置。腳本會檢查頁面、渲染 288 個影格、進行編碼,並檢查檔案的循環點。使用 --psnr 參數可以將一個編碼後的影格與其無損渲染結果進行比較。

  8. (可選)製作一個吉祥物會動的片段。 使用 "capability": "img2video" 呼叫 recommend,將去背圖片的 asset id 作為起始影像,並使用類似「the mascot waves and turns its head, plain flat background, locked-off camera, no cuts」的提示詞。依序執行 Schema 讀取、乾執行(dry run)、使用者確認、正式執行、jobs_wait、下載。然後再使用 "capability": "video2video" 與「remove the background from this clip, keep the subject with an alpha channel」的提示詞呼叫 recommend,選擇支援 Alpha 通道的 WebM VP9 作為輸出格式。再次依序執行上述步驟。接著,這次不使用 --params overlay=... 參數渲染一次循環(使用 --out loop-plain.mp4),然後使用 ffmpeg 將該 AI 片段疊加到循環影片上(具體命令請參閱 references/scenario-mcp.md)。這個合成影片的長度與該 AI 片段相同;除非該片段本身就是無縫循環,否則最終影片不會是無縫的。

  9. 交付成品。 交付 HTML 檔案(循環仍可編輯)、MP4 影片、靜態影像,以及任何合成影片。

常見錯誤

  • 在第 12 秒出現接縫跳躍。 使用了不能整除 12 的週期(例如 5 秒循環),或是滾動移動了 2.5 個重複次數。--check 會報告 SEAM JUMP(第 12 秒的影格與第 0 秒不同)。修正週期長度;切勿使用淡入淡出效果來銜接頭尾。
  • 在 tile 中使用狀態變數、Math.random 或 Date。 這會導致相同的 t 值產生不同的影格,動態模糊的子影格也會不一致,循環因此無法閉合。--check 會報告 NOT DETERMINISTIC。所有計算都應基於 t 和 M.rand(i, salt)。
  • 只能讀取十六進位顏色的輔助函式。 P.mid 和 M.mixColor 回傳的是 rgb() 字串,如果只用能解析十六進位顏色的解析器來處理,它們會直接被轉成黑色。範本中的 M.rgba 和 M.mixColor 可以同時處理兩種格式。
  • 快速移動時出現閃爍(Strobing)。 對於整個畫面的平移,8 個子影格是不夠的,它會顯示出階梯狀的複製影像。在實作中,全頁滑動效果需要 40 個子影格。對於非常快速的循環,請增加 --samples 參數值。
  • 線框圖看起來像雜亂的線條。 一個 3D 波浪網格曾經導致這個問題;後來將其重建為隱藏線脊線(每一行將其背景填滿在其下方,從遠到近繪製),看起來就像地形了。
  • 深度計算了兩次。 一個投影在根據深度縮放焦距後又再次縮小場景,導致場景集中在畫面中央。請使用 M.proj 投影一次。
  • 使用每隔 1.5 秒的靜態影像來審查一個 3 秒週期的循環。 這只能看到週期中的兩個姿勢。請在一個週期內以及循環點兩側都進行取樣(例如 --at 11.9,11.95,0,0.05)。
  • 將所有標記都視為錯誤。 一個經過設計的瞬間變化(例如彈出、爆發)或在循環點的停頓,可能會觸發接縫或閃爍檢測器。請先檢視影格畫面。腳本會比較循環點與其周圍的運動狀態,以及其他週期邊界,這避免了大多數誤報:所有 80 個循環都能通過這個檢查。
  • 標籤或計數器換行錯誤。 任何由週期索引的內容都必須使用 M.mod 來處理換行;在實作中,一個頁碼計數器因為忘了使用 M.mod,導致在循環點顯示成「06 / 05」。
  • 在某一色調下對比度過低。 與其新增一個顏色,不如為該循環切換色調(深色、強調色、淺色)。
  • 從磁碟載入疊加的 PNG 檔案。 從 file:// 協定開啟的頁面,如果繪製了本地圖片並嘗試讀取像素資訊,會因為圖片污染了 Canvas 而失敗。render-loop.mjs 腳本會透過一個本地位址來提供檔案服務;瀏覽器預覽功能只負責顯示,因此不受影響。
  • 字型尚未載入就開始繪製文字。 Canvas 的文字繪製不會等待網頁字型載入;請在第一個影格繪製前使用 await document.fonts.load(...),或者在循環中不使用文字。
  • 過度追求位元率。 在純色區域上,x264 編碼器只會使用極少的位元,檔案看起來很小。在實作中,PSNR 顯示編碼器幾乎沒有引入畫質損失;唯一真正的損失來自 4:2:0 色彩取樣對細小飽和線條的影響。請使用 --psnr 檢查,並透過加粗細小的彩色線條來解決,而不是提高位元率。
  • 遺失了 VP9 影片的 Alpha 通道。 ffmpeg 內建的 VP9 解碼器會忽略 Alpha 通道;請確保在 -i shot.webm 之前加上 -c:v libvpx-vp9。
  • 使用影片模型來建立循環。 一個生成式影片片段的最後一個影格極少能與第一個影格完全吻合。

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

相關技能