Communitygithub.com

geoqiao/short-video-skills

用程式碼製作附旁白的短影片,無需影片生成模型。適合知識講解、軟體教學、產品功能介紹、數據解讀等以圖形、文字、程式碼和資料圖表為主的內容。

short-video-skills 是什麼?

這項技能提供了一套完全基於程式碼的短影片製作流程,無需傳統影片剪輯軟體或AI影片生成模型。它透過Canvas按時間逐幀繪製畫面,使用edge-tts合成旁白並根據逐詞時間戳對齊畫面節拍,再藉由Playwright驅動本地Chrome進行截圖,最後以ffmpeg合成MP4影片。此方法特別適合知識講解、軟體教學、產品功能介紹和數據解讀等以圖形、文字、程式碼和資料圖表為主的內容,但無法處理實拍、真人演出或寫實畫面。支援Claude Code、Cursor、Codex等AI代理平台,透過結構化的專案模板、完善的工具鏈(如voice.py、render.mjs)和嚴格的規範,讓開發者能快速建立、迭代並交付高品質的短影片專案,包含封面圖和聯絡表。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/geoqiao/short-video-skills/tree/HEAD/skills/code-video

在你喜歡的 AI 中提問

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

說明文件

用程式碼做短影片

畫面只由時間決定:頁面暴露 window.render(t),給它一個秒數,它畫出那一刻的畫面。渲染腳本用無頭 Chrome 逐幀呼叫它並截圖,ffmpeg 把截圖和配音合成 mp4。改畫面就是改程式碼,重新渲染即可。

這套做法的出處是 xilo 在 X 上的一篇文章(2026-09-29,https://x.com/xilo2991/status/2104912748794589515)。本 skill 在它的基礎上加入了配音對齊、封面、靜幀檢查和一套寫腳本、畫畫面的規矩。

起步

需要 Node 20+、uv、ffmpeg 和本機的 Google Chrome。預設字型是 macOS 自帶的宋體、蘋方和 SF Mono;其他系統在 brand.json 的 fonts 裡換成本機有的字型。

  1. 把本 skill 的 template/ 整個複製成一個新專案目錄。
  2. 在新目錄裡執行 npm install(只裝 playwright-core)。
  3. 改 brand.json:series 是封面左上角的系列名,handle 是封面和片尾的署名,avatar 是頭像圖片的相對路徑(可以是 null),colors 和 fonts 是配色和字型。
  4. 跑一遍範例:
uv run tools/voice.py demo                # 配音、配樂、時間線 -> episodes/01-demo/build/
node tools/render.mjs demo --stills auto  # 每個鏡頭末尾出一張靜幀
node tools/render.mjs demo                # 渲染整片 -> episodes/01-demo/out/video.mp4 和 cover.png
sh tools/covers.sh demo                   # 4:3 和 3:4 封面
sh tools/sheet.sh demo                    # 封面加各鏡頭末幀拼成聯絡表 build/sheet.png

命令裡只寫 slug,腳本自己找 episodes/<期號>-<slug>/。配音會把旁白文字傳送給微軟的線上 TTS 服務。

專案結構

  • brand.json:品牌。改這裡,不改引擎。
  • src/lib.js:繪圖工具,掛在 window.E 上。
  • src/run.js:時間線排程。第 0 幀是封面,停 0.3 秒後平穩移進第一個鏡頭;鏡頭橫向排開,用平移銜接;字幕和進度條也在這裡畫。
  • src/stage.html:渲染頁面。
  • tools/voice.py:逐行合成配音,用逐詞時間戳定分句起點,合成鋪底音樂和提示音,響度歸一到 -14 LUFS。合成不完整會重試,三次失敗就報錯。
  • tools/render.mjs:四個頁面並行取幀,ffmpeg 編碼,30 幀每秒。
  • tools/covers.sh、tools/cover-vertical.mjs:4:3 橫封面(16:9 封面上下補底色)和單獨排版的 3:4 豎封面。
  • tools/sheet.sh:從成片抽封面和每個鏡頭的末幀,拼成聯絡表。
  • episodes/<期號>-<slug>/:一期一個目錄,裡面是 script.json、shots.js,以及生成的 build/ 和 out/。

一期的流程

按順序做,前一步沒過不進下一步。

內容和事實由你自己準備,本 skill 從寫腳本開始。

  1. 腳本:建 episodes/<期號>-<slug>/,寫 script.json,期號同時寫進 cover.no。
  2. 畫面:寫同目錄的 shots.js,鏡頭數等於旁白行數。
  3. 配音:uv run tools/voice.py <slug>。改了旁白、音色或封面文案都要重跑。
  4. 靜幀檢查:見下面「靜幀檢查」。
  5. 成片:node tools/render.mjs <slug>,再跑 covers.sh 和 sheet.sh,看一遍聯絡表。
  6. 交付:見本文最後一節。

調整期號時,目錄名前綴和 cover.no 一起改,然後重跑配音和渲染。只改封面字不用重配音:改 script.json 的 cover,把 build/timeline.js 裡的 cover 換成同樣的內容,再跑渲染和 covers.sh。

script.json

{
 "title": "這個影片是程式碼畫的",
 "cover": { "no": "01", "lines": ["這個影片", "是程式碼畫的"], "hot": 1, "tag": "沒有剪輯軟體,也沒有影片模型" },
 "voice": "zh-CN-YunxiNeural",
 "rate": "+6%",
 "lines": [["你看到的每一幀,", "都是程式碼畫出來的。"], ["頁面只暴露一個函數:", "給它一個時間,", "它畫出那一刻的畫面。"]]
}
  • 一行是一個鏡頭,行內每個分句是一個畫面節拍。分句可以寫成 [唸的文字, 字幕文字]:念「百分之七十五」,顯示「75%」;英文術語唸不準時也用這個辦法改唸法。
  • 封面:lines 兩行以內,hot 是用主色的那一行,tag 是一句帶具體數字或結論的鉤子,no 是兩位期號。封面標題、平台標題和第一句旁白說同一件事。

腳本怎麼寫

  • 豎屏刷到的短影片,75–90 秒、8–9 個鏡頭比較合適。+6% 語速約每秒 4.8 字(含停頓),旁白約 380–430 字(中文字加英文單字)。超了先刪字再配音。
  • 前兩秒放這一期最吸引人的東西。 寫腳本前先回答:這一期真正抓人的是哪一點?通常是一個反直覺的數字、一個具體的結果,或觀眾正在遇到的問題。模板裡旁白 0.5 秒開口(tools/voice.py 的 HEAD),到 2 秒只唸得完 8–9 個字,所以第 0 個分句要短,開頭幾個字就是這一點;第 1 個鏡頭在 1.2 秒前把它做成大字,封面的 tag 也說這一點。這一點要用觀眾自己的說法,帶上主題詞(「推理強度別拉滿」,接著才說「從 High 拉到 Max,花費 2.9 倍,分數只多 0.6 分」),然後再進正文。不鋪墊、不自我介紹、不說「今天我們來聊」,不用光禿禿的「X 是什麼?」,也不用「同一個 A,同一個 B」這類還沒給資訊的鋪墊。這是從少量影片裡看出的經驗,按待驗證處理。
  • 下面幾種順序可以作為起點,按內容調整。
  • 教學類:最終效果 → 一步一個鏡頭 → 常見的坑 → 一句話收尾。
  • 產品介紹:它解決什麼問題 → 兩三個主要功能,一個功能一個鏡頭 → 怎麼開始 → 一句話收尾。
  • 概念講解:結論和數字 → 舊做法或常見誤解 → 問題出在哪 → 新做法 → 具體機制 → 實測或官方資料 → 一句話收尾。
  • 研究發現:結論和數字 → 常見誤解 → 實驗怎麼做的 → 結果 → 後續研究 → 原因 → 一句話收尾。
  • 收尾先用一句話說清結論或給出做法,再用一個觀眾憑自己經驗就能回答的問句(「你平時開哪一檔?」),引導留言。問句和置頂留言呼應。這條也按待驗證處理,看留言數有沒有變化。不單獨做講限制的鏡頭,資料的限制條件寫在資料鏡頭的來源註腳裡。
  • 不說「下一期講」「上一期講過」,發布順序可能調整。要呼應別的期,說「講某某的那一期」。
  • 原文給了誤差範圍時,落在誤差內的差距說成「幾乎沒變」。自己推出來的數要在交付時列為弱證據。
  • 口播裡不出現網址,不說「去某網站看」「搜尋某某」(平台把這類內容算作站外導流,見 video-publish skill)。

畫面怎麼畫

shots.js 是一個立即執行函數,最後寫 window.SHOTS = [...]。每個鏡頭是 (c, k) => {}:

  • c 是 1920×1080 的 Canvas 2D 上下文。
  • k.at(i, delay, dur) 返回第 i 個分句開始 delay 秒後、在 dur 秒內從 0 到 1 的緩出進度;k.raw 是同樣的線性進度;k.t 是鏡頭內已過的秒數,k.d 是這一行旁白的時長,k.segs 是各分句相對鏡頭起點的秒數。
  • 繪圖工具在 window.E:title(鏡頭標題加品牌筆畫)、txt、measure、rise(淡入加位移)、pop(彈出)、rrect、path(按進度畫折線)、arrow、chip(標籤塊)、code(打字機程式碼塊)、stroke(品牌筆畫)、mark(頭像)、sign(片尾落款)、fmt,配色 C、字型 F。先讀 src/lib.js 的函數簽名再用。缺的工具寫在自己那期的 shots.js 裡,不要為單個鏡頭改 lib.js 和 run.js。

規矩:

  • 每個分句都對應畫面上的一個新東西,2–4 秒必須有變化。一個鏡頭只講一件事,用圖講:流程箭頭、數量點陣、對比條、程式碼塊、表格,不要整頁文字。
  • 左對齊、不對稱。不做深色背景加置中大字,不讓所有元素一起淡入,不加發光。
  • 主強調色標「這一屏要看的那個數」,不代表好壞;點睛色一屏最多用一兩處。
  • 按手機直立觀看橫向畫面來決定字號:txt 會把小於 56 的字號抬高(傳 24 畫成 34px,傳 30 畫成 38px),承載資訊的字傳入值不小於 30,來源註腳可以傳 24。估寬度按抬高後的字號算,等寬字型每個字元約為字號的 0.6 倍。
  • 版面邊界:字幕條在 y 932 以下,一行約 30 個全形字;封面鉤子句約 14 個全形字會碰到頭像;鏡頭有 1.025 倍的緩慢推近,貼邊元素留 20px 以上;傳 24 的註腳一行約 48 個全形字。
  • 宋體 Black 沒有「÷」,「×」會畫成很大的叉:運算子用蘋方畫,或寫成「除以」「倍」。200px 大標題裡英文的下伸筆畫會壓到下一行。
  • 第 0 個分句很短時,鏡頭開頭容易空屏:把圖的骨架(軸、表頭、輪廓)放在第 0 個分句進場,資料跟著後面的分句出現。
  • 不是實測資料畫出來的圖示「示意圖」。從原文圖表上讀出來的數字,註腳寫「讀自原文圖表」。資料鏡頭底部寫來源註腳,只寫名稱(「來源:某某官方文件」),不寫網域和網址。
  • 每個鏡頭都用 E.title 出標題;最後一個鏡頭用 E.sign 落款。

靜幀檢查

node tools/render.mjs <slug> --stills auto 出每個鏡頭的末幀;--stills 0,t1,t2,… 出指定秒數的幀(0 是封面)。中間幀取每行起點後約 0.4 秒和每個分句後約 1 秒,時間點從該期的 build/timeline.js 裡讀。每次 --stills 會清空上一批,所以分批看,或把時間點並進同一條命令。張數多時用 ffmpeg 拼成聯絡表,封面和末幀看原尺寸。

逐張確認:

  • 文字有沒有超出卡片、程式碼塊、表格列,或者被字幕條和進度條擋住。
  • 右對齊的數字和左邊的標籤有沒有碰上;座標軸標籤和曲線標籤有沒有疊在一起。
  • 鏡頭的最後一幀是不是資訊最全的一幀,有沒有元素還沒進場。
  • 封面兩行標題有沒有縮得太小,鉤子句有沒有超寬。
  • 有沒有兩三秒沒有新東西的空畫面,尤其是鏡頭開頭。

發現問題就改,不帶著已知的溢出出成片。只改畫面時直接重跑渲染。

已知限制

  • edge-tts 走的是微軟的非官方介面。7.2.8 版從 2026-10 起返回 403(rany2/edge-tts #490),tools/voice.py 釘在修復 PR #491 的提交上;官方發新版後換回 edge-tts==<新版本>。再出 403 先去上游倉庫看 issue。
  • agent 聽不到配音:英文術語的讀音和語速要人聽一遍。合成中途斷流由 voice.py 的時長檢查兜底。
  • 沒有動態模糊,也沒有按音樂節拍剪輯。

交付時要說明的

  • 配音沒有人聽過。
  • 靜幀檢查的結果,包含還留著的已知問題。
  • 成片、三張封面和聯絡表的路徑,以及時長。

Individual skills in this repo

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

相關技能