Voxel 動畫
製作外觀像積木建造遊戲的場景,但完全不使用現有遊戲的任何素材: 每個紋理都在程式碼中即時生成,角色也是原創設計。 輸出是一個自包含的 HTML 頁面(互動且可分享),並且在要求時, 可從同一個頁面渲染出逐幀精確的影片。
此技能包含的檔案
assets/voxel-kit.js:工具包(紋理、材質、應用程式循環、軌道攝影機、日夜天空、島嶼地形、工作室平台、角色骨架、粒子、彈入效果、爆炸、火炬、路徑輔助工具、錄製器、擷取模式)。在撰寫場景之前請先閱讀此檔案:以下的 API 參考為摘要,此檔案才是權威。assets/template.html:起始頁面,包含工具包標記、島嶼、角色和一個簡短的時間軸。examples/house-builder.html:建造者逐塊放置房屋、歡呼、爆炸、循環。examples/melting-crystal.html:物理範例(6×6×6 冰晶格的林德曼熔化,附體素溫度計、水坑和再凍結)。複製其結構以製作科學解說。scripts/inline_kit.py:將頁面中的<!-- VOXEL_KIT -->替換為工具包,產出單一檔案。scripts/render.py:將頁面逐幀精確渲染為 PNG 幀和.mov/.mp4/.webm。
如果只有此 SKILL.md 可用(缺少資料夾),請在開始建構前從 https://github.com/normix93/voxel-animations 取得完整的技能。
工作流程
- 用一句話鎖定想法:要建造、轉換或解釋什麼,以及循環如何結束(重置、爆炸、凍結、攝影機飛出)。決定最終目標:互動頁面、供剪輯用的影片(透明背景或不透明)、豎直短片(1080×1920)。
- 以時間軸進行分鏡:3–6 個節拍,附帶時間長度,例如
0–2 秒 空場地 → 2–40 秒 建造 → 40–44 秒 歡呼 → 44–49 秒 爆炸 → 循環。每個節拍是app.onUpdate狀態機中的一個mode(參見房屋範例)。 - 從
assets/template.html開始,保留工具包標記,撰寫 SCENE 部分。重複使用工具包中的元件,不要重新編寫。保持所有內容在一個頁面中。 - 建構頁面:
python3 scripts/inline_kit.py scene.src.html scene.html。 - 檢查:開啟它(或使用
render.py渲染幾幀到一個資料夾並查看)。檢查:是否有方塊漂浮或重疊、角色穿牆、攝影機卡進樹裡、前幾秒空白、透明方塊閃爍。 - 交付:在環境支援時將頁面發布為成品,並同時交出 .html 檔案;如有要求則渲染影片(參見匯出)。
風格規則
- 僅限原創。 絕對不要使用現有遊戲的紋理、音效、標誌、生物、角色或名稱。不要將輸出稱為「Minecraft」:應稱之為 voxel、blocky、block-world。工具包中的程序化紋理和戴安全帽的建造者可以安全使用和修改。
- 像素清晰:使用
NearestFilter的 16×16 紋理(工具包已處理)。硬光、清晰陰影、每種材質使用少數顏色、小噪點。 - 動作有重量感:方塊以過衝方式彈入(
app.pop),碎片使用重力(≈20–22 區塊/秒²)和阻尼彈跳,角色以約 5 區塊/秒的速度行走並平穩轉向。避免對任何物理相關的動作使用線性補間。 - 一目了然:一個主要主體位於中央,攝影機緩慢環繞(
autoSpeed0.05–0.1),背景平靜(天空或studio顏色)。 - 文字:頁面可以有一個標題和狀態列。對於影片,使用
?clean渲染(無 UI)。如果影片中需要標籤,請使用非常簡短的詞語;說明應放在旁白或頁面中,而不是在影格上。
Kit API(摘要)
const app = VK.createApp({
title, subtitle, hint, // UI 文字(使用 ?clean 或按鍵 H 隱藏)
sky: 'day' | 'night' | 'studio', // studio = 純色(studioColor),無霧
cycle: false, dayLength: 48, tod: .27, // 時間 0..1(.25 日出側,.75 夜晚)
camera: { radius, phi, theta, target: [x,y,z], auto: true, autoSpeed: .07 },
speed: 1, seed: 7, fileName: 'my-scene', shadowSize: 28,
});
app.M.grass | dirt | stone | sand | planks | roof | log | leaves | glass | water | ice | snow | cobble | brick | lava
VK.solid(0xff8800, { glow, opacity, noise, border }) // 彩色像素方塊材質
VK.block(app, 'planks' | material, x, y, z, { pop: true }) // 單一網格(移動/彈入)
VK.instanced(app.scene, material, [[x,y,z], ...]) // 靜態方塊,一次繪製呼叫
const world = VK.island(app, { seed, radius: 18, flatRadius: 7.5, trees: 10, water: -1, snowLine })
// → world.groundTopAt(x, z), world.hAt(ix, iz)
VK.platform(app, { size: 16, top: .5, mat: 'stone', topMat: 'cobble' }) // 工作室地板
const hero = VK.character(app, { ground: world.groundTopAt, position: [x,0,z], yaw, colors: { shirt:[r,g,b], hat: 0xf5c518 | null, ... } })
hero.goTo([[x,z], ...]) · hero.arrived · hero.face(x, z, dt) · hero.jump(v)
hero.pose = 'idle' | 'reach' (set hero.reach 0..1) | 'cheer' | 'panic' | 'wave'
hero.lookTarget = {x,y,z} | null
VK.standOutside(x, z, { halfX, halfZ, cx, cz }) // 站在何處以對一個方塊或箱子進行工作
VK.routeAround(from, to, { halfX, halfZ, cx, cz }) // 繞過箱子的路徑點
VK.explode(app, meshes, { center, power, ground, onDone })
VK.torch(app, x, y, z) // 燈光在夜晚變強
app.puff(position, material, n, power) · app.pop(mesh) · app.clearParticles()
app.onUpdate((dt, time) => { ... }) // dt 已按速度縮放;在擷取模式下是確定性的
app.rand() // 種子亂數:用它來代替 Math.random
app.status(html) · app.button({ label, key, toggle, on, onClick }) · app.standardButtons({ cycle })
app.start()
確保場景正確的規則:
- 使用
app.rand()(基於種子),絕對不要用Math.random(),這樣渲染才能重複。 - 所有動畫放在
app.onUpdate中使用dt;絕對不要用setTimeout/setInterval做動畫(會破壞擷取模式)。 - 方塊為 1×1×1 且中心位於整數座標;高度
h的柱子其頂面位於h + 0.5。角色站在groundTopAt(x, z)。 - 靜態場景 →
VK.instanced;任何移動、彈入或爆炸的物件 →VK.block。 - 大量物件:保持移動的網格在 ~1500 以下;超出此範圍,請動畫化 InstancedMesh。
配方
- 建造序列:製作有序計畫
[{type,x,y,z}](逐層、沿周長行走;屋頂用蛇形行)。對每個項目:導航到standOutside,設定pose='reach',在到達約 45% 時生成,下一步。參見examples/house-builder.html。 - 用方塊解釋物理:將物理量映射到可見事物。溫度 → 抖動幅度 ∝ √T(均分定理);壓力 → 方塊碰撞;能量階層 → 塔的樓層;場 → 方塊箭頭;熵 → 有序牆壁重新排列;重力 → 未支撐時倒塌的堆疊。用體素計(如
melting-crystal.html中的溫度計)顯示控制變數,而不是在畫面上顯示數字。 - 轉換:改變
mesh.material(水 ↔ 冰,石頭 → 岩漿),使用scale.y壓平,使用兩個位置間的緩動線性插值滑動。 - 原子 / 分子:
VK.solid(colour)立方體作為粒子,glow: true用於電子或光子,小立方體(mesh.scale.setScalar(.3))用於軌跡。 - 循環結局:爆炸(
VK.explode)→ 重置,或凍結 + 慢速攝影機,或夜幕降臨(app.sky.cycle = true)搭配火炬。
匯出
URL 參數(適用於任何使用此工具包建立的頁面):
?clean 隱藏 UI · ?alpha 透明背景(無天空、無霧) · ?seed=3 ·
?speed=2 · ?night · ?capture&fps=30 渲染器使用的逐幀精確模式。
按鍵:H 隱藏 UI · Space 暫停 · V 快速即時 WebM 錄製(當頁面從本地檔案開啟時有效;託管預覽可能阻擋下載)。
逐幀精確影片(建議用於剪輯):
pip install playwright && python3 -m playwright install chromium # 一次性,也需要 ffmpeg
python3 scripts/render.py scene.html --seconds 12 --fps 30 --out scene.mov # ProRes 422 HQ
python3 scripts/render.py scene.html --seconds 12 --alpha --out overlay.mov # 含 Alpha 的 ProRes 4444
python3 scripts/render.py scene.html --size 1080x1920 --warmup 3 --out short.mp4 # 直式 H.264
python3 scripts/render.py scene.html --seconds 5 --out frames/ # 僅 PNG 幀
--warmup 在錄製前跳過場景的前幾秒;--params "seed=3&night" 添加 URL 參數;--headed 使用可見瀏覽器(真實 GPU,在大多數筆記型電腦上更快)。使用 --alpha 時攝影機仍會環繞;請設定 camera: { auto: false } 以獲得靜態疊加層。
交付前檢查
- 頁面開啟時無控制台錯誤;第一幀已顯示主題。
- 循環至少可運行兩次(重置會清除網格、燈光和粒子)。
- 角色永不穿牆;除非有意為之,否則沒有東西漂浮。
- 對於影片:使用
?clean渲染、正確大小/幀率、如要求則檢查 Alpha 通道。 - 程式碼、標題、檔案名稱中無第三方遊戲的名稱、紋理或角色。