線稿動畫
動畫插圖元件:所有內容都用一支細鋼筆在紙上繪製, 在 SVG 中透過 TypeScript 即時建構,因此無論縮放多少 都保持清晰,能回應滑鼠指標, 且可逐格步進以進行檢查或影片輸出。
此技能包含一個小型函式庫 (lib/)、兩個範例(examples/walker,
約 150 行的單一人物;examples/village,完整場景)以及工具(scripts/)。
在開始書寫任何程式碼前,請先閱讀最接近需求的範例。
人們如何評斷這項作品
他們會像動畫師一樣審視:逐格、放大、對照現實或參考資料。以下都是 在實務中被拒絕的情況,每一項都對應一條規則:
- 像正弦波一樣上下彈跳的走路、滑動的腳、為了配合延時攝影而加快的步伐
- 肢體畫成封閉的管狀;筆直的尺規線條;僵硬到忽略雙腿的衣物
- 一次建構完成、看起來都一樣的整套元件(「AI 垃圾」)
- 感覺像 UI 而非世界反應的互動
- 背景隨場景改變的頁面(「看起來像影片,不是元件」)
- 在要求新角色時重複使用參考片段的角色
- 沒人要求的遺留道具(他們要求移除晾曬的衣物)
工作流程
- 在移動任何東西之前先確定風格。 閱讀
references/style.md。決定 筆觸粗細、紙張顏色、人物比例以及一兩種平面強調色。 - 設定專案。 將
lib/複製到專案中(它是四個無依賴的.ts檔案)並使用 Vite + TypeScript(此儲存庫中的package.json、tsconfig.json和vite.config.ts顯示了設定方式)。元件是純 DOM/SVG — 無需框架。 - 先建立一個角色或一個角落 並展示它(螢幕截圖或短片, 如有參考資料則放在旁邊)。在建立其餘部分之前先獲得同意。一次完成的 整套元件會被退回,認為是泛泛之作;一個好的部分能顯示出水準。
- 讓它動起來,使用
references/motion.md:使用gait()處理走路和跑步,spring()/pendulum()處理任何附著或懸掛的東西,使用curve()或sequence()處理帶關鍵姿勢的 手勢。絕對不要用簡單的正弦波來動畫角色。 - 組合場景,使用
references/scenes.md:在固定頁面背景上的一個 自包含卡片、圖層、來自lib/daynight.ts的按時段調色板、燈光、 風、依時間表出現的人物、屬於反應的互動。 - 在展示任何內容之前先驗證,使用
references/verify.md:型別檢查、?debug步進、每個移動物體的放大幀條紋圖、觸發並逐步執行的互動、 在真實分頁中達到 60 fps。 - 如果有要匹配的參考片段,請遵循
references/matching.md— 從片段中 測量時間點和姿勢,而不是猜測,並使用疊加圖層檢查。 - 如果他們想要影片,請遵循
references/video.md(使用scripts/capture.ts進行確定性 無頭捕獲,然後使用 ffmpeg)。
使其運作的規則
- 肢體是兩條開放筆畫。
limb()繪製一條紙張填充的帶狀區域,位於兩條鋼筆線條之間, 這兩條線在末端彼此留有空隙。這是此風格的標誌。 - 線條是彎曲的。 關節處是圓的,邊緣略微彎曲,沒有任何東西是尺規般筆直的。
- 在各自的空間中繪製每個角色 — 約 95 單位高,腳在 y = 120,朝向 +x 方向,
站立在 x = 40 — 並使用
place(g, x, y, dir, scale)放置它。比例、 筆觸粗細和步伐預設值都假設此空間。 - 衣物是圍繞骨架繪製的。 先處理腿部(即使被隱藏),然後 從前膝和腳踝處繪製外套或和服下擺,使布料隨著步伐 張開和閉合。袖子、圍巾和包包在彈簧上擺動。
- 腳是著地的。 以
gait.speed × scale的速率精確移動步行者, 支撐腳就能保持靜止在地面上。不要為了配合壓縮的時鐘而加快步伐; 應該壓縮抵達時間。 - 墨色是
currentColor,紙張是.pp。 使用applyPalette()重新著色整個繪圖 (白天:暖色紙上的深色墨跡;夜晚:靛藍紙上的淺色墨跡,搭配溫暖的窗戶)。 實心顏色的肢體填充必須使用solid(),否則紙張的 CSS 會優先。 - 元件是一張卡片。 其周圍的頁面永遠不會改變顏色。
- 互動是世界在反應:人物鞠躬或脫帽、貓醒來伸展、 燈籠搖晃、鳥群散開、魚跳躍。滑鼠指標移動就是風。 場景內沒有按鈕;一條微弱的提示線就足夠了。
- 新就是新。 如果需求是「像這個但要是新的」,請保留媒材、鋼筆、 比例和時間感;創造新的角色、活動和道具。
函式庫一覽
| 模組 | 提供功能 |
|---|---|
lib/ink.ts | pen shape blot paint limb solid joint hang curve shoe place toScene inkDefs run |
lib/gait.ts | `gait({ kind: 'walk' |
lib/motion.ts | spring pendulum pointerWind sequence seeded wobble ease minJerk … |
lib/daynight.ts | palette(τ) → sky, paper, ink, lamp, night, sunset; applyPalette nightTint |
run(draw) 驅動一切,使用 draw(t, dt)。兩個 URL 標誌對檢查很重要:
?t=1.25 凍結時間;?debug 停用 rAF 並暴露 window.__step(seconds)
用於精確步進(背景和無頭分頁會限制 rAF,因此請務必在除錯模式下驗證)。
腳本
scripts/capture.ts <url?debug> <outDir> <frames> <fps> [w] [h] [setupJs] [frameJs]— 從無頭 Chrome 取得確定性的 PNG 幀scripts/clip.ts period|blobs …— 區域的循環長度;每幀的深色斑點追蹤scripts/frames.sh <clip> x y w h outDir— 帶網格疊加的幀,用於從片段中讀取姿勢
全部需要 Node ≥ 22.18(TypeScript 原生被剝離)以及 ffmpeg;capture.ts
會在本機尋找 Chrome/Chromium 或使用 $CHROME。