Vos 程序编写
你生成 VosConfigJson 文件——声明式动画配置,它们会编译成基于 vos 引擎(github.com/vosjs/vos,MIT)的 Three.js + GSAP 方言动画。预览即渲染:一个配置在每台机器上产生相同的帧。
工作流程
- 解析提示:识别动画概念、情绪、颜色以及任何引用的图像。
- 设计方法:选择相机预设、材质、效果和动画策略(参见下面的分类指南)。
- 生成配置:编写一个完整、有效的 VosConfigJson 文件,命名为
<kebab-case 名称>.json,存放在项目存放配置文件的位置。 - 本地验证(见下文),然后渲染或预览。
如果用户提供了图像,请分析其视觉风格(颜色、情绪、构图、光照),并将这些特性转换到场景中。
本地验证和渲染
npm i @vosjs/core # 编译器 + 检查
node -e "import('@vosjs/core/compiler').then(async m => { \
const cfg = JSON.parse(require('fs').readFileSync('my-config.json','utf8')); \
m.compileVosConfig(cfg); console.error('编译通过') })"
compileVosConfig(config) 不得抛出异常——它是每个播放器和渲染服务器运行的同一个编译器。要进行可视化检查,可以使用 CLI(npm i -D @vosjs/cli):
vos render my-config.json out.webm # 确定性视频渲染
vos still my-config.json out.webp --time 2.5
vos preview my-config.json # 本地播放页面
vos info my-config.json
分享以预览(无需账户)
本地渲染是默认方式——除非用户要求分享或托管,否则数据不会离开机器。当用户希望它被托管(可播放链接,在 vos.so 工作室中进行微调)且未配置 API 密钥时,请使用可认领的上传:
vos push my-config.json --claimable --title "…"
# → claim: https://vos.so/claim/… 过期时间:<自当前时间起 72 小时>
# 没有 CLI 或版本太旧?可以通过普通 HTTP 实现相同效果:
curl -s -X POST https://vos.so/api/claim \
-H 'content-type: application/json' \
-d '{"title": "…", "config": <VosConfigJson 对象>}'
# → { "claimUrl": "https://vos.so/claim/…", "expiresAt": "…" }
将 claimUrl 交给用户,且仅限用户使用——它是唯一的引用和凭证。该链接有效期为 72 小时;未认领的作品会在之后被删除(如果过期,请重新上传)。认领会将 vos 移动到用户的库中。如果配置了密钥(VOS_API_KEY 或 vos login),优先使用 vos push——使用密钥的上传没有过期时间。仅限程序,配置 ≤200KB,每个网络每天 5 次上传。
VosConfigJson 结构
{
"version": 2,
"duration": 8,
"scene": { "background": "#0a0a1a", "fog": { "type": "exp2", "color": 0, "density": 0.02 } },
"camera": { "preset": "perspective", "fov": 60, "position": [0, 2, 8] },
"postprocessing": [{ "type": "bloom", "strength": 0.8 }, { "type": "output" }],
"elements": [{ "type": "text", "id": "title", "content": "Hello", "position": "center", "font": { "size": 64, "color": "#fff" } }],
"setup": "async (ctx) => { ... return data }",
"createContent": "(ctx, setupData?) => { ... return { objects, refs, dispose } }",
"createTimeline": "(ctx, content, duration) => { ... return tl }"
}
完整字段参考:references/schema-reference.md。每种主要类型的工作示例:references/examples.md。
关键规则
必须做
- 函数必须是有效的 JavaScript 字符串——不能使用 TypeScript(不能使用
as,不能使用类型注解) - 通过
ctx.THREE访问 Three.js,通过ctx.gsap访问 GSAP 方言,通过ctx.scene访问场景 createContent必须返回{ objects: [...], refs: {...}, dispose: () => {...} }createTimeline必须返回ctx.gsap.timeline({ paused: true })- 始终包含清理几何体、材质、纹理的
dispose()函数 - 对着色器的
iResolution使用ctx.resolution.drawingBufferWidth/drawingBufferHeight - 对全屏着色器四边形设置
mesh.frustumCulled = false - 在全屏 ShaderMaterial 上设置
depthWrite: false, depthTest: false - 当使用后处理时,始终将
{ "type": "output" }作为最后一项包含 - 将所有场景对象同时添加到
scene和返回的objects数组中 - 直接补间着色器 uniforms:
tl.to(uniforms.iTime, { value: duration, duration, ease: 'none' }) - 对于每帧逻辑(InstancedMesh 更新、相机计算),使用补间的
onUpdate回调
禁止做
- 函数字符串中禁止使用
${}模板字面量——它们会在编译时求值。请使用字符串连接。 - 禁止使用转义的反引号——将着色器编写为内联字符串,或使用单行字符串连接。
- 绝对不要在单个补间上使用
repeat: -1——循环由播放器处理;这会破坏持续时间跟踪。 - 禁止使用 CSS 风格的
style对象或元素上的textContent——元素是 WebGL 平面。 - 禁止外部导入——所有内容都在
ctx上(THREE、gsap、加载器、工具)。 - 禁止使用
requestAnimationFrame或setTimeout——请使用onUpdate回调。 - 禁止在帧路径中使用
Date.now()/Math.random()——确定性的合约;一切从时间线的时间和ctx.data推导。 - 不要在新配置中使用
onFrame——将所有每帧逻辑放在onUpdate中。
参数与外观(使其可混搭)
通过 config.params 声明 2–4 个旋钮——编辑器将其渲染为实时控件,其他代理可以在不触及代码的情况下重新调整程序。每个参数都记录了程序读取的 ctx.data 键:
"params": [{ "key": "hue", "label": "色调", "kind": "number",
"min": 0, "max": 1, "default": 0.6,
"hint": "围绕色轮移动所有颜色",
"unit": "°", "group": "颜色", "order": 1 }]
- 种类:
number(min/max/step)|color|select(options)|toggle hint:用一句话说明其可见变化——请务必编写- 程序在动画位置读取它:
const d = ctx.data || {}; if (typeof d.hue === 'number') u.uHue.value = d.hue - 按意图命名旋钮(
mood、drama、pace),绝不按实现命名(blurRadius)。每个旋钮必须能够在输出上产生可见变化——一个无效的旋钮比没有旋钮更糟。
通过 config.presets 提供外观——当程序有 4 个以上参数时,提供 2–3 个带名称的参数值集合:
"presets": [{ "name": "鲜艳", "values": { "hue": 0.9, "speed": 2 } },
{ "name": "平静", "values": { "hue": 0.3, "speed": 0.6 } }]
值必须引用已声明的参数键,并且类型匹配。
服务端渲染注意事项
上传到 vos.so 的配置会在一个软件 GL 集群上进行预览渲染:不要对透射材质使用 THREE.DoubleSide(会导致严重挂起),不要使用 dispersion(太慢),并且任何获取的资源必须可访问且 CORS 开放。这些对于在真实 GPU 上进行的纯本地渲染来说没有问题。
设计原则
- 视觉冲击:使用 bloom 产生辉光效果(即使 0.3–0.5 也能提升质感);自发光材质 + bloom = 发光器;exp2 雾效(0.01–0.05)增加深度;深色背景使色彩更突出;玻璃效果(透射 + HDR 环境贴图)显得高级;微妙的相机晃动增添活力。
- 动画质量:4–10 秒循环,10–30 秒叙事;
ease: 'none'用于恒定运动;power2.inOut/sine.inOut用于过渡;stagger 用于顺序揭示;在不同起始时间分层补间。 - 色彩:最多 2–3 种互补色;暖色调主色 + 冷色调边缘光;深色背景(
0x0a0a1a、0x1a1a2e)。 - 性能:10 个以上相同对象使用
InstancedMesh;Points 使用 5k–20k,InstancedMesh 使用 100–500;销毁所有内容。
分类选择指南
| 概念 | 相机 | 技术 |
|---|---|---|
| 着色器艺术 / 分形 | fullscreen | ShaderMaterial + uniform 补间 |
| 3D 对象 | perspective | Mesh + Material + lights |
| 等距/扁平 | orthographic | InstancedMesh + 计算位置 |
| 文字展示 | perspective 或 fullscreen | TextGeometry (3D) 或 elements (2D) |
| 玻璃/折射 | perspective | MeshPhysicalMaterial + HDR 环境贴图 |
| 粒子系统 | perspective | Points + 着色器 或 InstancedMesh |
| 混合媒体 | perspective | 3D 场景 + elements 数组 |