Communitygithub.com

体素动画

使用 Three.js 构建块状体素风格的 3D 场景和动画(类似积木游戏的视觉效果),生成程序化像素纹理和原创方块角色,并导出逐帧精确的视频(带 Alpha 通道的 .mov、.mp4)或可分享的 HTML 页面。适用于体素或方块动画、“逐块搭建”场景、科学概念的方块世界解说以及像素艺术 3D 片头。

体素动画 是什么?

该技能允许开发者使用 Three.js 创建类似积木游戏的 3D 场景和动画,所有纹理在运行时通过代码生成,角色也是原创设计。它提供了一个完整的体素工具包(包含纹理、材质、摄像机、地形、角色、粒子系统等),帮助开发者快速构建并导出交互式 HTML 页面或逐帧精确的视频。支持多种导出格式,包括带 Alpha 通道的 .mov、.mp4 和 .webm。该技能特别适用于需要体素或方块风格动画、‘逐块搭建’演示、科学概念的方块世界解说、像素艺术 3D 片头等场景。它支持命令行渲染和 URL 参数控制,并可生成可分享的独立 HTML 文件,兼容 Claude Code、Cursor、Codex 等主流 AI 代理平台。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/normix93/voxel-animations/tree/HEAD

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

体素动画 是做什么的?

制作看起来像积木游戏的场景,而不使用任何来自这类游戏的元素:每个纹理都在代码中运行时生成,角色是原创设计。输出是一个自包含的 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 获取完整的技能包再构建。

工作流程

  1. 用一句话确定创意:什么被建造、变换或解释,以及循环如何结束(重置、爆炸、冻结、摄像机飞出)。确定目标:交互页面、用于剪辑的视频(透明背景或不透明)、竖版短视频(1080×1920)。
  2. 将故事板组织成时间线:3-6 个节拍并附上时长,例如 0-2 秒 空地 → 2-40 秒 建造 → 40-44 秒 欢呼 → 44-49 秒 爆炸 → 循环。每个节拍是 app.onUpdate 状态机中的一个 mode(参见房屋示例)。
  3. 从 assets/template.html 开始,保留工具包标记,编写 SCENE 部分。重用工具包中的组件,不要重写。将所有内容保持在一个页面中。
  4. 构建页面:python3 scripts/inline_kit.py scene.src.html scene.html。
  5. 检查它:打开页面(或使用 render.py 渲染几帧到一个文件夹并查看)。检查:方块悬浮或重叠、角色穿墙、摄像机切入树木、前几秒空白、透明方块闪烁。
  6. 交付:当环境支持时,将页面作为工件发布,同时提供 .html 文件;如果需要,渲染视频(参见导出)。

风格规则

  • 仅限原创。 绝不使用现有游戏中的纹理、音效、标志、生物、角色或名称。不要将输出称为“Minecraft”相关内容:使用体素、方块、方块世界。工具包中的程序化纹理和戴安全帽的建造者可以安全使用和修改。
  • 像素清晰:使用 NearestFilter 的 16×16 纹理(工具包已处理)。硬光、清晰阴影、每种材质颜色少、小噪点。
  • 运动有重量:方块弹出时带有超调(app.pop),碎片使用重力(≈20–22 方块/秒²)和阻尼弹跳,角色以约 5 方块/秒的速度行走并平滑转向。任何物理相关的动画都不要使用线性补间。
  • 一目了然:一个主要主体在中央,摄像机缓慢环绕(autoSpeed 0.05–0.1),背景平静(天空或 studio 颜色)。
  • 文字:页面可以有标题和状态行。对于视频,使用 ?clean 渲染(无 UI)。如果视频中需要标签,使用非常短的词语;解释应放在旁白或页面中,而不是帧上。

工具包 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 压平,在两个位置之间使用缓动 lerp 滑动。
  • 原子/分子:使用 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            # ProRes 4444 with alpha
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 则检查是否包含。
  • 代码、标题、文件名中均无第三方游戏名称、纹理或角色。

相关技能