Communitygithub.com

ninjasweb/painter-skill

以程式碼繪製場景並轉為影片 — 具備油畫筆觸(刷毛、厚塗、乾筆、畫布紋理)、光譜顏料混合、逐步揭示繪製過程及「活畫作」動態效果(風、浮雲、波光、視差鏡頭)。

painter-skill 是什麼?

這個技能讓開發者能像畫家一樣以程式碼作畫:先決定構圖、明暗與色調,再從後往前放置真實筆觸,並反覆檢視與調整。引擎會將這些筆觸轉換為幀,而非對渲染結果套用濾鏡。它支援 WebGPU/WGSL 實例化筆觸、headless Chrome、WebCodecs 與 Mediabunny 的 MP4 匯出,以及 ffmpeg 品質檢查。平台包括 Node.js 22.12 以上、具備 WebGPU 的 Chrome、ffmpeg 與 ffprobe,完全在本機硬體上執行,無需建置步驟或 API 金鑰。使用場景包含:油畫風格/手繪風動畫、縮時繪畫影片、動態風景或背景、故事/音樂/氛圍影片的繪畫感畫面,以及研習參考畫作的構圖、明暗與色調。觸發關鍵字如「pintar」、「pintura animada」、「escena pintada」、「óleo」、「painterly」、「paint a scene」、「speedpaint」、「living painting」。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ninjasweb/painter-skill/tree/HEAD

在你喜歡的 AI 中提問

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

說明文件

油畫風格影片

你用程式碼作畫,就像畫家用畫筆作畫一樣:先決定畫面(構圖、明暗、色調),然後從後往前鋪上真實的筆觸,檢視結果,再調整。 引擎將這些筆觸轉換為幀;沒有任何東西是渲染效果濾鏡 — 每一個標記都是你放置的筆觸。

這個方法取自四場繪畫示範(過程、松樹、油畫樹林、日落雲彩)以及對 13 幅公共領域大師風景畫的測量。提煉出的心得在 references/ 中;可運作的程式碼在 engine/ 和 examples/ 中。

設定(每個專案一次)

cp -R /path/to/painterly-video/engine ./painter-engine
cd painter-engine
npm ci
node bin/paint.mjs still ../path/to/scene.js --t 8          # → PNG 位於場景旁(stills/<scene>/)

請將 /path/to/painterly-video 替換為包含此 SKILL.md 的資料夾(例如 ~/.claude/skills/painterly-video)。需要 Node ≥ 22.12、具有 WebGPU 的 Google Chrome(或設定 CHROME_PATH)、ffmpeg 和 ffprobe。參考研究還需要 Python 與 tools/requirements.txt。無需建置步驟或渲染 API 金鑰;渲染在本機硬體上執行。開始一個新場景時,請複製 examples/ 中最接近的檔案(sunset-river.js 天空/雲/水 · lone-pine.js 垂直構圖、單一主體 · lake-path.js 樹木/縱深/路徑 · sunset-study.js 帶有背光邊緣的暗雲塊戲劇性天空(示範結構研究) · mountain-hamlet.js 山、小屋、岩石、行走人物、煙霧 · brush-chart.js 筆刷與混色)。

工作流程 — 請勿跳過檢視步驟

  1. 簡報。 主題、情緒、時間、格式(16:9、9:16、1:1 — 任意 --size)、時長,以及時間分配方式:逐步揭示、活畫作、或兩者兼具(預設:約 60% 揭示、40% 活畫作)。
  2. 若有參考,則研究參考(tools/study.py,參見 references/composition.md)。它會回報明暗塊、色調、彩度、色板與焦點 — 請模仿其結構,而非畫面。
  3. 先構圖,再上色。 將構圖以註解寫在場景檔案的頂端:地平線高度(絕不能在中間)、焦點(放在三分線上,最強明暗對比與最高彩度處)、引導線、框架元素,以及明暗計畫 — 每個大形狀一個明暗值(0–1),分成三個不相等的大塊。references/composition.md。
  4. 從顏料取色,置於明暗計畫上。 tone(mix({ ultramarine: 1, transYellowOxide: 1 }), 0.42)。除焦點強調外,其餘地方保持低彩度(大師畫作:OKLab 平均彩度 0.02–0.06,高彩度區域約低於 8%)。
  5. 從後往前繪製,使用主題繪製器(paintSky、paintCumulus、paintHills、paintMountains、paintWater、paintTreeline、paintPine、paintFir、paintTree、paintGrass、paintRocks、paintHouse、paintGlow、paintMoon、walker、boat、smoke…)以及原始 layer.scatter/stroke/path 處理其他部分。每個階段一個 p.phase('name'),圖層由遠到近建立。references/api.md。
  6. 檢視、批評、調整 — 至少兩輪。 渲染一張靜態圖,打開 PNG,像判斷油畫一樣判斷它:瞇眼看(三個明暗塊是否清晰?)、焦點是否在計畫位置、是否有任何東西等距/等大/等飽和、是否有筆觸看起來機械化?在程式碼中修正原因。對自己的靜態圖執行 study.py 並與計畫比較。這個循環就是這項技能的核心;第一次渲染永遠不會正確。
  7. 時間。 p.timelapse() 用於揭示,然後是動態:sway、drift、shimmer、p.wind、p.camera(按圖層深度的視差)、p.dynamic 用於移動中的物體。references/animation.md。
  8. 接觸表,然後渲染。 still --n 12 --sheet → 檢查時間軸的每個階段;然後 render → qa。references/pipeline.md。
  9. 如實報告:哪些是自動檢查的、哪些是你親自檢視的、哪些你沒有做。

場景骨架

import { Painting, mix, tone, mixOk, skyColor, paintSky, ridge, paintHills, paintGrass, key, ease } from 'painter';
export const meta = { duration: 16, fps: 30 };

export default function ({ aspect, seed }) {            // aspect = 渲染的寬度 / 高度
  const p = new Painting({ aspect, seed, ground: '#c9b89a' });   // 有色畫布,絕不能用白色
  p.duration = 16;
  const A = aspect;                                     // 場景單位:x 0…A,y 0(頂部)… 1(底部)

  const skyTop = tone(mix({ ultramarine: 2, titaniumWhite: 2 }), 0.72), skyLow = tone(mix({ cadmiumOrange: 1, titaniumWhite: 3 }), 0.88);
  const hillCol = tone(mix({ ultramarine: 1, burntUmber: 1 }), 0.3);
  const hill = ridge({ y: 0.68, amp: 0.05, freq: 2, seed });

  p.phase('sky');
  paintSky(p.layer('sky', { depth: 0 }), { color: skyColor({ top: 0, bottom: 0.7, stops: [[0, skyTop], [1, skyLow]] }), bottom: 0.72 });
  p.phase('land');
  paintHills(p.layer('hill', { depth: 0.6 }), { top: hill, color: (x, y, k) => hillCol, size: 0.03 });
  paintGrass(p.layer('grass', { depth: 1 }), { bounds: [0, 0.8, A, 1.05], dark: hillCol, light: tone(hillCol, 0.5), blade: 0.05 });

  p.timelapse({ start: 0.3, end: 10 });                 // 畫面於 10 秒完成
  p.camera = (t) => ({ zoom: key(t, [[10, 1], [16, 1.07]], ease.inOut) });
  p.wind = (t) => ({ strength: key(t, [[0, 0], [10, 0.15], [12, 1]]) });
  return p;
}

使其看起來像油畫的規則(簡短列表)

  1. 明暗做主要工作,色彩得功勞。 計畫三個不等的明暗塊;對每張靜態圖瞇眼測試。
  2. 底色調,絕不用白色。 選擇底色來和諧畫面(暖赭色襯托綠色,淺奶油色襯托日落)。
  3. 先遠後近。 遠 = 較亮、較冷、較灰、較柔、較薄顏料、較小筆觸。近 = 最暗的暗部、最高對比與彩度、最厚顏料、最大筆觸。使用 atmosphere(color, d, air)。
  4. 暗部先畫且薄,亮部後畫且厚。 陰影與遠處使用 thick 0.1–0.3,高光使用 0.8–1;高光要小且少。
  5. 亮襯暗,暗襯亮。 每個色塊都用與下方相差一個小明暗值(±0.05)的筆觸打破;p.valueAt(x, y) / p.sample(x, y) 可以告訴你下面的值。
  6. 筆觸順應形體:環繞雲塊、沿著山坡、水平於水面、向上於草葉、向下於樹幹。
  7. 混合綠色並使其沉穩(earth(mix({ ultramarine: 1, cadmiumYellow: 1 }), 0.3));純彩度只留給一個重點。
  8. 讓一切變化:大小、間距、高度、間隔。相等 = 機械化。奇數群組、重疊形狀、一個主導。
  9. 消失與清晰邊緣:形體轉向或後退處柔化(soft 0.5+),焦點處清晰。
  10. 時間的純函數。 場景由 seed 決定;每一幀只取決於 t。絕不使用 Math.random() 或真實時鐘時間 — 使用 layer.rand / rng(seed)。

常出錯的地方(從建置過程中學到)

  • 白色吞噬混色。 光譜混合器按亮度加權顏料;1:9 的顏色:白色混色幾乎是白色。先用少量或不用白色混合色相,再用 tone(c, value) 放置。用 chroma(c, 0.5–0.8) 削減刺眼的結果。
  • 雲像球加棍 → 扁平基底上的許多小葉狀(cumulusShape 葉數 40–60),僅朝向太陽一側亮色,圓潤柔和的點畫,適度的 thick。
  • 松樹像棕櫚樹 → 針葉是圓形簇(短扇形筆觸爆發)位於枝條上,其間有天空空隙,下方暗,上方亮;枝條低垂且高舉。
  • 樹木有傘輻狀枝條/黑色樹幹 → 枝條末端必須在樹冠內;樹幹暗部明暗值約 0.22,非黑色,並隨距離增加空氣感(atmosphere)。
  • 整個區域使用飽和顏色(橙色地面、綠松色天空) → 使其沉穩;將純色作為少量小筆觸散佈。
  • 路徑看起來像河流 → 暖淺灰色,筆觸沿行進方向,冷紫色僅用於陰影。
  • 水由短劃組成看起來像數位效果 → 水是長水平拖筆,彼此融合,僅在靠近觀者處有少許漣漪(paintWater 的作用);不要手動添加一排排劃線。
  • 海洋看起來像玻璃鏡面 → paintWater({ chop: 1 }) 用於波背與白浪;湖泊與河流保持 chop: 0。
  • 燈/窗光看起來像平板一塊 → 在暗色環境上用 paintGlow,然後加上小而熱的核心;一筆長柔筆觸不是發光。
  • 光線看起來像白色尖刺 → 少、寬、非常柔、低不透明度的光束(paintRays 預設值)。
  • 畫布紋理在淺薄顏料上變成網格 → 保持 look.weave ≤ 0.2。
  • 山看起來像鱗片牆或斑馬條紋 → 用 peaks() 建立天際線,保持遠距(薄顏料、size ≈ 0.02、窄明暗範圍),讓 paintMountains 將其分成少數幾個大的受光與陰影平面。
  • 平坦帶狀不是雲層/山丘/樹線 → 變化頂緣、內部數值並留下空隙。
  • 場景因模糊的瀏覽器錯誤而失敗 → CLI 先進行語法檢查;執行時錯誤會印出行號。區域變數遮蔽顏色名稱(leaf、sky、hill)通常是 c.map is not a function 的原因。
  • 讀取過時的靜態圖:打開 PNG 前務必檢查命令輸出是否有錯誤。
  • WebGPU 與 WebCodecs 僅存在於安全來源 — CLI 使用 http://127.0.0.1;絕不要透過 file:// 開啟場景。

參考檔案

  • references/painting-lessons.md — 每場示範的教學內容及其如何映射到引擎呼叫。
  • references/composition.md — 場景構圖、明暗計畫、大師畫作的數據、study.py。
  • references/api.md — Painting / layer / brush / colour / subject-painter 參考,撰寫新的主題繪製器。
  • references/animation.md — 揭示節奏、活畫作動態、相機與視差、動態圖層、煮沸效果、音訊。
  • references/pipeline.md — CLI、渲染設定、效能、品質檢查、疑難排解、交付成果。

相關技能