Communitygithub.com

Apollonny/stickman-explainer

將腳本轉換為垂直(9:16)手繪火柴人解說/故事影片(適用於 Instagram Reels、Shorts、TikTok 歷史與趣聞風格),使用由 JSON 故事板驅動的 Python 渲染器。

stickman-explainer 是什麼?

此技能提供一個自動化工作流程,用於從文字腳本生成具備獨特視覺風格的動畫解說影片。它利用一個 Python 渲染器(`scripts/render.py`),該渲染器讀取一個結構化的 JSON 故事板,並輸出 1080×1920 解析度的 MP4 影片。輸出的影片模仿手繪外觀,具有搖晃的墨線條、8 fps 的線條沸騰效果,以及淡入、擦除、彈出等過場動畫。視覺風格預設為奶油色的紙質背景(`#f3ebdd`)、深色墨線(`#2b2723`)與語義磚紅色強調色(`#b8372d`),可選金色太陽主題。此技能特別設計用於支援像 Instagram Reels、Shorts 或 TikTok 這類平台的垂直影片。主要功能包括:精細的故事板結構(支援角色、道具、對話框、自訂形狀)、場景間的連續性(透過元素繼承與動畫)、基於時間軸的逐字卡拉 OK 式字幕強調(使紅色強調色跟隨口語),以及完整的驗證與錯誤處理。工作流程建議在完整渲染前先使用靜態圖片與草稿影片進行迭代,以確保正確的佈局與時序。

相容平台✓Claude Code✓Codex CLI~Cursor✓Antigravity✓OpenCode
npx skills add https://github.com/Apollonny/stickman-explainer/tree/main/stickman-explainer

在你喜歡的 AI 中提問

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

說明文件

stickman-explainer 是做什麼的?

將一個簡短的腳本轉換為完成的 1080×1920 mp4。你撰寫一個故事板 JSON;scripts/render.py 會繪製每一幀(搖晃的墨線條,8 fps 線條沸騰,淡入/擦除/彈出顯示效果)並使用 ffmpeg 編碼。

assets/example_storyboard.json 僅作為語法範例(3 個場景);請勿將其佈局或角色配件複製為範本。

視覺風格預設值

  • 使用 9:16 畫布(1080×1920,30 fps)。每個場景保持在一個概念,通常 2.5–4 秒,字幕保持在平台安全區域內。
  • 使用溫暖的紙色(#f3ebdd)、深色墨線(#2b2723)和語義磚紅色強調色(#b8372d)。太陽金色(#d89d48)僅可選用於太陽主題。保持其他部分扁平:無漸層、陰影或 3D 效果。
  • 使用清晰的臉部和充足的留白繪製簡單的黑墨色人物。除非故事或用戶要求,否則請勿添加頭盔、皇冠、斗篷、紅色衣物或其他配件。請勿從歷史名稱推斷服裝。
  • 保持場景可讀性:最多 2 個角色和 5 個小圖示。讓主體突出;避免字幕和道具重疊。不超過 2 行字幕。
  • 使複雜道具易於辨識。繪製一個具有清晰交叉環、緊密中心和可見繩端的繩結。為劍繪製清晰的握柄、護手和尖銳劍身。切割後,在兩條繩端之間留下可見間隙。
  • 當旁白時間點可用時,使紅色字幕強調色在旁白過程中跟隨當前口語的單詞。為每個以空白分隔的字幕單詞使用一個 karaoke 區間;非活躍的單詞保持正常文字顏色。
  • 偏好不對稱佈局並刻意留下留白。地面線條、太陽、標題卡、對話框和其他主題為可選;僅在它們支援場景時選擇使用。

工作流程

  1. 腳本 → 場景。 將故事拆分為一句一個場景(字幕 ≤ 6 個單詞,每個 2.5–4 秒)。模式:標題卡 → 鉤子/衝突 → 具體揭示。每個場景只增加一個新資訊。當提供旁白時,場景邊界應與口語句子對齊。
  2. 為每個句子選擇一個視覺。 每個場景一個隱喻:角色 + 道具、對話框、或一排圖示(X = "不具有")。保持 ≤ 2 個角色和 ≤ 5 個圖示。
  3. 撰寫故事板(結構如下)。對於逐字旁白時間點,為每個以空白分隔的字幕單詞添加一個 karaoke 區間,使紅色強調色跟隨正在發音的單詞。只有在單詞時間點不可用時才使用 **word** 進行靜態高亮;請勿將靜態標記與 karaoke 結合使用。
  4. 先檢查靜態圖片(快速,約 2 秒/場景): python scripts/render.py story.json --stills out/stills → 開啟每個 scene_NN.png,修正重疊/放置問題,重複執行。
  5. 草稿影片: python scripts/render.py story.json out/draft.mp4 --draft(無超採樣,12 fps)。
  6. 最終版本: python scripts/render.py story.json out/final.mp4 [--audio voiceover.mp3]。 場景時長應與旁白句子長度匹配;使用 ffprobe 測量音訊並相應設定 duration。單詞區間是從其場景開始的秒數,應來自旁白對齊或仔細聆聽。確保每個紅色單詞與其口語音訊同時出現,既不提前也不延後。

錯誤訊息與驗證

render.py 在繪製故事板前會進行驗證:未知的 type/pose/face/kind/font、缺少必填欄位、同一場景中重複的 id、duration <= 0、單點 lines 路徑、奇數(非偶數)解析度以及不存在的 carry id 將以明確訊息拒絕,而非回溯追蹤。對於永遠不會顯示的元素(場景結束後的 at)會發出警告。如果音訊檔案比影片短,結尾將填充靜音;如果較長,則會被截斷;影片長度絕不會改變。

故事板結構

{"meta": {"width":1080,"height":1920,"fps":30,"boil_fps":8,"transition":0.18,
          "palette":{"accent":"#b8372d"}, "audio":null, "font_dirs":[]},
 "scenes":[{"duration":3.4, "caption":"是偉大的 **亞歷山大**。",
            "caption_at":0.5, "caption_y":null, "elements":[ ... ]}]}

對於跟隨語音的單詞強調,請提供一個 karaoke 陣列,其中包含 caption 中每個以空白分隔的單詞一個 { "start": seconds, "end": seconds } 物件。時間是相對於場景的;紅色強調色在每個區間切換。當存在 karaoke 時,字幕不得包含 **...** 標記。

{"duration":2.8, "caption":"他一手刀劈開了繩結。", "caption_at":0.35,
 "karaoke":[{"start":0.35,"end":0.76},{"start":0.76,"end":1.02},
            {"start":1.02,"end":1.53},{"start":1.53,"end":2.15}],
 "elements":[ ... ]}

每個元素:type,可選 id(用於延續)、at(秒,出現時間)、dur(顯示秒數)、anim = fade | wipe | rise | pop、until/out_dur(淡出秒數)。 位置 x、x2、y、ground ≤ 2 時被視為寬度/高度的比例,否則為像素。尺寸始終為像素。

類型關鍵欄位
groundy(必填);x、x2 可選,若未提供則約為畫布的 ~2%–98% — 搖擺的基線
sunx、y、r、rays
texttext(**accent** 標記)、x、y、size、font = sans/sans_bold/sans_light/serif、tracking、caps、color、max_w、max_lines(預設 3)、rules(用於標題卡的雙線;寬度和間距根據文字自動調整)
figurex、ground、h、head_r、pose = stand/arms_open/point/wave/think/shrug/sit、dir(±1)、face = neutral/smile/sad/surprised/angry、可選 accessory = helmet/crown/hat/glasses、可選 cape、look
propkind = barrel/bowl/bucket/house/book/box/triangle/coins/tree、x、y(左上角)、w、h、cross(強調色 X)、flip
thoughtx、y、w、h、tail_to [px,py](頭部位置)、inner:氣泡本地像素座標中的元素列表
linespaths(點的列表的列表,本地像素)、closed、smooth、color、width — 用於任何自訂形狀的逃生口

場景間的連續性(延續)

要將一個場景的元素帶到後續場景,請為該元素賦予 id,並在下一個場景中使用 carry 引用它。攜帶的元素以相同的線條震動(相同的種子)開始,使其看起來像是「同一幅畫」,即使場景變換;新的場景過渡預設為剪切(無交叉淡入淡出)。

"carry": [
  "ground",
  {"id": "sun",  "set": {"r": 122}},
  {"id": "alex", "set": {"x": 120, "face": "smile"}, "tween": {"at": 0.1, "dur": 0.9}},
  {"id": "diog", "until": 0.1, "out_dur": 0.5}
]

各行依序:"ground" 按原樣攜帶 · sun 攜帶但修改欄位(修改在場景開始時立即生效) · alex 同時修改欄位並在持續時間內調整位置(tween) · diog 被攜帶但在場景內淡出。

  • "carry": "all" 攜帶所有內容("carry_except": ["id", ...] 排除特定項目)。字幕永遠不會被攜帶。
  • 未攜帶的元素在場景開始時立即消失;使用 until/out_dur 實現平滑淡出。使用 until 淡出的元素不能攜帶到下一個場景。
  • tween 僅動畫位置(x 和 y/ground);尺寸(r、h、w)和外觀(face、pose)的變化在場景開始時立即應用。
  • 攜帶的元素在新元素的下方繪製。要攜帶的元素在場景間的 id 必須是唯一的。
  • 具有相同 id 的元素在每個場景中使用相同的種子;不要為場景特定的新元素賦予 id。

透過擴展 render.py 中的 PROPS / hands 來新增道具/姿勢;保持相同的墨線風格(使用 stroke(),永遠不要使用普通線條)。

佈局:每次影片重新決定

無固定座標/範本。由於每個影片的主題不同,請從場景內容推導佈局:

  • 首先選擇該句子的單一視覺概念(比較、列表、夢想、旅程、數字…),然後建立與之匹配的佈局。同一個影片中,場景間的佈局可以改變。
  • 為重要元素留出空間:主體應該是最大/最突出的;次要元素保持較小。刻意留出空白(負空間)。
  • 大小、位置和數量根據內容變化(1 個還是 2 個角色;圖示條、單個大型物體還是地圖/時間線)。必要時使用 lines 繪製自訂形狀。
  • 請勿為歷史人物自動添加服裝/頭飾。人物預設繪製為無配件模式;頭盔、皇冠、帽子或斗篷僅在敘述或用戶明確要求時添加。請勿將強調色擴散到角色的服裝上作為裝飾。
  • 在繩結和切割場景中,以可讀的方式建構物體:用幾個明顯重疊的環圈繪製繩子,在中心顯示緊密的繩結,並區分繩端。劍應可辨識出握柄、護手和尖銳劍身。切割後,將兩條切斷的繩端清晰間隔並明顯可見;劍和繩結不應被字幕遮擋。使用 lines 繪製自訂的繩子/劍形狀。
  • 地面線條、太陽、標題卡等主題是可選的;如果不適合主題則不要使用(例如室內、夜晚、抽象概念)。
  • 將字幕放在可讀且遠離平台 UI 的位置;如果衝突,調整 caption_y。在靜態圖片中目視檢查衝突和溢出,不要依賴數字。
  • 繪製座標以像素(或 0–2 範圍的比例)給出,基於 1080×1920 畫布;為每個場景從頭規劃數值。

注意事項

  • 在編碼前務必檢視靜態圖片;重疊元素和裁剪的太陽光線是常見缺陷。使用 --draft 進行草稿,使用完整渲染處理細節:不變的幀不會重繪,10 秒的影片全品質約需 20 秒。
  • 字幕會換行至 86% 寬度(最多 3 行),但如果一個單詞無法容納或超過 3 行,則會縮小。將超過 2 行的句子拆分為兩個場景。預設字幕位置僅為備用;必要時在場景中提供 caption_y。
  • 字型:安裝 Poppins 和 Playfair Display(或 Lora),或提供 --font-dir。如果找不到 TrueType 字型,渲染器將列印警告,且土耳其語字元(İ ş ğ â)可能缺失;在靜態圖片中檢查。會掃描 Linux、macOS 和 Windows 字型資料夾。
  • 保持強調色的語義性(主體、關鍵字、否定)。不要添加更多顏色。
  • 當存在 karaoke 時,紅色字幕強調色使用提供的區間逐字跟隨旁白。不要在螢幕上留下固定的紅色關鍵字;以字幕文字顏色渲染非活躍的單詞。

相關技能