Communitygithub.com

smwbev/framewright

以程式碼完全產生短片:一份 HTML 檔案,每個影格皆為 (frame, seed, width) 的純函數。支援 Claude、Codex、Gemini、Cursor。

framewright 是什麼?

Framewright 是一個 AI 輔助技能,能讓開發者以類似版畫創作的方式,用純程式碼生成短片。其核心設計哲學是:每個影格僅由影格編號、種子值與輸出寬度決定,完全不依賴 `Math.random`、外部圖片、影片、字型或 CDN 資源。此技能支援 Claude Code、Codex、Gemini 與 Cursor 等平台,並透過結構化的八步驟工作流程,從需求釐清、概念提案、腳本建立、場景開發、素材處理(如照片向量化)、完整渲染、音效合成到最終交付,確保影片的確定性與可重複性。開發者需遵循嚴格的「非妥協」規則,例如驗證每個影格的純粹性、不讀程式碼而實際檢視 render 結果、單一場景逐步開發等。最終產出為單一 HTML 檔案,搭配 ffmpeg 合成影片,並可使用 `scripts/make.sh` 一鍵重建。

相容平台✓Claude Code✓Codex CLI✓Cursor✓Gemini CLI
npx skills add smwbev/framewright

在你喜歡的 AI 中提問

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

說明文件

framewright 是做什麼的?

你將以版畫家創作版畫的方式製作一支短片:一份包含 canvas、名為 plates 的場景清單,以及一個 frame 函數的 HTML 檔案,該函數可依 (影格編號, 種子值, 寬度) 即時繪製任何影格。無需影片素材、圖片檔案或任何來自 CDN 的資源。影格由無頭 Chrome 渲染,再由 ffmpeg 組裝。音效則在最後根據鎖定的場景長度合成。

請以使用者的語言與其交談。即使使用者時間緊迫,也請遵守以下規則:這裡的每個捷徑所節省的時間,都比不上它帶來的額外成本。

SKILL_DIR 以下指的是包含此檔案的資料夾(在 Claude Code 中為 ${CLAUDE_SKILL_DIR};在其他環境中為 .agents/skills/framewright)。完成步驟 3 後,腳本也會存在於專案自身的 scripts/ 資料夾中。

不可妥協事項

  1. 一個影格僅依賴於影格編號、種子值和輸出寬度。不得使用 Math.random、系統時鐘、CSS 動畫或將 requestAnimationFrame 作為時間來源。scripts/check.mjs 會在每次完整渲染前證明這一點。
  2. 不得使用圖片、影片、字型或函式庫檔案,不得使用 base64,不得使用 CDN。由腳本從照片追蹤出的多邊形屬於資料,可以使用。系統字型已足夠。
  3. 你必須透過檢視渲染後的影格來驗證,絕不能僅憑閱讀程式碼或想像來判斷。任何修正都必須用一個影格來確認。
  4. 一次只處理一個場景。撰寫一個 plate,拍攝三個影格,檢視,修正,然後再進行下一個 plate。
  5. 場景長度必須是初稿節拍的倍數。音效最後才加入。
  6. 只有在整個影片的預覽縮圖看起來正確後,才能進行完整渲染。
  7. 絕不提交 frames/、shots/、*.mp4、*.wav 或使用者的照片。
  8. 安裝系統套件前必須詢問。未經使用者確認他們有權使用,絕不發布真實人物的肖像。

工作流程一覽

步驟發生什麼事與使用者確認點
0環境檢查僅在需要安裝任何東西時
1簡報問卷調查,一個區塊
2概念三個選項,選擇一個
3分鏡 + 腳手架一次「開始」確認
4場景,逐個進行每 2-3 個場景提供一次預覽縮圖
5素材 (照片, 標誌)追蹤肖像的預覽
6完整縮圖、渲染、建置預覽 MP4
7音效重建 MP4
8交付與變化版最終成品

典型耗時:簡報與概念 10 分鐘,腳手架 10 分鐘,每個場景 10-20 分鐘,渲染 1080p 影片每分鐘約需 2-4 分鐘渲染時間,音效 15 分鐘。

步驟 0. 環境設定

bash SKILL_DIR/scripts/doctor.sh            # 報告;加上 --json 可輸出機器可讀摘要
bash SKILL_DIR/scripts/doctor.sh --install  # 安裝缺少的工具,每個步驟前會詢問

必要項目:Node 20+、npm、含 libx264 的 ffmpeg、專案內含 Chrome 的 Puppeteer。 選用項目:僅在需要追蹤照片時,才需要 Python 3 及 numpy、scipy、Pillow。如果 doctor 回報缺少工具,請告知使用者將安裝哪些工具及其位置,獲得同意後,再執行 --install(若使用者已同意,可加上 --yes)。請不要在 doctor 回報失敗的情況下開始步驟 3。

步驟 1. 簡報

執行來自 references/questionnaire.md 的問卷。請在支援結構化提問工具時使用該工具(Claude Code:AskUserQuestion,每次呼叫最多四個問題,每個問題二到四個選項,將推薦選項放在第一個並標記)。若無此類工具,請將問題列印為有序列表,每個問題包含字母選項和一個預設值,並接受簡潔的回答,例如 1b 2a 3c。

請務必依此順序詢問:

  1. 訊息:觀眾必須理解或感受到什麼,用一句話說明。螢幕上必須出現的名稱、日期、連結、確切詞組。
  2. 播放平台與格式:16:9、9:16、1:1、4:5。
  3. 長度:10-15、20-25、30-40、45-60 秒。
  4. 調性:俏皮、面無表情、溫暖、史詩、技術、黑暗。
  5. 風格:由你提議(預設),或從 references/styles.md 選擇一種風格家族。
  6. 素材:照片、標誌、螢幕截圖。檔案必須放在專案資料夾中;你無法儲存貼到對話中的圖片。對於真實人物的肖像,請詢問使用權利。
  7. 音效:合成音效、無音效、或保留空間給使用者自己的音軌(如有則詢問其 BPM)。
  8. 交付物與品質:草稿或最終版、額外的剪輯版本(直式、GIF、海報影格、種子變化版)、將 MP4 的第一個影格作為封面(在 feed 中會顯示為預覽圖)。

如果使用者說「你決定」,就採用預設值,並告知你採用了哪些預設值,然後繼續進行。

步驟 2. 概念

在開始寫任何程式碼之前,請提出三個概念。從三個角度建構:字面(展示主題)、隱喻(一個用來代表情境的視覺系統:用電視測試卡代表等待、用藍圖代表計劃、用終端機代表流程)、以及類型模仿(新聞快報、街機展示模式、安全須知卡、天氣預報、圖文電視)。針對每個概念提供:名稱、一句話的故事大綱、視覺系統與色板、依序的三到五個關鍵場景、結尾、音效草稿、為何合適、以及主要風險。以簡潔的表格呈現,推薦一個,並請使用者選擇。方法與實例在 references/questionnaire.md 中。對於一個大綱是「一次沒有剪輯的旅程」(一條永不中斷的線、從一個細節飛向景觀的飛行)的概念,應建構為一個連續世界(references/world.md);請在其行中說明,因為這會改變場景的建構與修改方式。對於一個是「繪製、上色並賦予生命的一幅畫」(從鉛筆素描變成有生命力的油畫,風格 13-16)的概念,應建構為一幅繪畫影片(references/painting.md);也請在其行中說明:其 plates 是一幅畫的時間章節,場景即是作品本身。

步驟 3. 分鏡與腳手架

填寫 storyboard.md(模板在 assets/storyboard.md):每行一個 plate,長度以小節為單位,節拍網格(30 fps, 120 BPM:一拍 15 幀,一小節 60 幀),主要事件發生的秒數,以及總長度。總長度必須與約定的長度一致;當稍後新增一個場景時,另一個場景必須讓出一小節。顯示表格並要求一次「開始」確認。

然後建立腳手架:

bash SKILL_DIR/scripts/init.sh              # index.html, scripts/, audio.mjs, storyboard.md, package.json
bash SKILL_DIR/scripts/init.sh . --world    # 同上,但 index.html 是單一世界骨架(無剪輯)
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 檔案並檢視。骨架的示範 plate 必須能正常渲染,然後你才能改動它。接著將示範 plate 替換為你的第一個場景。在繪畫影片中,影格 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 是一個對整個 plate 穩定的產生器;S.b 每三個影格重新播種,提供即時線條;S.nz 每影格變化,用於產生雜訊。種子衍生自 plate 名稱。
  • 所有幾何以邏輯單位進行,透過 CX, CY 置中。將重要內容放在影格的中央 92% 內;在 9:16 格式中,也要避開頂部 15% 和底部 20%,這些是平台按鈕和字幕的位置。
  • 在 plate 內以節拍計算時間:Math.floor(S.i/BEAT)、span(S.i, a, b)、ease.out(...)。切勿在場景內硬編碼全球影格編號。需要跨剪輯持續的內容,請透過名稱參考另一個 plate 的時間:at('plate', beats);音效必須配合的時刻需寫入 CUES,並透過 cue('name') 讀取。
  • 輔助函數放在 plates 區塊之上,絕不放在 plates 之間。
  • 轉場由引擎在 plate 邊緣繪製(cutIn/cutOut 標記);場景本身不需要知道轉場。
  • 世界影片(--world)沒有剪輯。Plates 是建構器 build(W, {pen, b, R}),它們會附加到一條時間線:b(x) 是 plate 的第 x 拍,筆從上一個 plate 結束的地方繼續畫線,camKey 移動一個攝影機,title 新增文字。請在編寫第一個建構器前閱讀 references/world.md。
  • 繪畫影片(--painting)繪製一幅使用三種媒材的靜止畫作。其所有 plates 都呼叫 drawPainting(S);視圖存在於 SCENE 物件及其位於 /* ===== scene ===== */ 和 /* ===== end scene ===== */ 之間的圖層中,而其上方的繪畫工具包保持不變。請在編寫第一個圖層前閱讀 references/painting.md。首先單獨審視繪畫部分,然後是揭示部分,最後是生命化部分(references/painting.md,第 13 節)。

每個場景:編寫它,拍攝第一個影格、中間的一個影格、以及結束前五個影格的一個影格,檢視,修正,再次檢視。每完成兩到三個場景:

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.5 秒內可理解為一個靜止畫面;沒有文字被裁切;相鄰的線條和面板沒有接觸;同一個 plate 的兩個相鄰儲存格看起來絕不相同;剪輯落在計畫的位置,且沒有吃掉場景的第一個影格;沒有重要內容位於外圍 8% 內;色彩沒有渾濁;細線沒有碎裂;主要事件發生在計畫的秒數上;最後一個影格看起來像個結尾;螢幕上沒有兩個標題同時出現在同一位置。對於未能滿足「1.5 秒內可理解」的場景,應重新設計,而非裝飾。對於空白場景,應使用更大的物體或更近的攝影機,而非增加更多細節;對於忙碌的特寫,應降低主體周圍裝飾的不透明度。在世界影片中,還要拍攝每個 plate 的最後一個影格,並將其與下一個 plate 的第一個影格並排檢查:不能有任何跳動。

在這些時間點將預覽縮圖發送給使用者,並附上兩句狀態說明。不要描述程式碼。

步驟 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

檢查會以七種順序(新分頁的第一個影格、順序、反向、隨機、緊接在前一個影格之後、在不同寬度之後、在模擬渲染分頁遍歷影片的掃描之後)渲染每個 plate 的五個影格,並要求像素完全相同。它還會掃描原始碼中是否有 Math.random、Date 和 performance.now,如果頁面請求任何檔案則會失敗,並列印節拍網格和預估的渲染時間。在渲染前修正每一個失敗;make.sh 會執行檢查並在失敗時停止。如果一個影格會隨渲染順序而改變,表示存在跨影格殘留的狀態:一個未清除就繪製的 pooled canvas、一個 plate 改變的全域變數、或一個未包含所有輸入的快取鍵。

從檔案而非影格驗證:ffprobe 影格總數等於 look.mjs info 的總數,持續時間等於影格數除以 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:包含 plate 的開始點、提示點、以及在世界影片中每個影格線條頭部的速度和螢幕位置,在繪畫影片中則包含已揭露的部分、生命化部分、gust 和縮放。audio.mjs 會從此檔案取得其時間線,因此它永遠不會與畫面不同步(如果頁面沒有 RISO.curves(),則需要手動將 look.mjs info 的開始點複製到 T 中)。使用 references/audio.md 中的提示地圖,為每個 plate 撰寫一個事件區塊;需要配合畫面標記的打擊點,其時間應來自頁面的提示點 cue('name')(CUES,或在世界影片中為 W.cues),而非從 plate 中複製出的節拍數字;在世界影片中,為線條或角色賦予一個跟隨曲線的聲音(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.7 MB)並說明如何重建:bash scripts/make.sh [photo.jpg] [seed] [width]。提供選項,而非強迫:不同的種子(相同 plates 的不同印象)、直式剪輯(AR=9:16 node scripts/render.mjs frames-v 7 1080 5,然後用 AR=9:16 檢查預覽縮圖;直式中較低的標題應放在高度的 70% 處,即 TITLE_Y,避開平台的按鈕;如果使用者想要一個海報影格,渲染種子 0 的影格 0 並加上 -vframes 1)。如果他們想要 GIF,請從 MP4 中抽取。不要重新渲染。請他們在交付物準備好之前先預覽。在出貨前完成所有交付物。如果他們想要另一個種子,也請在渲染完成後,用 bash scripts/make.sh [photo.jpg] <seed> 提供一個不同的 out-seed.mp4(再次確認種子編號,因為種子 0 是標準交貨版)。提供一個 .env 模板(FRAMEWRIGHT_SEED= 和 AR=)來儲存參數。所有交付物完成後,透過詢問「還有什麼我可以幫你的嗎?」來確認使用者是否滿意,並在轉向其他任務前解決剩餘問題。

相關技能