GNM/GDK、前向+、虚拟几何、GI、ECS、MIR 等术语,以及 WebGL2 扩展的真相

00 · 概念手册

这份文档是给"术语陌生但工程经验充足"的人看的。每个概念回答四件事: 它是什么 → 为什么需要它 → 拿什么类比 → 在 MagicEngine 里落在哪一层。 最后一节修正一个常见的技术前提错误。


1. GNM / GNMX / GDK —— 主机平台的"私房 API"

是什么

名称 归属 是什么
GNM PlayStation 4 / 5 索尼的低层图形 API。显式、直接写命令缓冲、几乎无驱动开销,风格接近 Vulkan 但更贴近硬件
GNMX PlayStation 4 / 5 GNM 之上的高层封装。帮你处理常见模式,手感接近 D3D12 / Vulkan,多数 PS 游戏用它
GDK Xbox Game Development Kit,Xbox 的开发套件(不只是图形 API)。图形部分就是 D3D12 + Xbox 扩展
NVN Nintendo Switch 任天堂基于 NVIDIA 的定制低层 API

为什么需要它

主机是固定硬件:每台 PS5 的 CPU/GPU/SSD 完全一致。这意味着性能是确定可预测的——你 profile 一次,结果对所有人成立。代价是:不能靠"玩家升级显卡"来救,必须把每一字节内存、每一毫秒都算准。

所以主机的 API 设计哲学是"把控制权全部交给你,把责任也全部交给你"。GNM 就是这么来的:draw call 极其便宜,但你要自己管内存别名、同步、资源屏障。

类比

在 MagicEngine 里的位置

L3 RHI 的后端之一。 但这些 SDK 全是 C++、且受 NDA 保护,所以:

常见误解

"支持主机 = 加个编译目标"

错。 主机支持 ≈ 重写一个渲染后端 + 重做平台服务(存档/网络/成就/手柄)+ 通过认证(索尼 TRC / Xbox TCR / 任天堂 Lotcheck,100+ 项技术要求,每补丁都要重新过)。第一次做,3–6 个月很正常,且几乎必然反复失败。


2. 前向+(Forward+ / Clustered Forward)—— 用"分格子"解决多光源

是什么

它是前向渲染(Forward)的改良版。三代演进:

方案 做法 问题
Forward 每个物体画一遍,画的时候把所有光源都算一遍 光源一多就爆炸(N 物体 × M 光源)
Deferred 先把几何信息写进 G-Buffer(法线/材质/深度),再对每个像素统一算光照 带宽大;透明物体没法用;移动端 TBDR 上极贵
Forward+ 先把屏幕切成小格子(cluster),每个格子只记录"影响我的少数几盏灯",然后每个物体画的时候只算这几盏 兼顾前向的简单 + 支持大量光源

为什么需要它

移动 GPU 几乎全是 TBDR(Tile-Based Deferred Rendering:Apple / Mali / Adreno / PowerVR)。

TBDR 的特点:把屏幕分 tile,在片上内存里完成渲染,最后一次性写回主存。好处是省带宽;坏处是每多一个渲染目标(RT),就多一次 tile 内存往返。

Deferred 需要 3–4 个 G-Buffer RT → 在 TBDR 上是灾难。所以移动端必须前向。

但纯前向撑不住"几百盏灯"(现代游戏需要大量局部光源)。Forward+ 用 cluster 把光源分配问题变成"每格子查表",成本可控。

类比

一个大厅里有 200 盏灯,你要给每个客人化妆:

在 MagicEngine 里的位置

L4 Renderer 的主管线,Tier0–Tier2 使用。Tier3/4 走 Visibility Buffer + Deferred Material。

实现要点:cluster 构建在 WebGL2(无 compute)上要退化——静态光源用预烘焙 cluster 表,动态光走 uniform 数组。这条写进 02-rendering.md 的 §8。

常见误解

"Forward+ 就是 Forward 加了点优化"

不完全。它改变了复杂度模型:Forward 是 O(物体 × 光源),Forward+ 是 O(物体 × 该物体所在格子的光源)。光源数量从"乘数"变成"局部常量",这是质变。


3. 虚拟几何(Virtual Geometry)—— 让美术不用做 LOD

是什么

一套自动管理几何细节层级的系统。核心思想:

  1. 把高模切成固定大小的小块(cluster,常见 128 三角面)
  2. 给 cluster 建一棵层级 DAG(不是简单的树,允许复用)
  3. 运行时根据"这个 cluster 在屏幕上占多少像素"决定用哪一级
  4. 只渲染刚好够用的细节

UE5 的 Nanite 是这套思路最著名的实现。

为什么需要它

传统流程里,一个高模要美术手工做 4–6 级 LOD(高/中/低/更低/远景),还要处理 LOD 切换的接缝、阴影 LOD、碰撞 LOD。这是巨大的、纯人力成本。

虚拟几何把这件工序消灭了:美术只交一份高模,剩下全自动。

这才是它真正的价值。不是画质更高,是省掉了人的工作。 这也是 MagicEngine 判断"新技术必须有工序价值"的典型案例。

类比

一张 8K 全景照片:

区别在于:照片是 2D 的 mipmap,虚拟几何是 3D 空间里的层级细分 + 遮挡剔除,复杂得多。

在 MagicEngine 里的位置

L4 Renderer 的几何子系统,P2 才做。分三步走(见 ADR-004 附录):

  1. 编译期生成 cluster LOD 链 + CPU 选择(Tier1/2)
  2. compute 软件光栅到 visibility buffer(Tier2/3)
  3. mesh shader 路径 + 完整 DAG(Tier3/4)

常见误解

"有了虚拟几何就不需要优化面数了"

错。 Nanite 降低的是"几何细节的成本",但付出了:内存占用更高、固定开销(culling 与光栅化)更大、不支持骨骼蒙皮(角色还是传统管线)、半透明不支持。

所以它是"静态环境的解决方案",不是"所有几何"的解决方案。


4. GI(Global Illumination,全局光照)—— 让光"反弹"

是什么

直接光 = 光源直接照到表面。 间接光 = 光照到墙,墙再照亮旁边的地板和天花板。

GI 就是把间接光也算进去。真实世界里,一个房间有 80% 的亮度来自反弹光。

为什么需要它

没有 GI 的画面,会呈现典型的"游戏感":

三代技术

方案 原理 代价 用在哪
光照贴图(Lightmap) 离线算好,烘成纹理贴到表面 静态、不能动、占内存 小游戏、移动端
光照探针(Light Probe / SH) 在空间里撒探针,存环境光的方向分布 精度低、有漏光 动态物体
DDGI(动态漫反射 GI) 探针实时更新,用射线/距离场更新探针 需要 compute 移动高端 / PC
硬件光追 GI 真射线追踪 需要 RT 硬件 PC / 主机

类比

手电筒照墙:

烘焙 = 提前把"这个房间白天/晚上各长什么样"拍照存下来,运行时贴上去。 实时 GI = 每次移动光源都重新算一遍。

在 MagicEngine 里的位置

L4 Renderer 的光照子系统,按 Tier 分级:

关键设计:Tier0 只有烘焙,但要让玩家"感觉是动态的"——用 SH 探针给角色补环境光、关键场景烘多套光照按时间切换。


5. 角色栈(Character Stack)—— 写实的胜负手

是什么

不是"一个 shader",而是一整套专为角色(人和动物)设计的渲染子系统:

子模块 解决什么 关键技术
皮肤 肉感、透光、油光 预积分 SSS、双层高光、曲率图
毛发 真实感的最大来源 Strand(发丝)/ Shell(壳层)/ Card(卡片)三档
眼睛 "活不活"的一半 角膜折射层 + 巩膜 + 虹膜视差 + 微扫视
布料 褶皱与垂坠 XPBD 模拟 / 预烘焙骨骼
面部 表情不"橡皮" FACS blendshape + 皱纹法线混合

为什么需要它

一个场景里的建筑、地形、道具,现代管线已经能做得很像。一眼让人看出"这是游戏"的,永远是角色:

所以角色必须单独一套管线,不能混在通用 PBR 材质里。UE 的 "MetaHuman" 就是这条路线的极致。

类比

画人像 vs 画风景:

风景可以靠构图和光影"糊"过去;人像只要眼睛和皮肤有一点不对,整张画就废了。角色渲染就是"人像",需要专门的技法。

在 MagicEngine 里的位置

L4 Renderer 的独立子系统,P2 才做。02-rendering.md §7 有完整的预算表。

常见误解

"角色就是蒙皮模型 + PBR 材质"

如果你的目标是"卡通/风格化",这话基本对。如果目标是"写实",这句话会让你在 P2 阶段推倒重来。


6. ECS(Entity-Component-System)—— 数据导向的组织方式

是什么

把游戏对象拆成三样东西:

概念 是什么 例子
Entity 一个 ID(就是个数字) #1024
Component 纯数据,无逻辑 Position{x,y,z}、Health{hp}
System 纯逻辑,处理"拥有某组组件的所有实体" MoveSystem:遍历所有有 Position+Velocity 的实体

为什么需要它

传统 OOP 是"每个对象一个类,类里既有数据又有方法":

Player 对象 { x, y, hp, 贴图, 音效, AI逻辑, 网络同步... }   ← 一个巨大的对象
Enemy  对象 { x, y, hp, 贴图, 音效, AI逻辑, 网络同步... }   ← 大量重复

问题:

  1. 内存不连续:遍历 10000 个敌人,内存跳来跳去,CPU 缓存全废
  2. 继承地狱:想做个"会飞的敌人",只能多重继承或复制粘贴
  3. 无法并行:逻辑和数据混在一起,没法安全地多线程

ECS 的做法:按组件类型分数组,同类数据在内存里连续排列。

Positions:  [x1,y1,z1, x2,y2,z2, x3,y3,z3, ...]   ← 连续!CPU 缓存命中率高
Velocities: [vx1,vy1,vz1, vx2,vy2,vz2, ...]

遍历时是"扫一遍数组",比"追 10000 个指针"快一个数量级。

类比

在 MagicEngine 里的位置

L5 Runtime 的世界模型。但有个细节:ECS 本身不支持"父子层级"(场景树),而编辑器需要。

解决方案:ECS 之上单独维护一份 HierarchyIndex(父子关系是稀疏数据,不放进 archetype)。这是 Unity DOTS 和 Bevy 都踩过的坑。


7. 流式加载(Streaming)—— 边玩边下

是什么

不把整个游戏一次性加载进内存,而是按需、渐进地加载:玩家走到哪,加载到哪;看不清的,先放低清版本。

三种粒度:

粒度 场景
分包流式 小游戏:主包 4MB 先跑起来,其他包按需下载
资产流式 大世界:按玩家位置加载周边地形/贴图
渐进式精化 先给低模/低清,再异步换成高模/高清

为什么需要它

两个硬约束:

  1. 小游戏主包 4MB:装不下任何像样的资产
  2. 大世界:几百 GB 的内容不可能全进内存

类比

渐进式精化 = 先看 480p,网络好了自动换 4K,你几乎察觉不到。

在 MagicEngine 里的位置

L5 Runtime 的 Streaming 子系统。小游戏的策略写在 01-architecture.md §5.3:

  1. 主包只含引擎最小运行时 + 首场景 MIR + 占位资产
  2. 进场景后立刻预下载相邻分包(wx.preDownloadSubpackage)
  3. 高模/高清贴图按视距与重要性替换
  4. 利用平台缓存(微信 IAA 可申请 1GB)

关键指标:首帧 <3 秒。 这是小游戏留存的生死线。


8. 预算注解(Budget Annotation)—— MagicEngine 的核心创新

是什么

在 MIR 的每个节点上,标一个"这个节点允许花多少资源"的显式声明:

node n_alley_wall : mesh.static {
  budget: { tri=8000, tex=2MB, draw=4, ms=1.2, mem=6MB }
}

不是"事后统计",而是节点的一等属性。

为什么需要它

传统引擎的性能优化流程是:

美术做完 → 打包 → 上真机 → 掉帧 → profile → 找到问题 → 反推是哪个资产 → 让美术改

这条路的问题:反馈延迟是"天"级,而且问题定位靠人。

有了预算注解,流程变成:

生成/导入时就知道预算 → 超了立刻报错(编译期) → AI 可以局部重算

三个直接收益:

  1. 定位精确:报错是"节点 n_alley_wall 超预算 240%",不是"场景掉帧"
  2. 可协商:Planner 可以在节点间"借贷"预算(从余量池借),借贷必须编译期归零
  3. AI 可优化:优化目标从"让它更快"(模糊)变成"把这 3 个节点压到预算内"(明确)

类比

装修预算表:

预算注解就是给每个 MIR 节点发一张"预算表"。

在 MagicEngine 里的位置

L6 MIR 的属性 + 编译链的 budget pass + CI 的硬门禁。


9. MIR(Magic Intermediate Representation)—— 引擎的"源码"

是什么

游戏内容的中间表示。不是二进制资产,而是带类型、带预算、带溯源的结构化图。

四类图,共用一套机制:

图 表达什么
SceneGraph 场景层级、变换、组件挂载
MaterialGraph 材质节点图(分层 PBR)
AnimGraph 状态机、混合树、Motion Matching 配置
BehaviorGraph 游戏逻辑(可编译为 WASM)

为什么需要它

因为AI 需要一个能被精确读写、能被机器验证的中间层。

对比三种资产形态:

形态 AI 能改吗 能 diff 吗 能验证吗
二进制资产(.uasset) 只能猜 ✗ ✗
纯 JSON(Cocos prefab) 能改,但容易破坏引用 ✓ 需要额外写
MIR 能精确改(有 schema) ✓(稳定排序) ✓(内置校验)

MIR 不是为人类设计的,是为 Agent 设计的。 这是它和"序列化格式"的根本区别。

类比

编译链 = 施工队。图纸通过审核(硬校验)才能开工。

在 MagicEngine 里的位置

L6,全局枢纽。运行时不接受绕过 MIR 的资产直读。这条是架构宪法第 2 条。

AI 只能通过 mir.query / patch / measure 三个接口碰它。


10. 硬校验(Hard Validation)—— 门禁,不是建议

是什么

由确定性代码(不是 LLM)执行的、不通过就阻断编译的检查。

在 MagicEngine 里由 Guardian 角色执行,检查项包括:

检查项 例子
预算 三角面/纹理/内存/draw call 超限
引用完整性 材质引用了不存在的贴图
变体数 单个材质族编译出 40 个变体(上限 32)
几何合法性 碰撞体未闭合、法线反向
包体约束 主包 4.1MB(上限 4MB)
确定性 同 seed 两次构建产物不一致

为什么需要它

因为 LLM 会幻觉,且在"看起来对"和"确实对"之间没有可靠界限。

如果让 LLM 判断"这个模型能不能用",它会说"看起来不错"。然后你上线,玩家撞进了墙里。

所以架构上的分工是铁律:

类比

两者不能混。

在 MagicEngine 里的位置

L7 Agent Runtime 的 Guardian 角色 + 编译链的门禁。

设计原则(04-toolchain-platform.md §8):所有能在编译期发现的问题,绝不留给运行期。 编译失败比线上闪退便宜 1000 倍。


11. 修正一个技术前提:WebGL2 到底有什么扩展

你提到"需要额外开启 EXT_color_buffer_float / WebGL2 Compute 扩展"。这两件事必须分开说,因为一个是真的,一个已经死了。

11.1 EXT_color_buffer_float —— 真实存在,非常重要

配套的还有几个,引擎必须逐项探测:

扩展 作用 缺了会怎样
EXT_color_buffer_float 浮点渲染目标 无法做 HDR 后处理链
OES_texture_float_linear 浮点纹理线性过滤 浮点纹理采样变块状
EXT_float_blend 浮点缓冲混合 部分粒子/透明效果失效
WEBGL_compressed_texture_astc ASTC 纹理压缩 包体暴涨(移动端最关键)
WEBGL_compressed_texture_etc ETC2 纹理压缩 同上(Android 通用)
KHR_parallel_shader_compile 异步编译 shader 首次进入卡顿

WEBGL_compressed_texture_astc 是小游戏包体的命门。 没有纹理压缩,4MB 主包里塞不下几张图。

11.2 "WebGL2 Compute 扩展" —— 这条不存在,别再指望

这是必须纠正的重点:

事实 依据
WebGL 2.0 Compute 只是一个编辑草案(Editor's Draft,2021-03-31) Khronos 官方规范页
官方明确写:"this specification should be considered obsolete" 同上
原因:Khronos 决定停止扩展 WebGL API,把 compute 能力交给 WebGPU 同上
实际实现:只有 Chrome / Edge Insider 的实验性通道,从未推广 多方资料一致
标准 WebGL2 不支持 compute shader 规范本身

所以任何"在 WebGL2 上跑 compute shader"的设计都是空中楼阁。

WebGL2 里做 GPGPU 的正确姿势(如果真需要):

  1. transform feedback(WebGL2 原生)—— 顶点着色器输出写回 buffer,适合粒子
  2. fragment shader + 浮点 RT(需要 EXT_color_buffer_float)—— 把计算编码成"画一张图",结果读纹理
  3. 多个 RT(MRT,WebGL2 原生)—— 一次输出多个结果

这些能做的事远少于真 compute(没有 shared memory、没有原子操作、没有 work group 同步),所以不要按"有 compute"来设计渲染器。

11.3 那微信小游戏 iOS 的 Metal 后端呢?

这是另一回事,也是好消息:

微信在 iOS 侧提供了原生 Metal 渲染后端(2025 年 Unite 大会公布)。它绕过 WebGL,直接走 Metal,因此可以用 Compute Shader、Indirect 调用、PSO、UAV。官方数据:执行效率 +10%,功耗 −15%。

这意味着:

同一款游戏在两个平台要用两份不同的编译结果。 这就是为什么 MagicEngine 的能力分级必须按"后端能力"而不是"平台名"——这条写进了 ADR-004。

11.4 结论(给架构的三条硬规则)

  1. 永远不设计依赖 WebGL2 compute 的方案。 它不存在,也不会存在。
  2. EXT_color_buffer_float 等扩展必须运行时探测 + 分级降级,不能假设。
  3. RHI 接口第一件事就是 capability_query(),返回一张能力表,渲染器据此选择预编译好的路径(不是运行期 if)。

12. 能不能超越 Cocos / Laya?

先说结论,再说依据。

结论

维度 判断
1–2 年内全面超越 不可能,也不该作为目标
单点超越(AI 内容生产效率) 可能,P0 就能验证
结构性超越(跨端到主机 / 写实角色) 架构上成立,但要 3 年
生态、稳定性、包体极限 短期必然落后,靠时间补

可以超越的地方(三条,都是结构性的)

① AI 内容生成的"可验证性"

Cocos / Laya 的 AI 是外挂式:对话给建议,人手动落地。MagicEngine 的 AI 产出 MIR diff,经硬校验、可 review、可回滚、可复现。

差别不在"AI 强不强",而在AI 的产出能不能被工程化管理。这是架构差异,不是功能差异。

② 跨端上限(到主机)

Cocos / Laya 没有 PS5 / Xbox 后端,也没有这个计划——因为它们的抽象层次(JS/TS 运行时)撑不到主机级性能。这不是努力问题,是架构天花板。

MagicEngine 的 RHI 从第一天就按"多后端 + C ABI"设计,主机是"还没实现",不是"实现不了"。

③ 写实角色的渲染上限

Cocos 的 3D 管线做不了 SSS 皮肤 / 发丝 / 角膜折射那一套。如果你的目标里真有"渲染真实的人物、动物",这是一条硬需求,而 Cocos 满足不了。

不能超越的地方(也要认清)

① 包体极限优化

Cocos 在小游戏包体上积累了多年(引擎裁剪、资源压缩、代码分包),P0 阶段我们大概率做不过它。这是经验问题,只能用真实项目喂出来。

② 微信生态适配深度

Cocos 与微信有官方级合作,新能力(如 Metal 后端、GLX 模式)往往第一时间适配。我们要自己追。

③ 生态与人才池

Cocos 有插件市场、教程、社区、招聘池、免费开源。这些是"网络效应",新引擎从 0 开始,这块基本是 0 分。

④ 稳定性

Cocos 被几万个项目踩过。我们的 P0 版本一定有一堆边界 bug。这是必经之路,不能靠架构设计跳过。

一个必须承认的事实

Cocos Creator 的 .prefab / .scene 本来就是 JSON,可 diff。所以"资产可 diff"不是我们的独占优势——这一点我上一版文档里说得过重了,这里修正。

我们真正的差异是三条:预算注解 + AI 精确编辑 MIR + 编译期跨端。前两条 Cocos 没有,第三条它做不到。

所以战略上应该怎么定位

不做"另一个 Cocos",做"AI 时代的另一种生产方式"。

具体来说:

最危险的做法是:还没证明效率优势,就先按"通用引擎产品"来做。 那会同时输掉技术和商业。

一句话定位、三条信念、明确不做什么、成功标准

MagicEngine / 悦居魔法引擎

AI-native game engine。从第一行代码开始,AI 就是编译链的一等公民,而不是编辑器里的一个对话框。

项 值
版本 v0.1 — 架构基线(未实现)
状态 Proposed 待评审;音频子系统 SfxForge 已可运行
代号 MagicEngine(ME)
主体 北京悦居智能科技中心
日期 2026-10-22

1. 一句话定位

一个预算感知(budget-aware)的跨端游戏引擎:

游戏内容以可读、可验证、可复现的中间表示(MIR)存在; 由 AI Agent 生成与优化; 由编译链按目标平台预算编译为可执行包。

不是"3D 引擎加个 AI 助手",而是"把游戏当作可编译程序的产物"。


2. 我们相信的三件事

① 引擎的瓶颈不是画质算法,是内容成本。 Nanite 之所以改变行业,不是因为它的光栅化算法更优雅,而是因为它消灭了 LOD 制作这道人力工序。任何一项新技术如果不削减人的工作量,就进不了生产管线。AI 的价值同理——它必须削减工序,而不是增加一个"要点一下"的按钮。

② AI 必须进编译链,不能只做面板。 Cocos / Unity / Unreal 都在加 AI,路径都是"引擎外部挂一个 Copilot"。这条路的天花板是人的手速:AI 给建议,人手动落地。我们的路径是 AI 直接产 MIR 变换(diff),由 Validator 硬校验、由编译器落盘。人只做 review,不做搬运。

③ 跨端不是"导出按钮",是编译目标。 同一份 MIR,编译到 WebGL2 与编译到 PS5,差别不在"打包方式",而在预算差 4 个数量级(每帧三角面 5 万 vs 2000 万)。所以平台差异必须在类型系统里表达,而不是在运行时用 #ifdef 兜。


3. 不做什么(与做什么同等重要)

架构的第一性工作是划边界。以下为明确非目标,违反即架构失控:

非目标 原因
5 年内在"写实画质"上超过 UE5 UE5 有 20 年、数千人年积累与 Quixel 资产库。正面硬刚必输,必须换赛道
全平台同步交付 主机 SDK 有资质门槛(NDA/审核),且工作量为小游戏的 20 倍以上
自研物理引擎 刚体/约束求解是 30 年成熟领域,集成 Jolt 即可;自研只做"游戏性特化层"
自研音频中间件 集成 Wwise / FMOD;小游戏端自研轻量混音器。注意区分:自研的是音效合成(SfxForge,见 07),不是混音总线/3D 引擎
自研视频编解码 用平台原生
支持 30 种平台 每个平台的测试矩阵成本是超线性的
做通用低代码/无代码平台 与"面向 3A"直接冲突,会毁掉引擎的表达力上限

4. 差异化:三条护城河

4.1 AI Bake —— 解决"小游戏端零 AI 算力"

小游戏跑在 WASM + WebGL2 上,没有 NPU、没有 CUDA、单线程为主。任何"运行时跑模型"的方案在这里都不成立。

ME 的机制:工具期用大模型生成,运行期只消费烘焙产物。 AI 的产出被编译成确定性的数据(光照探针、导航网格、LOD 层级、材质参数、动画片段),烘焙进包或 CDN 分包。运行时零推理开销。

这让"AI 引擎"第一次能跑在 4MB 主包里。

4.2 MIR —— 带预算的中间表示

MIR(Magic Intermediate Representation)之于游戏引擎,如同 MLIR 之于编译器。

4.3 Performance Contract —— 性能契约

游戏在项目设置里声明目标:微信 iOS / 低端机 / 30fps / 峰值内存 600MB。 引擎把这条契约编译成每个资源的预算分配,并在 CI 里持续验证。 不达标时 Perf Agent 自动产出降级方案(MIR diff),人 review 后合入。

性能从"上线前救火"变成"每次提交的断言"。


5. 成功标准(可证伪)

引擎项目最容易死在"永远差半年"。所以定义可证伪的里程碑:

阶段 可证伪标准
P0 1 款真实上线微信小游戏,主包 ≤4MB,低端安卓 30fps 稳定,全程未手写 shader
P1 该游戏 3D 版本上线微信+抖音双端;AI 生成的关卡占比 >50% 且通过 review
P2 同一份 MIR 编译出 PC 与主机包,画质差距 ≤1 档;外部团队能用它做出第 2 款游戏
P3 有第 3 方团队付费使用;单项目美术工时相比 Unity 路线下降 ≥30%(可测量)

关键判据:引擎只有被 ≥3 个项目复用才可能回本。 所以 P0 就必须用真实商业项目喂,不能做"先做引擎再做游戏"。


6. 文档地图

文档 内容
01-architecture.md 分层架构、MIR 设计、依赖规则、编译链
02-rendering.md 渲染分级、能力矩阵、"逼真+性能"的技术拆解
03-ai-kernel.md ★ AI 内核:Agent 拓扑、预算感知生成、确定性
04-toolchain-platform.md 工具链、平台矩阵与降级策略
05-roadmap.md 分期路线、组织、成本、风险登记册
06-asset-intelligence.md 资产复用梯度、世界语法、构件化生成、规范化闸门、冷启动
07-audio.md ★ 音频与音效:AI 生成配方而非波形、七项硬校验、声学体检、场景音景闭环
08-audio-gen.md ★ 生成式音频选型:11 个后端许可核验、可调用性实测、三档选型、三分区架构
09-development-plan.md ★ 开发总计划:P0–P3 路线、六个里程碑 DoD、WBS 与工时、关键路径、三种降级方案
10-p0-sprint-plan.md ★ P0 迭代执行计划:13 个双周迭代的任务/人日/DoD,前 10 个工作日排班
11-parallel-agents.md ★ 四 Agent 并行开发:四类冲突、扇区模型、crate 内分权、共享面设计、并发度曲线、同步协议
plan/agents.json 扇区定义(机读唯一事实源)+ 4 份 Agent 启动简报
interface/ 契约目录:MANIFEST.json 登记版本与哈希,冻结后改动必须 bump
tools/ci/check_ownership.py 越界守卫:files / contracts / dupes 三个检查
plan/gantt.html 可交互甘特图(数据源 plan/p0-plan.json,改排期只改 JSON)
adr/ 架构决策记录(6 份关键决策)

7. 当前未决问题(Open Questions)

  1. 内核语言最终定 Rust 还是 C++ —— 见 ADR-001,已提前到 P0 第 2 周(S0 的 D0 门)做 FFI 冒烟测试后定论
  2. 主机资质路径(PS5 对国内中小团队的实际审批周期)
  3. 自研超分 vs 集成 FSR/XeSS 的取舍(授权与主机认证问题)
  4. ~~MIR 的文本语法最终形态(是否采用 S-expression)~~ → 已定:块语法 + 稳定属性顺序,不用 S-expression(理由见 10 号文档 S1)
  5. 商业模型:自用 / 授权 / 开源核心 —— 影响架构的开放性设计

八层结构、依赖宪法、MIR 设计、七段编译链

01 · 总体架构

1. 设计约束(先约束,再方案)

编号 约束 对架构的硬性影响
C1 微信小游戏主包 4MB / 总包 30MB 内核必须极小;资产必须可远程分包;不能带完整引擎运行时
C2 小游戏 Android 侧仅 WebGL2(≈GLES3.0,无 Compute Shader) 渲染器必须有 Compute-free 路径,不能假设 compute 存在
C3 小游戏 iOS 侧已有原生 Metal 后端(compute / indirect / UAV 可用) 能力分级要看"后端能力",不能按"平台"分级
C4 小游戏 WASM 单线程为主,CPU 弱 主线程绝不做重计算;Job 系统要能退化到"时间切片"而非线程
C5 主机 SDK 仅 C++,且需资质 内核语言选择必须留下 C ABI 逃生口
C6 目标跨度:5 万三角面/帧 → 2000 万三角面/帧 差异必须在类型系统层表达,不能靠运行时分支
C7 引擎须被 ≥3 项目复用才回本 必须"游戏驱动",架构要允许局部裁剪

2. 分层架构

┌──────────────────────────────────────────────────────────────────────┐
│  L8  Magic Studio(编辑器 / 工具层)                                   │
│      场景编辑 · 材质图 · 动画图 · AI 工作台 · 性能工作台 · 资产库        │
├──────────────────────────────────────────────────────────────────────┤
│  L7  Agent Runtime(AI 内核)★                                        │
│      Intent → Planner → Generator → Validator → Optimizer            │
│      模型适配层:云 LLM / 本地小模型 / 烘焙缓存                         │
├──────────────────────────────────────────────────────────────────────┤
│  L6  MIR(Magic Intermediate Representation)★★ 全局枢纽              │
│      SceneGraph · MaterialGraph · AnimGraph · BehaviorGraph           │
│      + 预算注解 + provenance + 可 diff 文本格式                        │
├──────────────────────────────────────────────────────────────────────┤
│  L5  Runtime Subsystems(运行时子系统)                                │
│  World(ECS) │ Anim │ Physics │ Audio │ Script │ Net │ UI │ Streaming  │
├──────────────────────────────────────────────────────────────────────┤
│  L4  Renderer(Render Graph 驱动)                                     │
│  VirtualGeom │ GI │ Material │ Character │ PostFX │ Culling           │
├──────────────────────────────────────────────────────────────────────┤
│  L3  RHI(渲染硬件抽象,C ABI 边界)                                   │
│  WebGL2 │ WebGPU │ Metal │ Vulkan │ D3D12 │ GNM │ GNMX │ D3D12X       │
├──────────────────────────────────────────────────────────────────────┤
│  L2  PAL(平台抽象)                                                   │
│  FS · Thread · Time · Input · Net · Pay · Ads · Account · Storage     │
├──────────────────────────────────────────────────────────────────────┤
│  L1  Platforms                                                         │
│  微信/抖音小游戏(WASM) │ iOS │ Android │ Win │ macOS │ Linux │ PS5 │ Xbox │ Switch │
└──────────────────────────────────────────────────────────────────────┘

2.1 依赖规则(架构的"宪法")

  1. 只允许向下依赖。L5 不许 import L7;L4 不许知道 L8 存在。
  2. L6 是唯一真相源。运行时不接受任何"绕过 MIR 的资产直读"。这条保证了 AI 可介入性——凡是不能表达为 MIR 的东西,AI 就碰不到,也就无法优化。
  3. L3 边界必须是 C ABI。理由见 ADR-001:内核语言可能变,RHI 后端几乎必然是 C++(贴 SDK)。C ABI 是唯一稳定契约。
  4. L2 之上禁止出现 #if PLATFORM。平台差异收敛为 PAL 的接口实现 + MIR 的 target 注解。允许的例外只有构建脚本。
  5. L7 不许直接改文件。Agent 只能产出 MIR diff 或 recipe,落盘由编译链统一执行(保证可审计、可回滚)。

违反第 4 条是最常见的死法:三年后代码里 3000 个 #ifdef,引擎就废了。


3. MIR:引擎的枢纽

3.1 为什么需要它

传统引擎的资产是"二进制 blob"(.uasset / .prefab / .meta)。问题:

MIR 把资产变成带类型的程序。

3.2 节点模型

每个 MIR 节点是一个类型化 Operator:

node <id> : <op-type> {
  inputs:  [ ... ]
  attrs:   { ... }
  budget:  { tri=12k, tex=4MB, draw=3, ms=0.8, mem=6MB }
  provenance: { by="agent:artisan", seed=0x9f2a, model="xxx@v3", at="2026-10-22T09:00Z" }
}

四类图(Graph),共用同一套节点/预算/溯源机制:

图 表达 主要消费者
SceneGraph 层级、变换、组件挂载 World / Renderer / Culling
MaterialGraph 材质节点图(PBR 分层) 着色器生成器
AnimGraph 状态机 + 混合树 + Motion Matching 配置 Anim 子系统
BehaviorGraph 游戏逻辑(可视化节点) Script 子系统(可编译为 WASM/原生)

3.3 文本与二进制双形态

两者由同一份 schema 生成,CI 强制校验往返一致性(mir → mirb → mir 必须字节级等义)。

3.4 预算注解是核心创新

预算不是"事后统计",而是节点的一等属性。这样:

对比:UE 的 Nanite 让几何"免预算",但代价是把成本转移到固定开销与内存。ME 的选择是显式预算 + 自动协商,因为小游戏端必须有硬上限。


4. 编译链

MIR 到可执行包,是一条标准的多 pass 编译流水线:

 .mir 文本
   │ ① parse        → AST
   │ ② legalize     → 目标平台能力合法化(如 compute → 伪 compute)
   │ ③ budget-pass  → 预算分配与协商(父子节点间借贷)
   │ ④ ai-pass      → ★ Agent 优化(可选,可多次迭代)
   │ ⑤ lower        → 平台特化 IR(着色器变体、资产编码、场景烘焙)
   │ ⑥ link         → 分包切分(4MB 主包约束)、资产寻址、依赖排序
   │ ⑦ pack         → 平台包(小游戏 zip / APK / IPA / 主机镜像)
   ▼
 发布产物

关键设计:


5. 运行时架构

5.1 World(ECS)

5.2 内存模型

三级:

级别 用途 小游戏策略
Frame Arena 每帧临时数据,帧末整体重置 固定大小,超限即报错(早失败优于 OOM)
Asset Heap MIR 编译产物,引用计数 + 句柄 按分包粒度整体卸载
Persistent 全局单例、配置 极小

小游戏端峰值内存目标是 iOS 低端机 <600MB(Unity 官方建议 <1GB 才不易闪退,我们取更保守值留余量)。

5.3 资产流式

小游戏的启动预算:首帧 <3 秒,主包 <4MB。策略:

  1. 主包只含:引擎最小运行时 + 首场景 MIR + 占位资产(低模 + 纯色材质)
  2. 首场景进入后立即预下载相邻分包(wx.preDownloadSubpackage)
  3. 高模/高清贴图按视距与重要性分优先级流式替换("渐进式精化")
  4. 缓存利用平台能力(微信 IAA 游戏可申请 1GB 缓存)

6. 代码组织(仓库形态)

magic-engine/
├── crates/
│   ├── me-core/         # 基础类型、数学、句柄、错误
│   ├── me-mir/          # MIR schema、解析、序列化、校验
│   ├── me-compiler/     # 编译链 7 个 pass
│   ├── me-runtime/      # L5 运行时(no_std 友好,可编 WASM)
│   ├── me-render/       # L4 渲染器
│   ├── me-rhi/          # L3 抽象 + 各后端(C ABI)
│   ├── me-pal/          # L2 平台抽象
│   ├── me-agent/        # L7 AI 内核
│   └── me-studio/       # L8 编辑器后端
├── backends/            # C++ 实现的 RHI 后端(Metal/Vulkan/D3D12/GNM)
├── studio-ui/           # 编辑器前端(TS + React)
└── samples/             # 垂直切片项目

若 ADR-001 最终选 C++,此结构不变,仅语言替换——这正是把 RHI 边界定在 C ABI 的收益。


7. 与成熟引擎的取舍对照

维度 Unreal Unity Cocos MagicEngine
资产格式 二进制 uasset,不可 diff YAML prefab + meta(可 diff 但冗长) JSON + 二进制 MIR(带预算/溯源,LLM 原生)
跨端方式 各平台独立后端 IL2CPP + WebGL 转换(有转换损耗) TS 原生 + 多后端 MIR 多目标编译(WASM 一等公民)
AI 定位 外部助手(Copilot) 外部助手 外部助手 编译链 pass + Agent 闭环
小游戏 转换方案,包体压力大 转换方案,需大量裁剪 原生优势 原生 WASM-first,预算编译
优化方式 人工 profile 人工 profile 人工 profile 性能契约 + Perf Agent 自动产 diff
学习曲线 极陡 中 平缓 取决于 AI 生成质量(风险点)

我们的赌注:AI 让"引擎复杂度"对开发者的暴露面大幅下降。UE 难学是因为要人理解它的抽象;如果 Agent 能正确产出 MIR,人只需要 review。这个赌注如果成立,复杂度就是护城河;如果不成立,复杂度就是负债。这是全项目最大的单点风险,见 05-roadmap 风险 R1。

逼真的六个维度、Tier0-4 能力矩阵、角色栈、Compute-free 路径

02 · 渲染架构

目标原话:"渲染既要逼真,又要性能好,可以渲染真实的世界和人物、动物。"

先把这句话拆开,否则无法工程化。


1. "逼真"的六个维度(拆解)

"看起来真"不是一个指标,是六个正交维度。每个维度的技术手段与成本完全不同,必须分开预算,否则优化会打空。

# 维度 人眼敏感度 关键技术 成本量级
V1 几何保真 中 微多边形/置换、扫描资产、虚拟几何 高(内存)
V2 光照保真 高 多次反弹 GI、能量守恒、体积介质 极高(算力)
V3 材质保真 高 多层 BRDF(清漆/布料/皮肤)、各向异性、吸收散射 中(shader 复杂度)
V4 动态保真 高 毛发、布料、软体、破碎 高(模拟)
V5 时序保真 极高 TAA、超分、去噪、抗闪 低(后处理)
V6 感知保真 极高 物理相机、景深、运动模糊、色调映射、镜头特性 低

核心判断 1:V5/V6 的性价比远高于 V1/V2

人眼对闪烁、抖动、噪点、锯齿的容忍度极低,对"光线反弹了几次"几乎无感。所以:

预算分配顺序:V5 → V6 → V3 → V4 → V1 → V2

这解释了为什么"一个稳定的 30fps 移动游戏"看起来比"一个抖动的 60fps 高模场景"更专业。也解释了为什么 TAA/超分必须在 P1 就做完,不能留到最后。

核心判断 2:写实的真正门槛是"人物与动物"

真实世界的建筑/地形,现代管线已经能做得很好。真正让人一眼看出"这是游戏"的,是角色:皮肤的次表面感、毛发的透光、眼睛的高光形状、布料褶皱。所以渲染架构里 Character Stack 是一个独立的一等子系统,不混在通用材质里。


2. 能力分级矩阵

分级依据是后端能力,不是平台名(因为微信 iOS 已有原生 Metal:compute/indirect/UAV 可用;而 Android 仍是 WebGL2:无 compute)。

能力 Tier0
WebGL2
Tier1
小游戏+Metal
Tier2
移动原生
Tier3
PC
Tier4
主机
Compute Shader ✗ ✓ ✓ ✓ ✓
Indirect Draw ✗ ✓ ✓ ✓ ✓
Mesh Shader ✗ ✗ ✗ ✓(部分) ✗(GCN)
✓(RDNA)
硬件光追 ✗ ✗ ✗ ✓ ✓
稀疏纹理 / 虚拟纹理 ✗ ✗ ✓ ✓ ✓
目标分辨率 720–1080p 1080p 1080–1440p 1440p–4K 4K
三角面/帧 5 万 30 万 100 万 1000 万+ 3000 万+
Draw call/帧 <100 <400 <1000 动态 动态
帧率 30 30–60 30–60 60–120 60
峰值内存 400MB 600MB 1.5GB 8GB 12GB

面数不是靠"优化"从 5 万堆到 3000 万,而是靠完全不同的几何管线。这就是为什么"一份内容全平台跑"必须靠 MIR 编译期的 legalize pass 做形态转换,而不是运行期 LOD 切换。


3. 渲染管线选型

3.1 移动端必须 Forward+

移动 GPU 绝大多数是 TBDR(Tile-Based Deferred Rendering:Apple / Mali / Adreno / PowerVR)。TBDR 的片上 tile memory 让"多 pass 全屏写 G-Buffer"极其昂贵(每多一个 RT 就多一次 tile 内存往返 + 带宽)。

所以:

目标 管线 理由
Tier0/1/2 Clustered Forward+ 单 pass、MSAA 友好、带宽可控;用 light cluster 支持多光源
Tier3/4 Visibility Buffer → Deferred Material 虚拟几何天然产 vis-buffer(只存 triangleID+depth),material resolve 延后,带宽最优

两条管线共享同一个 Render Graph 描述层,差异由 legalize pass 决定,不是两套代码。

3.2 Render Graph

所有 pass 不直接绑定资源,而是声明"读/写哪个虚拟资源",由 Graph 编译器做:

这是现代渲染器的标配(Frostbite FrameGraph / UE RDG),但从 0 做的好处是可以把预算直接建进去:每个 pass 声明 ms_budget,Graph 编译时报"总预算超支 X%"。


4. 几何:Virtual Geometry

目标:让美术不用做 LOD(这是 Nanite 的真正价值,不是画质)。

4.1 两种实现路径

路径 前提 做法
A. Mesh Shader 路径(Tier3/4) mesh shader 可用 cluster 层级 culling 在 task shader 里做,直接输出 micro-triangle
B. 软件光栅路径(Tier1/2) compute 可用 compute 做 cluster cull + 软件光栅到 vis-buffer,硬件光栅只处理"边缘像素"
C. 预烘焙 LOD 链(Tier0) 无 compute 编译期离线生成 4–6 级 cluster LOD,运行时按视距/屏幕占比选级

关键:A/B/C 是同一个 MIR 几何源的三种 lower 结果。美术只交一份高模。

4.2 数据布局

4.3 Tier0 的现实妥协

WebGL2 没有 compute、没有 indirect,所以"GPU driven"在小游戏低端机上不成立。妥协方案:

这是硬边界,不要幻想在 4MB 主包里跑 Nanite。


5. 光照:三级 GI

Tier 方案 说明
Tier0 Lightmap(烘焙)+ SH 探针 完全离线。AI 在工具期生成光照并烘焙
Tier1/2 SDF-DDGI + 反射探针 动态物体有间接光,代价可控(DDGI 需要 compute/纹理反馈)
Tier3/4 HWRT-DDGI + 屏幕空间反射 + 体积雾 硬件光追做次级光追与反射

关键判断:Tier0 的 GI 必须"看起来是动态的"

小游戏端只能烘焙,但玩家会看到"角色走过墙边没有颜色渗透"而觉得假。解决: - 角色用 SH 探针采样环境光(近似) - 关键场景用"烘焙 + 屏幕空间补光" - AI 在工具期以"多套光照方案"烘焙,运行时按时间/天气切换(等效动态)


6. 材质:分层材质系统(Layer Stack)

写实材质的真相是"没有单一 BRDF 能表达真实表面"。

6.1 分层模型

Layer 3: 清漆 / 污渍 / 水膜      (薄膜、Fresnel 调制)
Layer 2: 细节法线 / 划痕 / 织物  (微表面扰动)
Layer 1: 基础 BSDF              (GGX / 布料 / 皮肤 / 毛发)
Layer 0: 吸收与次表面            (体积吸收、SSS)

每层是一个 MIR MaterialGraph 子图,可独立被 AI 生成/替换。这是 AI 能介入材质的关键:AI 不需要生成"最终 shader",只需要生成"某一层的参数与拓扑"。

6.2 扫描材质与 AI 生成

6.3 着色器变体治理

变体爆炸是引擎的隐形杀手(Unity 的 shader variant 噩梦)。ME 的策略:

  1. 材质图编译为"超着色器(ubershader)+ 静态分支",分支由 uniform 控制,减少变体数
  2. 变体 key 由 MIR 静态推导,编译期枚举(不是运行时发现)
  3. 缺失变体 = 编译错误(不是运行时黑屏)
  4. 小游戏端强制"变体预算":单个材质族 ≤32 个变体

7. Character Stack(人物与动物专用)

这是"写实"的胜负手。独立子系统,包含:

7.1 皮肤

7.2 毛发(含动物)

三级方案:

方案 Tier 说明
Strand(曲线) Tier3/4 真实发丝,需要 compute + 深度排序;UE 的 Hair Strands 路线
Shell(壳层) Tier0/1/2 20–40 层壳,每层偏移 + alpha 噪声;成本可控,远看效果尚可
Card + 深度排序 Tier0 传统方案,配合双面渲染与深度剥离

动物毛发的额外难点:密度高(几百万根)、有方向性(grooming)、有长短过渡。方案是 Shell 为主 + 少量 Strand 做近景("混合毛发"),并用 AI 从参考图推断 grooming 方向场(工具期烘焙成 3D 纹理)。

7.3 眼睛

写实角色"死不死",一半看眼睛:

7.4 布料与软体

7.5 角色渲染的预算分配(Tier2 移动端,1080p)

项 预算
主角三角面 60k
主角骨骼 120
同屏角色数 8
皮肤 shader ≤2.5 ms
毛发(主角) ≤3 ms
布料模拟 ≤1 ms

8. Compute-free 路径:最容易被低估的工程难点

Tier0(Android 小游戏)没有 compute,但渲染器有 80% 的现代技术依赖 compute。必须有一套"退化实现":

依赖 compute 的技术 WebGL2 退化方案 质量损失
GPU 视锥/遮挡剔除 CPU 剔除 + occlusion query 异步回读(延迟 1–2 帧) 轻微
Cluster 光照构建 预烘焙 cluster 表(静态光)+ 动态光走 uniform 数组 中
软件光栅(虚拟几何) 编期 LOD 链 中
GPU 粒子 transform feedback(WebGL2 支持) 轻
后处理降噪 空间滤波(不用时序) 中(会闪)
Bloom / DOF mip 链近似 轻

架构要求:所有"依赖 compute"的能力,必须在 RHI 接口层就提供 is_compute_available(),且渲染器有明确的两条构建路径(不是运行期 if)。这条如果做错,后期无法补救。


9. 性能预算与验证

每个 pass 在 MIR 里带 ms_budget,CI 自动跑基准场景,超支即 fail。

Tier 帧预算 33.3ms(30fps)分配
几何 + 剔除 4 ms
主 pass(不透明) 9 ms
透明 / 毛发 5 ms
光照 / GI 4 ms
后处理(TAA/超分) 4 ms
动画 + 模拟 3 ms
逻辑 / 脚本 3 ms
余量 1.3 ms

硬规则:永远留 5% 余量。 没有余量的引擎在真实设备上必然掉帧,因为真机温度墙、后台占用、系统调度都不可控。


10. 小游戏渲染的现实底线(写在最前面,避免幻想)

  1. 主包 4MB:引擎最小运行时目标 ≤1.2MB(gzip 后)。这要求 L5+L4 极度精简,且 Tier0 必须裁掉 Tier3/4 的所有代码(编译期 feature gate,非运行期)。
  2. 首帧 3 秒:必须"占位资产先跑起来",不能等资源。
  3. 30fps 是目标不是底线:低端安卓实测 25fps 就要算失败,因为用户手机会更差。
  4. 发热:小游戏 iOS 用 Metal 后端可降功耗 15%(微信官方数据),这直接影响留存,所以 Tier1 后端要尽早接。

AI 三层、五角色拓扑、预算感知生成、AI Bake、确定性锁

03 · AI 内核(差异化核心)

"Cocos、Unity、Unreal 都是扩展 AI 能力,而我们从 0 开始开发,从 0 就融入 AI 的思考和推理。"

这份文档回答一个问题:"从 0 融入 AI" 在架构上到底意味着什么?


1. 三种 AI 定位,只有一种能形成护城河

定位 做法 天花板 谁在做
A. 外挂助手 编辑器里加聊天面板,AI 给建议,人手动改 人的手速 Cocos / Unity / UE 现状
B. 工具期生成 AI 生成贴图/模型/代码,导入后再人工整理 人的整理成本 各类 AIGC 工具
C. 编译链一等公民 AI 输出 MIR 变换,由编译器硬校验后落盘 验证器质量 MagicEngine

选 C。理由不是"更先进",而是 A 和 B 都有一个共同死穴:AI 的产出不进入可验证的中间层,所以质量不可控、不可复现、不可回滚,最终只能当"灵感工具"用。

C 的前提是引擎有一个能被 AI 精确读写、且能被机器验证的中间表示——这就是 MIR 存在的根本原因。MIR 不是为人类设计的,是为 Agent 设计的。

1.1 为什么成熟引擎做不了这件事

不是技术能力问题,是历史包袱 + 组织约束:

障碍 说明
资产格式不可精确编辑 .uasset / .prefab+meta 是给人用的,AI 只能"猜",改一个字段可能破坏引用图
无预算概念 优化只能事后人肉做,AI 没有可优化的目标函数
跨端是"多后端"而非"多目标编译" 平台差异散落在运行时 #ifdef,AI 无法在编译期消除
工作流已固化 数百万用户依赖现有操作方式,激进改动会引发迁移灾难

这四条构成了一个真实的窗口期:新引擎没有兼容负担,可以一开始就按"Agent 操作 IR"来设计。


2. 三层 AI(必须分开,否则成本失控)

层 时机 算力位置 典型任务 是否必需
AI-1 工具期 编辑/构建时 云端大模型 关卡生成、材质生成、代码生成、风格评审 必需(P0)
AI-2 编译期 打包时 云端 + 本地 MIR 自动优化(合批、LOD 策略、预算重分配) 必需(P1)
AI-3 运行期 游戏运行时 设备 / 云端 NPC 行为、动态叙事、程序化内容、AI 超分 可选(P2+)

关键决策:AI-3 在 P0/P1 一律不做。 小游戏端没有算力,做运行期推理等于自杀。AI-3 的所有产出形态必须先被"烘焙"成数据(见 §5 AI Bake)。


3. Agent 拓扑

五个角色,职责严格分离。分离的目的不是"像人",而是让每个角色有独立的可验证目标。

                    ┌─────────────┐
    用户意图  ─────▶ │  Planner    │  拆解任务、分配预算、仲裁冲突
   (自然语言/文档)    └──────┬──────┘
                            │  Task DAG + Budget
              ┌─────────────┼─────────────┐
              ▼             ▼             ▼
        ┌──────────┐  ┌──────────┐  ┌──────────┐
        │ Builder  │  │ Builder  │  │ Builder  │   场景/材质/动画/逻辑
        │ (scene)  │  │ (material│  │ (anim)   │   各自只改自己领域的 MIR 子图
        └────┬─────┘  └────┬─────┘  └────┬─────┘
             └─────────────┼─────────────┘
                           ▼  MIR diff
                    ┌─────────────┐
                    │  Guardian   │  硬约束校验(编译期门禁,非建议)
                    └──────┬──────┘
                           ▼  通过 / 带诊断退回
                    ┌─────────────┐
                    │   Critic    │  多模态评审:截图 vs 概念图 / 真实参考
                    └──────┬──────┘
                           ▼  评分 + 差异报告
                    ┌─────────────┐
                    │  Optimizer  │  读 profiler → 产 MIR 优化 diff → A/B 验证
                    └─────────────┘

3.1 每个角色的输入输出契约

角色 输入 输出 禁止
Planner 用户意图 + 项目预算 + 现有 MIR 摘要 Task DAG(带预算配额) 禁止直接改 MIR
Builder 单个 Task + 局部 MIR 视图 MIR diff(patch) 禁止跨领域改(材质 Builder 不能动场景层级)
Guardian MIR diff pass / reject(diagnostics) 禁止"宽容放行",禁止用 LLM 判断硬约束
Critic 渲染截图 + 参考图 + 风格向量 0–100 分 + 具体差异描述 禁止无依据打分(必须指出差异区域)
Optimizer profiler trace + 预算报告 MIR 优化 diff + 预期收益 禁止无 A/B 验证就提交

Guardian 必须是确定性的代码,不是 LLM。 这是整个系统可信度的基石:硬约束(碰撞体闭合、预算超限、引用完整性、变体数)永远由代码判定。LLM 只做"软"判断(好不好看、符不符合风格)。


4. Agent 与引擎的唯一接口:三个 API

Agent 不调用引擎 API,不操作文件系统。它只有三个能力:

mir.query(selector) → 结构化子图 + 预算实测值
mir.patch(diff)     → 提交变更(schema 校验 → Guardian → 落盘)
mir.measure(scope)  → 运行基准场景,返回性能/内存/包体实测

为什么必须这么窄

好处 说明
可复现 diff + seed + 模型版本 = 完全可重放
可 review 所有 AI 改动都是文本 diff,像 code review 一样过
可回滚 一次 patch 就是一个 commit
平台无关 Agent 不需要知道目标是小游戏还是 PS5,预算信息在 MIR 里
可组合 多个 Builder 可以并行改不同子图,靠 diff 合并

反模式:给 Agent 一个 engine.createObject() 之类的命令式 API。这样 AI 变成一个"手速极快的实习生",改动无法 review、无法合并、无法回滚。这是绝大多数"引擎 + AI"项目的失败原因。


5. AI Bake —— 让小游戏也能是"AI 引擎"

5.1 问题

小游戏运行环境:WASM + 单线程 + 无 NPU + 4MB 主包。任何运行期推理都不可能。

5.2 机制

工具期(云端)                    编译期                    运行期(设备)
─────────────────              ─────────────           ─────────────────
大模型推理                       AI 结果编译为            零推理
  ↓                              确定性数据              只读数据
生成光照/导航/动画/            → 探针/LUT/骨骼/      → 直接采样
LOD/风格参数                      纹理/表

具体可烘焙的 AI 产出:

AI 产出 烘焙为 运行期开销
光照与反弹 Lightmap + SH 探针 + DDGI 探针 采样成本(极低)
场景布局 静态场景图 + 合批结果 零
毛发 grooming 方向场 3D 纹理(低分辨率) 一次采样
动画重定向结果 骨骼动画片段 零
LOD 层级与切换阈值 Cluster 层级数据 距离比较
材质参数 常量缓冲 + 纹理 零
NPC 行为策略 行为树 / 状态机 / 权重表 状态机求值
风格向量 项目级常量 零

5.3 这条机制的战略价值

它让"AI 引擎"和"低端设备"不再矛盾。竞品的 AI 能力在中高端设备上才能体现;ME 的 AI 能力在所有设备上都体现,因为 AI 的作用发生在构建时,而非运行时。

这是本架构最重要的一条洞察。


6. 预算感知生成(Budget-aware Generation)

6.1 常规做法的问题

生成 → 检查预算 → 超标 → 简化 → 再检查 → ...

这是"生成后裁剪",问题:可能生成的东西本身就是错的,简化救不回来;且迭代次数不可控。

6.2 ME 的做法:预算进入 Prompt 与搜索空间

Budget 作为生成请求的硬参数:

{
  "intent": "雨夜的江南小巷,青石板泛光,两侧三米高老墙,巷宽2.5米,尽头一盏路灯",
  "target": "wechat-android-lowend",
  "budget": { "tri": 18000, "tex": 6MB, "draw": 40, "ms": 8.0 },
  "style_lock": "project:yueju-wuxia@v3",
  "seed": 29281
}

Builder 在生成时就在预算内构造(例如选择"贴图代替几何"、"烘焙光照代替动态光"),而不是生成完再砍。

6.3 预算借贷(Budget Arbitration)

需求天然冲突时(想加细节但超预算),由 Planner 仲裁:

这让"预算"变成和内存一样的硬资源,而不是软目标。


7. 确定性锁(Determinism Lock)

没有确定性,AI 生成的工程不可维护。 这是很多 AI 工具的死穴。

每次生成记录三元组:

seed            : 0x9f2a
model_version   : <provider>@<model>@<version>
recipe_hash     : sha256(完整输入上下文)

三者 + 输入快照 = 任何人可重跑出同一结果。要求:

  1. 模型调用必须 pinned 版本(不接受 latest)
  2. 温度、top_p 等参数进 recipe
  3. 生成结果与 provenance 一起入库
  4. me build --no-ai 必须能在无网络下重建(用已缓存结果)
  5. CI 定期重跑历史 recipe,检测模型漂移

第 2、5 条最容易被忽略,但它们是"三年后还能维护"的唯一保障。


8. 风格锁定(Style Lock)

AI 生成最大的工程问题不是"单个资产不好",而是"拼在一起不协调"。

机制:

  1. 项目级风格向量(来自参考图集,工具期提取一次,锁定)
  2. 每次生成产出的截图由 Critic 打分(与风格向量的相似度 + 具体维度:色彩/材质粗糙度/边缘硬度/光照对比)
  3. 低于阈值 → 拒绝并带诊断重生
  4. 风格向量变更 = 项目级 ADR,必须人工批准(防止风格漂移)

9. 一个完整的闭环(示例:做一个可上线的关卡)

[Day 1]
策划:"做一个雨夜江南小巷,玩家长按屏幕蓄力跳跃,躲避水洼里的陷阱"

Planner:
  ├─ 读项目 MIR 摘要 → 已知:2D 横版、剪纸风格、目标微信低端机
  ├─ 产 Task DAG:场景(40%) / 材质(25%) / 玩法(25%) / UI(10%)
  └─ 分配预算:tri 18k / tex 6MB / draw 40 / 帧内 8ms

Builder(scene):
  ├─ 生成 MIR SceneGraph:巷道体块、青石板、墙、路灯、水洼
  └─ 提交 diff

Guardian:
  ├─ ✗ 巷道宽度 1.8m,与"2.5m"意图不符 → reject(diag)
  └─ ✗ 水洼数量 14 个,超出 draw 预算(每个独立材质)→ reject(diag)

Builder(scene) 修正 → 通过

Builder(material):
  ├─ 生成 MaterialGraph:湿石板(分层:基础→水膜→细节法线)
  └─ 通过(能量守恒校验 OK)

Builder(anim/玩法):
  ├─ 生成蓄力跳跃的 BehaviorGraph + 参数曲线
  └─ 通过

Critic:
  ├─ 截图 vs 参考图:78 分
  └─ 差异:路灯辉光过硬、墙面缺少雨水流痕、整体偏冷
  → 回流给 Builder(material)

Optimizer(CI 自动跑):
  ├─ 低端机实测 11.2ms(超 3.2ms)
  ├─ 定位:透明水洼 overdraw 占 6.1ms
  ├─ 产 diff:水洼改用不透明 + 假反射(省 4.8ms),视觉差异 Critic 打分 -3 分
  └─ 人 review 后合入 → 6.4ms ✓

[Day 3] 打包:主包 3.7MB,分包 12MB(CDN),首次进入 2.1s

这个闭环里,人只做了两件事:写意图、review diff。这就是"AI 进编译链"的实际体感。


10. 反模式清单(写下来防止走偏)

反模式 为什么错
Agent 直接产二进制资产 不可 diff、不可 review、不可回滚 → 工程不可维护
用 LLM 判硬约束 幻觉 → 放出坏包 → 线上事故
运行期跑大模型 小游戏端直接死刑
用 latest 模型版本 三个月后无法复现,等于技术债爆炸
AI 一次生成整关 上下文超限 + 预算失控;必须 Task DAG 分解
无 Critic 直接入库 单个资产"能看",拼起来"难看",返工成本极高
让 AI 决定架构 AI 优化局部,架构必须人定

11. 成本模型(必须算,否则不可持续)

AI 生成的成本对标是美术/策划工时,不是 token 价格。

计算方式(每关卡):

AI 成本 = (生成 token + 重试 token + Critic 视觉调用) × 单价
人力成本 = 节省的美术工时 × 时薪 + 返工工时 × 时薪

经验规律(需在 P0 实测校准): - 一次性资产(场景/关卡):AI 优势最大,因为避免了"沟通成本" - 高频复用资产(角色/UI 组件):AI 优势小,因为人做一次能用一百次 - 需要 IP 一致性的资产(主角/品牌元素):AI 优势最小,因为风格锁定最难

结论:AI 优先攻"一次性、低复用、高沟通成本"的内容——这正是关卡与场景,而不是角色。 这个判断直接影响 P0 的切入点选择。


12. 风险

风险 影响 缓解
AI 生成质量不达"可上线" 引擎价值主张崩塌 P0 就用真实商业项目验证;提前准备"人工兜底工作流"
模型能力/价格突变 成本模型失效 模型适配层抽象;关键能力要求可本地化(小模型蒸馏)
上下文长度限制 大关卡无法一次生成 Task DAG + 局部视图查询(已在架构里)
版权与合规 商用风险 生成资产溯源链 + 商用模型白名单 + 人工审核门
团队不会用 采纳失败 编辑器必须"AI 可选、手动可用",不能强绑

同源原则、MIR 协作模型、平台矩阵、主机门槛

04 · 工具链与平台矩阵

"完善的工具链,加速游戏的开发流程。"

工具链不是引擎的附属品,工具链是引擎产品的本体。开发者日常 90% 的时间在编辑器里,不在引擎源码里。


1. 工具链设计的第一原则:同源

编辑器与运行时必须是同一份代码。

引擎 编辑器渲染 运行时渲染 结果
Unreal Slate + 编辑器视口 独立管线 WYSIWYG 永远差一点,需"Standalone 再调"
Unity 编辑器视口(近似) 独立管线 类似问题
ME 同一个 Renderer,离屏渲染到编辑器纹理 同一份 编辑器里看到的 = 玩家看到的

实现方式:引擎作为库(libme),编辑器进程内嵌引擎实例,渲染到共享纹理(Metal/Vulkan 外部纹理 → 编辑器 UI 合成)。不做两套渲染路径。

代价:引擎必须能在"编辑器模式"下运行(可暂停、可单步、可回滚),这对 ECS 与资源生命周期提出更高要求。这个代价必须付。


2. Magic Studio(编辑器)

2.1 技术选型

层 选择 理由
UI 框架 Tauri + React + TypeScript 包体小(比 Electron 小一个数量级)、内存低、招人容易
编辑器服务 Rust(me-studio) 与引擎同语言,零序列化开销;可处理大 MIR
通 信 本地 IPC(MessagePack) 比 JSON 快,比 gRPC 轻
视口 引擎离屏渲染 → 外部纹理句柄 见 §1
图谱编辑器 自研 Canvas/WebGL 渲染(不用 DOM 节点) 大图(万级节点)性能

为什么不用 Qt/C++:编辑器 UI 的迭代速度决定产品生死,C++ UI 的迭代速度是 TS 的 1/5。UE 的 Slate 是它最难改的部分。

2.2 核心模块

模块 职责 优先级
Scene Editor 场景搭建、层级、变换、组件 P0
Inspector MIR 节点属性编辑(所见即 MIR) P0
Material Editor 分层材质图编辑 + 实时预览 P1
Anim Editor 状态机、混合树、Motion Matching 配置 P1
Behavior Editor 可视化逻辑(编译为 WASM) P1
AI Workbench 意图输入、Task DAG 进度、diff review、Critic 报告 P0
Perf Workbench 时间轴 profiler、预算热力图、优化建议 P1
Asset Browser 资产库、依赖图、引用完整性 P0
Build & Publish 分包预览、包体分析、一键发布 P0

2.3 AI Workbench 是人机协作的核心界面

这个面板的设计决定"AI 引擎"是否好用。三个必须的视图:

  1. 意图输入 + 预算设定:自然语言 + 可视化预算滑块(三角面、内存、包体)
  2. Diff Review:像 GitHub PR 一样,左侧 MIR 文本 diff,右侧实时渲染对比(生成前 / 生成后 / 参考图)
  3. 诊断面板:Guardian 的 reject 原因 + Critic 的差异区域(在图上高亮)

关键交互原则:AI 的每一步都可"退回一步"。 不是"重新生成"(成本高、结果不可控),而是"撤销这一次 patch"。


3. 协作模型:MIR 是文本,所以 git 可用

这是相对 Unity/UE 的结构性优势。

场景 Unity Unreal ME
Prefab/场景合并 需锁文件 / 第三方工具,冲突频发 二进制,必须锁 文本 diff 自动合并
Code Review 代码可以,资产不行 同 资产也能 review
分支开发 场景不敢开分支 同 正常 git flow
CI 校验 有限 有限 全量 MIR 校验 + 预算回归

配套要求:

这条如果做扎实,"多人协作体验"就是可感知的产品优势,成本却很低。


4. 资产管线

导入 → 净化 → 规范化 → MIR 化 → 编译 → 打包
阶段 做什么 AI 介入点
导入 支持 glTF/FBX/OBJ/PNG/EXR/WAV 等 —
净化 去重、合并材质、修正法线、重算切线 AI 判断"哪些是重复材质"
规范化 单位/坐标系/命名统一 —
MIR 化 转为 MIR 节点(不是二进制 blob) AI 补全材质层、生成 LOD 策略
编译 平台特化(纹理压缩、着色器变体、LOD 烘焙) —
打包 分包切分、寻址、压缩 AI 做"分包图划分"建议

关键:资产导入是幂等的、可重放的。 同一源文件 + 同一 pipeline 版本 → 同一 MIR。CI 校验这条,防止"某人的机器上能跑"。


5. 热重载(三级)

级别 内容 目标延迟 状态保留
L1 材质参数、光照参数、数值配置 <50ms 完全保留
L2 MIR 结构变更(增删节点、改层级) <300ms 保留(实体按 id 映射)
L3 代码(BehaviorGraph / 脚本) <1s 保留(WASM 模块热替换 + 状态序列化)

L3 是最难的:需要 WASM 模块级热替换 + ECS 状态迁移。做法: - 脚本编译为独立 WASM 模块,模块间通过稳定 ABI 通信 - 热替换时序列化组件数据 → 卸载旧模块 → 加载新模块 → 反序列化 - 组件 schema 变更时走"迁移函数"(AI 可生成迁移代码)

目标体感:改一行脚本,游戏不中断,0.5 秒后行为变了。


6. 性能工作台

传统 profiler 只告诉你"哪慢"。ME 的目标是"哪慢 + 为什么 + 怎么改 + 改了会怎样"。

视图 内容
时间轴 CPU 主线程 / Job 线程 / GPU 队列,三层对齐
预算热力图 场景里哪些节点超预算,直接高亮在 3D 视口
归因 一个 draw call 的成本,追溯到 MIR 节点链
建议 Optimizer 产出的 diff + 预期收益 + Critic 画质影响评分
回归 与上个版本对比,新增的耗时归因到 commit

真机调试:小游戏端无法本地 profile,需要"远程调试隧道"(WebSocket 推送 trace 到编辑器)。这是必须做的基建,P0 就要有。


7. 平台矩阵

7.1 小游戏(第一战场)

平台 主包 总包 技术约束 我们的策略
微信 ≤4MB ≤30MB(普通分包不限大小,可 CDN) WASM 单线程为主;Android=WebGL2;iOS 已有原生 Metal 后端(compute/indirect/UAV 可用) 主目标。Tier0 + Tier1 双路径
抖音 ≤20MB(无分包)/ 4MB(有分包) ≤20MB(IAP ≤30MB) 类似微信,包体更宽松 第二目标,复用编译链,仅换 PAL
快手 / vivo / OPPO / 小米 / 荣耀 4–6MB 20–30MB 各家 API 差异大 P2 后按商务需要接入

微信的两个关键事实(决定架构):

  1. iOS 侧有原生 Metal 后端 → 可以做 GPU driven、compute 粒子、大规模植被。这意味着"高端小游戏"是一条真实的产品线,不是幻想。
  2. Android 侧仍是 WebGL2 → 必须有无 compute 的退化路径。同一款游戏在两个平台要用不同的 lower 结果,这对编译链是硬要求。

7.2 移动原生

平台 图形 API 关键点
iOS Metal 3 统一内存、TBDR、ProMotion 120Hz
Android Vulkan 1.1+ / GLES3.2 回退 碎片化严重,必须有设备分级表

设备分级:维护一份"设备能力数据库"(GPU 型号 → Tier 映射),安装包首次启动上报,服务端下发画质档位。这是移动端的标配。

7.3 PC

平台 API
Windows D3D12(主)/ Vulkan(备)
macOS Metal
Linux Vulkan

PC 端要支持动态分辨率 + 帧生成 + 超分(FSR/XeSS/DLSS 三选一或抽象层)。这里有个取舍:自研超分 vs 集成,见 ADR-005。

7.4 主机(最远,但要现在就留口)

平台 门槛 工作量
Xbox ID@Xbox 计划,相对最容易申请 GDK(D3D12X)+ 认证(XR 要求)
PlayStation 5 索尼开发者账号 + 公司资质审核 + devkit 采购 + NDA GNM/GNMX(C++)+ TRC 认证
Switch / Switch2 任天堂开发者门户,审核较严 NVN(C++)+ lotcheck

现实提醒(必须写进计划):

  1. 主机 SDK 全部是 C++,且受 NDA 保护,代码不能上公有云、不能给外包看
  2. 认证(TRC/TCR/lotcheck)是独立的 3–6 个月工作,且第一次做几乎必然反复失败
  3. 主机移植的工作量约等于"重做一个渲染后端 + 全套平台服务",不是"改个编译目标"
  4. 中国团队拿 PS5 devkit 的周期不可控,这是商务风险不是技术风险

架构结论:主机支持在架构上"留口"(RHI 的 C ABI 边界、PAL 的平台服务抽象),但不在 P2 之前投入实现。详见 ADR-001。


8. 构建与发布管线

me build --target=wechat-ios      # Tier1(Metal)
me build --target=wechat-android  # Tier0(WebGL2)
me build --target=android         # Vulkan
me build --target=win             # D3D12
me build --target=ps5             # GNM(NDA 环境)

每次构建自动执行:

检查 失败后果
MIR 往返一致性 编译失败
变体数预算 编译失败
三角形/纹理/内存预算 编译失败
主包 4MB 约束 编译失败(并给出可分包建议)
引用完整性(无悬空引用) 编译失败
确定性(同 seed 同产物) 编译失败
真机基准(异步,不阻塞) 报警 + 阻断发布

设计原则:所有能在编译期发现的问题,绝不留给运行期。 编译失败比线上闪退便宜 1000 倍。


9. 工具链的优先级(P0 必须有 vs 可以后补)

P0 必须有 可以后补
MIR 文本编辑 + diff 可视化材质图(P1)
场景搭建(基础) 动画编辑器(P1)
AI Workbench(意图 + diff review) Motion Matching 可视化(P2)
一键构建到微信 + 包体分析 多平台并行构建农场(P2)
真机远程 profile 协作光标(P2)
资产导入 + MIR 化 插件市场(P3)

P0 的判断标准:能做出并上线一款真实游戏的最小工具集。 凡是"让工具更爽"但"不阻塞上线"的,全部推后。

P0-P3 分期、决策门、风险登记册

05 · 路线图、组织与风险

这一份最重要的作用不是"规划未来",而是让你能判断什么时候该停。


1. 总原则

引擎不能"先做完再找游戏"。 必须在有真实项目喂的前提下迭代,否则做出来的是"想象中的需求"。

所以路线图的形状是:每个阶段都以"一款能上线的游戏"为交付物,引擎是副产品。

P0 ──────▶ P1 ──────▶ P2 ──────▶ P3
2D小游戏    3D移动      PC/主机预研   3A管线
(6个月)     (12个月)    (18个月)     (长期)

2. P0:2D/2.5D 小游戏垂直切片(0–6 个月)

目标

上线一款真实的微信小游戏,主包 ≤4MB,低端安卓 30fps 稳定,全程不手写 shader。

这个目标看似"低",但它同时验证了引擎最难的四个假设:

假设 验证方式
H1:WASM-first 架构能塞进 4MB 主包 实测包体
H2:MIR 能被 Agent 正确生成并 review 关卡内容 AI 生成占比 >50%
H3:预算编译能保证真机性能 低端机 benchmark 通过
H4:AI Bake 闭环真的省人力 对比手作工时的实测数据

H2 和 H4 如果 P0 就失败,说明整个方向错了,应立即止损。 这是最重要的决策门。

交付清单

模块 P0 范围
me-core 数学库、句柄、错误、Arena 分配器、日志
me-mir SceneGraph + MaterialGraph(简) + 文本/二进制双形态 + 校验器
me-compiler parse → legalize(Tier0) → budget → link(分包) → pack(微信)
me-runtime Archetype ECS、2D/2.5D 渲染、输入、音频、资源流式
me-rhi 仅 WebGL2 后端
me-pal 仅微信(FS/网络/支付/广告/账号)
me-agent Planner + Builder(scene) + Guardian(不含 Critic/Optimizer)
Magic Studio 场景树、Inspector、AI 面板、构建发布、包体分析
工具基建 MIR 往返校验、me fmt、me merge、真机远程 profile

刻意不做(P0 砍掉的东西)

3D、蒙皮动画、物理(2D 用简单 AABB)、阴影、后处理、材质图编辑器、抖音、Metal 后端、Critic、Optimizer、多人在线。

砍掉清单比保留清单更重要。 P0 里每多加一项,上线时间就往后推一个月。

开发方式的一个加成

引擎代码里 70% 是"A 类代码"(样板多、模式清晰、可测试),非常适合 AI 辅助生成;只有 30% 是"B 类代码"(性能关键路径、平台适配、架构决策)必须人写。

这意味着 P0 用 3 人(1 架构 + 1 引擎 + 1 工具/TA)+ AI 辅助是可行的,而不是行业中常见的 8–10 人。这本身就是对"AI 重构引擎开发"的第一个证明。


3. P1:3D 移动端(6–18 个月)

目标

同一款游戏的 3D 版本上线微信 + 抖音双端;AI 生成的关卡占比 >50% 且通过 review。

交付

模块 内容
渲染 Clustered Forward+、PBR、级联阴影、后处理链、TAA、超分
RHI 新增 Metal 后端(Tier1,解锁 compute 路径)
动画 蒙皮、状态机、混合树、根运动
物理 集成 Jolt(3D 刚体)+ 自研角色控制器
材质 MaterialGraph 编辑器 + 分层材质 + 着色器生成器
MIR v1:完整预算注解 + provenance + 变更迁移
Agent + Critic、+ Optimizer(Perf Agent 闭环上线)
平台 抖音小游戏;Android/iOS 原生
编辑 器 材质编辑、动画编辑、Perf Workbench

关键里程碑

MIR schema 冻结是很重要的时间点。 之前可以随便改,之后每次改都要写迁移,成本陡增。


4. P2:PC 与高端渲染(18–36 个月)

目标

同一份 MIR 编译出 PC 包,画质与移动端拉开明显差距;完成主机移植的技术验证。

交付

模块 内容
几何 Virtual Geometry(先 Tier1 软件光栅,再 Tier3 mesh shader)
光照 SDF-DDGI → HWRT-DDGI、屏幕空间反射、体积雾
角色 Character Stack(皮肤 SSS、毛发 Shell+Strand、眼球、布料)
RHI D3D12、Vulkan
平台 Windows / macOS
工具 资产管线成熟、构建农场、多人协作
主机 申请 devkit(Xbox ID@Xbox 先行),完成一次 RHI 移植冒烟

关键判断

P2 才是"逼真"真正开始的阶段。 P0/P1 的渲染是"够用",P2 才谈"写实"。如果 P2 之前就在追画质,会拖死整个项目。


5. P3:3A 与商业化(36 个月+)


6. 人力与成本(量级参考)

阶段 全职等效人力 角色构成
P0 3–5 人 1 架构、1–2 引擎、1 工具/TA、0.5 策划
P1 8–15 人 +渲染 2、+动画 1、+平台 1、+工具 2、+美术 1
P2 25–40 人 +渲染 4、+角色 3、+主机 3、+QA 3、+美术 5
P3 50+ 人 完整引擎团队

资金量级(一线城市,含社保与设备):P0 约 150–300 万元,P1 约 800–1500 万元/年,P2 约 2500–4000 万元/年。

这些数字是让你判断可行性用的,不是预算书。如果 P0 的 300 万拿不出来,那就应该把 P0 缩到"一个人 + 一款极小游戏",而不是砍架构。


7. 风险登记册

按"影响 × 概率"排序。R1 是唯一的项目级风险,其他都是执行风险。

ID 风险 概率 影响 缓解 触发止损条件
R1 AI 生成质量达不到"可上线" 中高 致命 P0 用真实项目验证;保留人工兜底工作流;优先攻"一次性内容"(关卡/场景)而非"高一致性内容"(主角/IP) P0 结束时 AI 生成内容需人工重做 >60% → 停止 AI 主线,退化为"AI 辅助的传统引擎"
R2 范围爆炸(想做的太多) 高 高 每阶段硬性"不做清单";决策门评审 任一阶段超期 50% → 强制砍范围
R3 小团队产能不足 高 高 AI 辅助写引擎;不做全平台;P0 只做 2D 连续 2 个里程碑延期 → 缩到单人 MVP
R4 主机资质拿不到 / 周期不可控 中 中(延后) 架构留口不实现;Xbox ID@Xbox 先行 不影响 P0–P2,仅影响 P3 时间
R5 模型成本/能力突变、供应商锁定 中 中 模型适配层;关键能力要求可蒸馏到本地小模型 单关卡 AI 成本 > 人力成本 50% → 改用本地小模型
R6 与 Cocos 竞争(免费+成熟+小游戏强势) 高 高 差异化只能是"AI 带来的效率提升",必须可量化;先自用不对外卖 P0 无法证明效率优势 → 引擎转为内部工具,不对外
R7 引擎不回本(只有 1 个项目用) 高 中 计划中必须有 ≥3 个项目的路径 2 年内第 2 个项目未启动 → 降级为框架库
R8 MIR schema 演进失控 中 高 P1 末冻结 + 强制迁移脚本 + 版本协商 schema 变更导致 >1 周返工 → 冻结窗口
R9 引擎人才招不到/留不住 中 高 核心 2 人必须稳定;其余靠 AI + 文档 核心成员流失 → 暂停扩张
R10 小游戏平台政策变化(包体/分成/审核) 中 中 平台抽象层隔离;不押单一平台 主平台政策不利 → 切抖音/快手

R6 值得单独说

小游戏引擎市场已经有 Cocos(免费、成熟、微信生态深度绑定)、Laya、Egret,还有 Unity 的中国特供版。"我做了个新引擎"本身不是卖点。

唯一可能的卖点是:用 MagicEngine 做一款同类游戏,工期是 Cocos 的 1/2,或者同等工期下品质高一档。 如果这个不能被实测数据证明,那么 MagicEngine 的正确归宿是"悦居自用的生产工具",而不是"对外销售的引擎产品"。

这两个定位的架构是不同的(自用可以不管插件生态、文档、向后兼容;对外必须管)。建议 P0/P1 按"自用"设计,P2 再决定是否产品化。 这是一个可逆决策——反过来(先按产品做)不可逆,会拖死项目。


8. 决策门(Go / No-Go)

每个阶段结束必须开一次评审,用数据说话,不用感觉说话。

Gate 0(第 6 个月)

指标 通过线
游戏上线 微信小游戏真实上线,有真实用户
主包体积 ≤4MB
真机性能 低端安卓(骁龙 6 系及以下)30fps,帧时间 p95 ≤33ms
AI 生成占比 关卡内容 ≥50% 由 AI 生成,人工 review 通过率 ≥80%
效率对比 同等内容量,工时 ≤ Cocos 路线的 70%
无手写 shader 全程零手写 GLSL

6 项中 ≥4 项通过 → Go;3 项 → 有条件 Go(缩范围);≤2 项 → 重新评估。

Gate 1(第 18 个月)

3D 双端上线、Perf Agent 产出的优化被采纳率 ≥30%、MIR v1 冻结、第 2 个项目启动。

Gate 2(第 36 个月)

PC 端上线、主机移植冒烟通过、外部团队能独立使用(第 3 个项目)。


9. 第一个项目建议

用自己的产品做第一个项目。 理由:

  1. 不依赖外部客户,节奏自主
  2. 需求真实(不是"为了验证引擎而造的需求")
  3. 失败不外泄
  4. 成功即样板(对外最好的宣传是"我们自己用它做了上线产品")

候选:悦居的文旅/适老化场景做成轻量互动体验,或现有小程序的游戏化版本。关键是:必须是"能上线、有真实用户、有留存指标"的产品,不能是 Demo。


10. 一句话总结

这个项目的成败不取决于渲染有多强,而取决于 P0 那 6 个月里,AI 生成的内容能不能真的省下人力。 能,则后面所有阶段都是"加能力";不能,则越往后投入越亏。 所以 P0 的设计目标不是"做出引擎",而是"用最小成本验证这个假设"。

复用梯度、双索引检索、世界语法、构件化生成、规范化闸门、冷启动

06 · 资产智能与复用架构

这一篇回答:AI 智能体如何积累、检索、适配、装配资产,以及"描述一个世界就生成一个世界"在架构上到底怎么成立。


1. 先把"复用"拆开——三个层次,价值差 10 倍

大多数人说"复用",想的是第一层。真正有价值的是第三层。

层次 动作 人工成本 价值
L1 复制 找到 → 拿走 → 改路径 低 低(等于多存了一份)
L2 适配 找到 → 改参数/接口/规格 → 接入 中 中
L3 组合 找到构件 → 按规则装配成新东西 低 高

为什么 L3 才是终局:

架构结论:资产库的核心不是"仓库",是"构件化 + 装配规则"。 这一条决定了后面所有设计。


2. 复用率梯度——投入优先级由它决定

不是所有资产都值得投入。按品类给出真实梯度:

品类 复用率 为什么 投入优先级
音效 / 音景 90%+ 事件级触发,不依赖上下文;可参数化(pitch/filter/volume)产生变体 最高
UI / 图标 80% 纯功能性,与世界观弱相关 高
材质 / 贴图 70% 可跨项目复用(砖、木、金属、布料) 高
系统代码 60% 输入、存档、相机、寻路、设置、本地化——每个游戏都要 高
道具 / 建筑构件 45% 需适配风格,但构件级可复用好 中
场景布局 / 关卡 20% 关卡是设计,不是资源 低
角色 / IP 形象 10% 角色是识别度,必须专属 极低

三条结论:

  1. 音效优先做,你的判断是对的。 它是"投入产出比"最高的品类:体量小、检索容易、参数化空间大、跨品类通用(一个关门声能用在 50 个游戏里)。
  2. 代码要按"特性包"而不是"文件"复用(见 §5)。
  3. 关卡和角色不要指望复用。 这两块的价值在"独特性",用库反而会拖累品质。架构上不要为它们设计复用机制,那是浪费。

3. 资产库的架构——它不是一个搜索引擎

┌──────────────────────────────────────────────────────────┐
│  Asset Vault(资产仓)                                     │
│  内容寻址存储 · 版本 · 引用计数 · 增量同步                   │
├──────────────────────────────────────────────────────────┤
│  Semantic Index(双索引)★                                │
│  ① 向量索引:语义相近("美式乡村木屋" ≈ "木结构农舍")        │
│  ② 结构索引:规格关系(三角面/骨骼数/UV/材质槽/API 签名)      │
├──────────────────────────────────────────────────────────┤
│  Adapter Layer(适配器)★                                 │
│  规格转换 · 接口适配 · 风格迁移 · LOD 重生成                 │
├──────────────────────────────────────────────────────────┤
│  Provenance Ledger(授权与溯源账本)                        │
│  来源 · 许可 · 生成链路 · 可商用性                          │
└──────────────────────────────────────────────────────────┘

3.1 为什么必须是双索引

单靠向量检索必然失败。 因为美术资产的典型失败模式是:

"这个椅子看起来完全对,但它有 12 万面、UV 是一团乱、朝向是 Y-up、单位是英寸。"

向量索引只会说"很像"。它不知道这资产用不了。

所以必须有第二套索引,索引的是结构属性:

资产类型 结构索引字段
静态网格 三角面数、UV 通道、LOD 层级、包围盒、朝向/单位、材质槽数量
骨骼动画 骨骼数量、命名规范(Mixamo/UE/自定义)、帧率、根运动有无、循环性
材质 分层结构、贴图分辨率、PBR 通道完整性、tiling 模式
音频 时长、采样率、声道、循环点、BPM、情绪标签、事件类型
代码特性包 依赖列表、接口签名、平台要求、MIR 依赖、测试覆盖

检索时两个索引同时用:向量负责"像不像",结构负责"能不能用"。两个都过,才进候选。

3.2 检索不是一次,是一个循环

query
  → 粗排(向量 top-100)
  → 精排(结构兼容性打分)
  → 适配(Adapter 改规格)
  → 硬校验(Guardian:预算/引用/许可)
  → 接受 / 退回(带诊断,重新检索)

关键设计:适配器是必备的,不是可选的。 世界上的资产永远不会恰好匹配你的项目规格。


4. 代码复用——靠契约,不靠相似度

代码和美术的复用机制完全不同:

用向量检索找代码是错的("这段代码和那段代码很像"——像不代表能替换)。

4.1 Feature Package(特性包):复用的最小单位

packages/
  third-person-camera/
    manifest.mir-pkg        # 依赖、平台要求、MIR 版本约束
    src/                    # 实现(Rust/WASM)
    mir/                    # 配套的 MIR 片段(预制体、配置)
    api.md                  # 接口契约(输入/输出/生命周期)
    tests/                  # ★ 必须自带测试
    budget.json             # 预算画像(CPU/内存/包体)

硬规则:没有测试的特性包不允许入库。 因为 AI 会大量组合这些包,一个没有测试的包被组合 50 次,就有 50 个隐患。

4.2 哪些代码适合做特性包

类型 适合度 例子
基础设施 ★★★ 输入映射、存档、设置、本地化、相机、音频管理
系统机制 ★★★ 寻路、对话系统、任务系统、背包、属性系统
品类模板 ★★ 模拟经营的"时间/经济/建造"三件套;RPG 的"战斗/成长/掉落"
具体玩法 ★ 玩法是设计,复用会毁掉差异

你说的"模拟游戏、物理游戏、RPG 不用每次从 0 写",正确的落地方式是:

不是复用"一个 RPG",而是复用 20 个 RPG 特性包(对话、任务、战斗回合、掉落表、装备、属性、存档、商店……),再用 MIR 装配成你的游戏。

装配层才是差异化,包本身是公共设施。


5. 音效为什么最值得做(展开)

音效的可复用性来自四个物理属性:

  1. 事件级:不依赖上下文。"门关上"这个事件在任何游戏里都一样
  2. 可参数化:一个 0.8 秒的木门声,通过 pitch/低通/音量/叠加,能产生 10+ 个变体
  3. 体量小:一个音效 50KB,一个模型 50MB——库的成本差 1000 倍
  4. 描述性强:音频可以用语言精确描述("潮湿的、木头、短促、带金属扣声"),生成模型天然适配

架构:Sound Palette(音景包)

一个"场景的声音配方",而不是一堆散装音频:

palette: chinese-village-dawn
ambience: 远处鸡鸣 + 溪流 + 微风树叶
one_shots:
  木门开: [door_wood_01, door_wood_02(pitch+2)]
  脚步_石板: [step_stone_01..04]
  水桶落井: bucket_well_01
reverb: small_outdoor_rural

这样"中国乡村"这个世界自带一套声音,换场景 = 换 palette,不是逐个挑音频。

AI 介入点


6. 世界构建:世界语法(World Grammar)★

这是我认为整个资产体系里最有价值、也最容易被忽略的东西。

6.1 核心判断

一个"世界"不是资产集合,是"词典 + 语法"。

你说"一个美国小镇",真正的知识不是"有房子",而是:

美式小镇(1950s 中西部)=
  主街(Main Street):宽 12m,两侧连续商铺,雨棚统一,停车斜列
  + 十字支路:每 200m 一条,尽端是住宅区
  + 地标:教堂(尖顶,社区最高点)+ 加油站 + 杂货店 +  diner
  + 住宅区:独栋,前院 8m,车库朝街,白色栅栏
  + 基础设施:电线杆沿街(这是美式小镇最强的视觉符号)
  + 声音:远处火车 + 蟋蟀 + 教堂钟
  + 色彩:褪色红砖 / 米白木板 / 铬黄招牌

这段"语法"比 100 个模型更值钱,因为它能生成无限多个不重复的"美国小镇"。

6.2 对比:中国乡村 / 高端别墅内景

世界类型 语法要点(决定"像不像"的其实是这些)
中国乡村 院落围合(不是开放草坪);晒谷场/水塘是公共空间核心;田埂分割;屋脊方向;柴垛/农具/腌菜缸;声音是鸡犬+广播
高端别墅内景 动线(玄关→客厅→餐厅→厨房);层高与开间比例;材质档次梯度(大理石/木饰面/金属);灯光层次(基础/重点/氛围三层);家具品牌风格一致性

注意:让场景"像中国乡村"的,不是房子的模型,而是"院落围合 + 晒谷场 + 柴垛"这些语法元素。 这也是为什么"从库里随便拿几个中式房子拼一拼"一定不像。

6.3 语法在架构里怎么表达

World Grammar 是 MIR 的一种特殊图(不是代码,是声明式的规则图):

world_grammar "us-town-1950" {
  requires: [street_grid, building_shop, building_house, prop_pole, soundscape_rural]
  layout {
    grid: main_street(width=12m) + cross_street(every=200m)
    zone: commercial(front=main_street, depth=30m) | residential(behind)
    landmark: church{placement: highest_point, max_height: 25m}
    density: {commercial: 0.7, residential: 0.4}
  }
  style_lock: "us-midwest-faded@v1"
  budget: { tri: 180k, tex: 24MB, draw: 220, ms: 8 }
}

编译器(或 Agent)执行它 → 产出一个具体的 SceneGraph。

关键:语法是可积累的知识资产,且可以版本化、可以 A/B 测试(哪种布局玩家更喜欢)。


7. "我要一个房子" —— 构件化生成,不是整体生成

你说:"我需要一个房子的模型,先生成 2D 效果图,然后创建 3D 模型。"

这个流程方向对,但有一个关键岔路要说清:

7.1 不要生成"一个完整的房子模型"

做法 结果
❌ 整体生成一个房子 mesh 面数不可控、无法换风格、无法 LOD、只能用在一次
✅ 生成"墙体/屋顶/门窗/材质 + 装配规则" 面数可控、换材质即换风格、可 LOD、同套构件做 N 栋房

这是建筑业的"构件化"(prefab)思路,也必须是游戏场景生产的正确姿势。

7.2 正确的三段流水线

① 2D 概念图(人 review 这一层)
   文生图 + ControlNet/LoRA 锁定风格与构图
   → 得到"这个房子长什么样"的共识
   → 人工确认:比例、风格、光照意图
        ↓
② 构件生成(AI)
   图 → 构件级 3D(墙体/屋顶/门窗/装饰)
   不是"图 → 整栋房子"
        ↓
③ 规范化闸门(Asset Normalizer)★
   重拓扑 → UV 展开 → 单位/朝向统一 → LOD 生成
   → 材质烘焙 → 碰撞体生成 → 入库

② 之所以按构件生成,是因为 ③ 必须可控。 整体生成的模型过不了 ③。

7.3 关于"自研图生 3D"

必须给一个诚实的现状判断:

环节 现状(2026) 能否直接进管线
文生图 成熟,可控性可接受(配合 ControlNet) ✓ 可直接用(当概念图/贴图源)
图生 3D(整体) 质量参差,"看起来像" ✗ 拓扑/UV/布线不可用
图生 3D(构件/规整物体) 较好,尤其硬表面 △ 仍需规范化
图生 3D(角色/有机体) 差,无法蒙皮 ✗ 不可用

所以"自研图生 3D"的正确目标不是"生成能直接用的模型",而是"生成能被 Normalizer 收编的毛坯"。

这个定位差别很大: - 前者要求模型能力突破(不可控) - 后者要求"生成规整的、可修复的几何"(可通过约束/后处理达成,可控)

架构建议:把力气花在 Normalizer 和"生成约束"上,而不是追求生成质量的天花板。 因为生成质量由基础模型决定(你无法控制别人的迭代),而 Normalizer 是你的资产。


8. Asset Normalizer(规范化闸门)—— 不做这个,库会被垃圾填满

AI 生成的 3D 资产有四个原罪:

原罪 后果 Normalizer 的处理
面数爆炸 一把椅子 12 万面 重拓扑 / 减面到目标预算
UV 混乱 无法贴图、无法烘焙 自动 UV 展开(含 seam 优化)
拓扑差 无法蒙皮、无法变形 四边面重拓扑(角色);硬表面可放宽
单位/朝向不统一 拼装时全乱 单位与轴向规范化 + 包围盒对齐

额外必须做的:

这条闸门是资产库的生命线。 没有它,库的价值会随规模增长而下降(垃圾越多,检索越差)。


9. 流程编排:引擎管什么,平台管什么

你提到版本管理、自动化测试、发布、宣传片、线上运营。这些不能全塞进引擎,否则引擎会变成四不像。

能力 位置 理由
构建 / 打包 引擎内 需要 MIR 与平台工具链
单元/集成测试 引擎内(headless 模式) 需要运行时
自动化真机测试 引擎内产出 + 外部农场 设备矩阵在外部
版本管理 外部(git + Vault) MIR 是文本,天然适配 git
发布 外部 平台政策变化快,不该进内核
宣传片/截图 外部 Agent(调用引擎的离线渲染/录制) 需要视频剪辑能力
运营/数据分析 外部 与引擎无关

原则

引擎是"生产工具",不是"运营平台"。

分界线:凡是需要"MIR + 运行时"的,进引擎;凡是需要"外部服务"的,进平台。

me-ci(进程内 CLI)负责前者,Orchestrator(外部服务)负责编排后者。两者通过一套稳定的 API 通信。

宣传片这条特别值得说:不要做在引擎里。引擎只需要提供"离线高质量渲染 + 固定时间步录制 + 相机路径脚本",剩下的剪辑/配乐/字幕交给外部 Agent。否则你会花两年做一个半吊子的剪辑软件。


10. 冷启动——资产库的鸡生蛋问题

这是整个方向最真实的风险,比技术难得多。

资产库价值 = f(资产数量 × 元数据质量 × 检索准确率)

四个破局手段

  1. 垂直包先行,不做通用库 只做一个包(比如"中式乡村"),做到 300+ 构件、做深做透。 一个能用的垂直包 > 十个半成品通用库。

  2. 生成即入库 每次 AI 生成的产物,经过 Normalizer 后自动入库(带 provenance)。 这样"用"的过程就是"攒"的过程,库随项目自然增长。

  3. 配方优先于模型 World Grammar 和 Sound Palette 这类"配方",几十条就能产生巨大价值, 而模型要几百个才够用。先攒配方,后攒资产。

  4. 合法填充 开源资产(CC0/CC-BY)+ 商用授权库(需记账,Ledger 里标许可)。 注意:这一步必须做许可合规,否则是定时炸弹。


11. 跑满 Xbox——这不是渲染技巧,是"零 CPU 瓶颈"

"跑满主机"常被理解成"画质拉满",其实核心是让 CPU 不再是瓶颈。

Xbox Series X 的关键能力:RDNA2 12 TFLOPS、16GB GDDR6(约 13.5GB 可用)、硬件光追、Mesh Shader、VRS。

要跑满它,必须做到:

要求 含义 对架构的约束(现在就要留)
GPU Driven 场景数据整批提交,CPU 每帧只写少量常量 RHI 必须支持 indirect draw / dispatch
Mesh Shader 路径 几何在 GPU 上生成,不走传统 IA RHI 接口要能表达 mesh pipeline
硬件光追 GI 次级光线在硬件上跑 RHI 要有 RT 抽象(Tier 检查)
异步 Compute 后处理/裁剪与渲染并行 命令队列要支持多队列 + 同步原语
描述符堆 避免每 draw 绑定开销 RHI 要有 bindless/descriptor heap 概念

最关键的一条:如果 P0 的 RHI 只实现了"立即模式 draw call"(WebGL2 就是这样),那么后期要补 GPU driven 会重写整个提交层。

所以架构上必须从现在开始:RHI 接口里保留 draw_indirect / dispatch_indirect / multi_queue / descriptor_set 这些方法,即使 WebGL2 后端把它们实现成"退化版"(内部循环调用普通 draw)。

接口现在留,实现后补。 这是唯一能避免后期重写的办法。


12. Cocos 开源的借鉴方式

Cocos 的引擎代码是公开的,值得读。但要有边界:

借鉴(读设计,自己写) 不要借鉴
组件模型的取舍(为什么它这样设计) 直接拷贝代码(许可 + 架构耦合)
资源管线的依赖图与增量构建 TS/JS 运行时(我们的架构不同)
平台适配层的抽象方式 编辑器 UI 架构(我们的编辑器不同)
分包策略与小游戏发布流程 它的渲染管线(我们要更高上限)

正确做法:读它的 ADR/设计文档/issue 讨论,理解"为什么这样",然后用自己的架构重写。

代码拷贝会带来两个问题:许可风险(各文件许可可能不同)+ 架构污染(它的假设和我们的 MIR 冲突)。


13. 对你这个问题的直接回答

"对你是一个挑战吧?"

是,但挑战不在你想的地方。

你以为的挑战 实际难度 说明
生成能力(文生图/图生 3D) 低 接模型即可,且外部在快速进步
检索 低 向量 + 结构双索引,成熟技术
版本管理 低 MIR 是文本,git 天然适配
跑满 Xbox 中 纯工程量,但要现在就留接口

真正的挑战是三个:

① 冷启动(最大) 库空的时候,整套"智能复用"是空转的。而填库需要时间,时间需要钱。 → 破局:垂直包 + 生成即入库 + 配方优先(§10)

② 适配成本可能高于重做 尤其是代码。一个"看起来能复用"的包,接入时发现接口不匹配、依赖冲突、性能画像不符,改它的时间可能超过重写。 → 破局:特性包必须带契约和测试(§4),否则不允许入库

③ 产品线摊薄 引擎 + 资产库 + 流程编排 + 运营 = 4 个产品。一个小团队做 4 个产品,每个都做不深。 → 破局:明确不同时做。顺序是:引擎(P0)→ 资产库(P1)→ 编排(P2)→ 运营(P3,或永远不做,用现成工具)


14. 对已有架构的增量

这篇文档引入了 4 个新组件,都不改原有分层,而是挂在旁边:

新组件 位置 与既有架构的关系
me-vault L6 侧(资产服务,不在运行时) 产出的资产以 MIR 形式被引用
World Grammar MIR 的一种新图类型 编译期被 lower 成 SceneGraph
Asset Normalizer L8 工具链的后端服务 输出带 budget 的 MIR 节点
Orchestrator 引擎外服务 通过 API 调用 me-ci,不进内核

架构宪法不变:MIR 仍是唯一真相源;AI 仍只操作 MIR;硬校验仍是确定性代码。

新增一条宪法:

第 6 条:任何进入资产库的东西,必须经过 Normalizer 并携带 provenance 与 budget。 例外需要 ADR。

这条是为了防止"库被垃圾填满"——那比库空着更糟。

AI 生成配方而非波形、七项硬校验、声学体检、场景音景闭环、运行时合成

音频与音效架构

状态:P0 已验证(SfxForge 可运行,32 个资产 / 12 个配方 / 5 个场景) 相关:tools/sfx/(实现)、library/sfx/audition.html(试听台)


一、先回答一个前置问题:AI 该生成什么

WorkBuddy 现在没有音频生成模型(只有音频转写)。但这不构成阻碍,因为——

在游戏里,AI 生成音频的正确形态是"生成配方",不是"生成波形"。

理由不是"现在还没有模型",而是三个结构性的:

问题 生成波形(text-to-audio) 生成配方(参数化合成)
可复现 同 prompt 两次不同,无法回滚、无法 diff seed + 参数 = 逐字节一致(已验证)
变体成本 每多一个变体就是一次生成 换 seed,边际成本为 0
包体 每个变体几十~几百 KB 参数 JSON 几百字节,可运行时合成
版权 训练数据来源难自证 纯数学生成,无第三方权利
可编辑 "再亮一点"只能重新生成 改一个 cutoff 数值

这与引擎的核心原则一致:资产必须可复现、可 diff、可回滚。一段不可复现的音频,进不了这条流水线。

所以结构是:

AI(或人)→ 写/改配方(JSON/Python,可 diff)
          → SfxForge 渲染(确定性)
          → 硬校验(7 项,代码判定)
          → 入库(双索引)
          → 试听 / 预烘 / 运行时合成

AI 的产出物是几十行参数,不是 720KB 的 wav。这是本期最重要的一个判断。


二、为什么不用采样库

不是"合成音质更好"(通常不如录音),而是采样库解不了游戏音频的三个硬问题:

  1. 重复感:玩家每秒走两步,一小时 7200 次。同一个采样必被听出来。需要 8~12 个变体,采样方案的成本线性增长,程序化方案为零。
  2. 包体:4MB 主包里,一套能用的采样库(脚步 8 材质 × 8 变体 + 环境 10 条)轻松超过 2MB。程序化配方不到 10KB。
  3. 参数化:同一段风声,白天要亮、夜里要闷、进洞要加混响。采样只能换文件,配方改一个 cutoff 曲线就行。

采样库仍有不可替代的场景:人声、方言、音乐、真实乐器。边界要划清楚(见第八节)。


三、SfxForge 的分层

recipes.py    配方层     "这个声音的物理机制是什么"        ← AI 主要在这层工作
   │
dsp.py        基元层     噪声 / 包络 / 时变滤波 / 颗粒 / 混响 / LUFS
   │
forge.py      管线层     render → dc_block → seamless → normalize → 校验 → 导出
   │
verify.py     门禁层     声学体检(谱质心 / 衰减比 / 带宽)
   │
scene.py      编排层     场景 → 图层 → 检索 → 缺口 → 补齐 → 清单
   │
index.json    索引层     双索引(语义标签 + 结构规格)

3.1 配方:合成发声机理,不是模仿某段音频

这是配方能不能被 AI 改对的关键。写"一段沙沙声"AI 改不动;写清楚机理,AI 就知道该动哪个参数。

声音 机理(写进配方的东西) 只写"效果"会怎样
碎石脚步 低频体重撞击(52~78Hz)+ 5~8 个带通噪声颗粒(450~1100 / 1800~3800Hz) 听起来像踩薯片袋
木门吱呀 stick-slip 摩擦脉冲,音高缓慢上漂 1.4~1.9 倍,中段必有卡顿 像电子音效,不像门
金币 非谐波泛音 1 : 2.76 : 5.40 : 8.93(金属棒振型) 用谐波列会变成玩具笛子
风 粉噪 + 双 LFO(0.11Hz / 0.047Hz)驱动截至 260~1040Hz 扫动 + 树叶层 静态噪声,没有"阵风"
蟋蟀 3~5 个个体,频率 3.6~5.2kHz、节奏互不相同,双层门控(组 × 脉冲) 一只蟋蟀就是电子表

真实感来自"不齐":蟋蟀从不同步、火里的爆裂大小呈对数分布、碎石颗粒的间隔是随机的。配方的价值就在于把这些"不齐"参数化。

3.2 时变滤波为什么必须走 STFT

游戏音效绝大多数是"截止频率随时间扫动"的(风、门轴、水)。二阶 IIR 系数随时间变化会产生相位漂移,扫动时能听见"水泡声"。

实现上踩过两个坑,都记在代码注释里:

3.3 处理顺序不能乱

render → dc_block → make_seamless → normalize

dc_block 是一阶 IIR,带历史状态。我一开始把 seamless 放在 render 内部(即 dc_block 之前),结果交叉淡化做好的接缝被后面的滤波重新撕开,三个循环资产因此挂掉 C4。

教训:管线里只要有一个有状态的环节,前后顺序就是契约,不是风格。


四、七项硬校验

硬校验的原则:代码判定、不通过就不入库、判据本身必须可测量。

# 项 判据 为什么
C1 时长 偏离目标 < 8% 配方声明的时长是设计意图
C2 峰值 ≤ -1.0 dBFS 防削波(编码后会更糟)
C3 直流偏移 < 0.002 布朗噪声(火、风)天然堆在直流附近,不去会浪费动态余量
C4 循环接缝 接缝跳变 < 该信号相邻采样典型差的 3 倍 见下
C5 声道数 一过性=单声道 / 环境=立体声 见下
C6 响度 落在配方声明窗口 环境按 LUFS,短音效按峰值
C7 体积 ogg ≤ 配方预算 4MB 主包的硬约束

C4 的判据我第一版写错了

第一版是"首尾样本差 < 0.02"。这是错的:对宽带噪声,相邻采样点本身就差得很大,绝对阈值毫无意义(0.02 在峰值 -12dBFS 的信号里只相当于 8% 相对误差,正常噪声轻松超过)。

正确的判据必须是相对的:

seam = |x[-1] - x[0]|
typical = percentile(|diff(x)|, 90)
fail if seam / typical > 3.0

含义是:"接缝处的跳变远超这个信号自己的正常跳变"——这才是可听的咔哒。改完立刻通过,而且这个判据对任何信号类型都成立。

这说明一件事:硬校验的价值不在"有校验",在"判据对"。 一个错的判据比没有更糟,因为它会让你以为已经验过。

C5:位置音源必须单声道

这条容易被忽略但必须写死。一过性音效(脚步、狗吠、金币)如果在制作阶段就做成立体声,引擎再也无法做 3D 定位——立体声文件没有相位关系可供 HRTF 使用。

配方层用 decorrelate(fn) 生成真立体声:左右各跑一次不同随机流。这比"单声道 + 延迟"好在单声道兼容——手机外放时不会相位抵消掉音量。


五、双索引(与资产库里是同一套)

{
  "id": "sfx.footstep_gravel.v01",
  "semantic":   { "tags": ["footstep","碎石","土路","户外"], "mood": ["dry","gritty"] },
  "structural": {
    "duration_ms": 300, "channels": 1, "loop": false,
    "peak_dbfs": -3.0, "loop_seam": null,
    "bytes_ogg": 1200,
    "provenance": { "recipe": "footstep_gravel", "seed": 20261048917, "runtime": "baked" }
  }
}

检索时两侧都必须过。这是第六篇讲的"复用的瓶颈在适配不在检索"在音频上的具体落地:库里有一条"风声",标签命中 100%,但如果它是单声道立体声混错的、或者 40 秒长 2MB,它就不能用作 bed。


六、场景音景的闭环

实测跑通(python scene.py):

场景「北方乡村的傍晚」
  ├ [bed]   需要「乡村/傍晚」 → wind_village_dusk (1.00) → v01, 49KB
  ├ [bed]   需要「虫鸣」      → crickets_dusk (1.00)      → v01, 94KB
  ├ [spot]  需要「狗/远处」   → dog_bark_far (1.00)       → v01,  5KB
  ├ [spot]  需要「麻雀」      → bird_sparrow_chirp (1.00) → v01,  2KB
  └ [player] 需要「碎石」     → footstep_gravel 需 4 变体  → 现场补 v04(校验通过)

图层不是装饰,是必需。 真实游戏音景永远是 3~6 层:底床(给空间)、点缀(给生命)、玩家(给反馈)。少一层就"空"——只剩风声的场景听起来像素材,五层叠起来才像"傍晚的村子"。

缺口分两种,处理方式完全不同

类型 含义 处理
MISSING 库里没有这个物种 不能生成,必须新建配方。如实报告
SHORT 有配方但变体不够 换 seed 现场补,走同一套校验

实测中"白天的集市"场景故意留了两个 MISSING(人群嘈杂、叫卖),系统如实报告"2 处缺口"而不是硬凑一个不像的声音。

这个诚实的失败比虚假的成功有用:它直接告诉你"下一步该建哪个配方"。

幂等

第二次运行 scene.py:32 → 32,不重复补齐。缺口判定基于"现有变体数 ≥ 需求数",不是"每次生成一批"。


七、声学体检:不靠耳朵发现问题

我听不到生成的声音。所以做了一层可量化的门禁(verify.py),对每类硬编码物理期望:

类别 谱质心期望 依据
脚步 120~3800Hz 低频体重 + 中频砾石
麻雀 > 2000Hz 鸟的声带就这么高
环境床 80~5600Hz 高频被空气与植被吸收
环境床衰减比 0.45~2.2 循环床必须平稳(首段/末段能量比)
打击型衰减比 < 0.3 末段必须明显低于首段

它抓到了 4 个用耳朵很难定位的错误:

资产 首版质心 问题 修正后
小雨 8289Hz 高频过多,是白噪嘶声不是雨 4562Hz
柴火 7496Hz 爆裂跑到 11kHz,像电子炸点 3442Hz
风 4029Hz 树叶层压过低频,"呼呼"变成"沙沙" 3385Hz
碎石脚步 4267Hz 颗粒频段太高,像踩薯片袋 3400Hz 区间内

人耳会说"有点儿刺",但说不出是哪不对。谱质心直接指向"高频能量占比过高",改哪个参数就明确了。


八、运行时策略:这是体积问题的唯一解

实测:32 个资产 ogg 合计 747KB,其中环境床 690KB。4MB 主包里这是 17%——不可接受。

三条路,只有一条对:

方案 主包占用 代价
全部预烘进包 690KB 吃掉 17% 包体
全部放 CDN 下载 0(首包) 首次进场景卡顿,弱网致命
环境床运行时合成 0 需要 wasm DSP,CPU 有成本

所以 index.json 里标了 provenance.runtime:

环境音的合成成本实测:8.25s 立体声 / 48kHz,Python 侧约 0.4s。wasm 上会更快,且可以分帧增量生成——每帧生成 1024 个样本,占用的 CPU 摊到整个场景生命周期,几乎不可感知。

这还有一个副作用好处:环境音可以随游戏状态连续变化。玩家从屋外走到屋内,风的高频逐渐衰减、混响逐渐增加——用配方改参数就行,用采样就得做交叉淡化,还容易听到切换痕迹。


九、引擎侧音频中间件的接口

音效资产只是原料。引擎需要的是(P0 最小集):

Bus 结构
  Master ─┬─ SFX(一过性)
          ├─ Ambience(环境床,受 ducking)
          ├─ UI(不受 3D 影响)
          ├─ Voice(对话,触发 ducking)
          └─ Music

四个必须 P0 就设计的接口:

  1. 虚拟声部(voice virtualization):小游戏并发源上限约 32。超了要按"优先级 × 距离 × 音量"淘汰,而不是静默丢最老的。淘汰策略错误的表现是"打着打着音效没了"。
  2. Ducking:对话/关键提示时,把 Ambience 自动压 6~10dB。必须做成总线的属性,不能靠每个音效自己调音量。
  3. 3D 衰减模型:距离衰减 + 空气吸收(高频先衰减,这就是"远处"的听感来源,见 dog_bark_far 的 220~2200Hz 带通)。
  4. 流式 vs 常驻:环境床常驻内存(合成后 ~1.6MB PCM/条,需要按需释放),一过性全量预载。

这些都在 ADR-004 的 RHI 之外的独立子系统里,不依赖图形后端。P0 只做 Bus + 简单 pan + 距离衰减,HRTF 留到 P1。


十、做不了的边界(要说清楚)

类型 程序化合成 结论
脚步声/门/金属/UI ✅ 很好 继续扩配方
环境床(风/雨/火/水/虫) ✅ 很好 继续扩配方
人声 / 方言 / 叫卖 ❌ 做不到 必须录音或等 TTS/voice-clone
音乐 / BGM ❌ 不该做 用授权曲库或外部生成
大型生物(怪兽/马/人群) ⚠️ 有限 拟音(foley)或采样

上面表格里的 ❌ 不是"暂时没做",是"路线不同"。集市场景缺的"人群嘈杂"和"叫卖"永远不会被程序化合成解决——那是录音和 TTS 的领域。系统应该如实报告这个缺口,而不是硬凑。


十一、实测记录(可复现)

$ cd tools/sfx && python forge.py
共 32 项 / 12 个配方 / {ui:3, footstep:7, door:3, pickup:3, creature:6, ambience:10}
ogg 合计 747KB(其中环境循环 690KB),wav 合计 16.6MB
全部通过 7 项硬校验。

$ python verify.py
声学体检通过:32 项全部落在各类别物理期望区间内。

$ python scene.py
5 个场景合计 539KB ogg
  · 北方乡村的傍晚  5 层  151.2KB  全部满足
  · 北方老屋的炉火  4 层   86.2KB  全部满足
  · 雨夜的村口      4 层  115.2KB  全部满足
  · 白天的村口      5 层  121.3KB  全部满足
  · 白天的集市      2 层   65.6KB  2 处缺口(故意)

确定性验证:连续两次构建,31 个 wav 的 MD5 完全一致。
布局审计:0 横向溢出 / 0 处 < 11px 的字 / 0 JS 报错 / 32 个 ogg 全部可加载。

十二、下一步

按性价比排序:

  1. wasm 版 DSP(把 dsp.py 移植到 Rust→wasm32)——这是环境音 0 字节的前提,也是"引擎内实时合成"的唯一路径
  2. 配方扩展:先做 20 个"室内"配方(家具、布料、玻璃、陶器、金属),室内场景的复用率最高
  3. AI 写配方:给 AI 一份机理模板 + 参数区间 + 校验反馈,让它产出配方而不是音频。这是本期"AI 生成、确定性产出"的完整闭环
  4. 音频中间件(Bus / ducking / virtualization)——等 P0 引擎骨架起来再对接

本文档的所有数字均来自实跑,脚本在 tools/sfx/,试听台在 library/sfx/audition.html。

11 个后端许可核验、三处会否决商用的错误、可调用性实测、三档选型、三分区架构

08 · 生成式音频:选型核验与接入架构

状态:已核验(2026-10-22),许可证与端点均为当日实测/实读 适用:SfxForge 音频子系统的生成式后端选型


0. 三句话结论

  1. 清单里有 3 处会直接否决商用的错误:AudioGen 权重是 CC-BY-NC(禁商用)、Stable Audio 是"营收 <100 万美元"条件许可且叠加 Gemma 条款、Dasheng 输出只有 16kHz。
  2. 真正被漏掉的好东西是 MOSS-SoundEffect v2.0——清单里唯一真 Apache-2.0、48kHz、支持中文提示的音效模型。但本机 8GB 内存跑不动,且 HuggingFace 与 hf-mirror 均不可达(实测超时)。
  3. WorkBuddy 自身没有任何音频生成能力(只有图像/视频/3D 生成和音频转写)。可调用的三个云端后端我已全部接通并实测到鉴权层,只差你的 key。

1. 先划约束

选型不能脱离这四条,否则就是抄参数表:

约束 数值 为什么是硬约束
小游戏主包 4MB(首包) 一段 20 秒 48kHz 立体声 = 3.8MB,一条就吃掉整个包
本机算力 M1 / 8GB 统一内存 MOSS v2 权重 11.2GB,MLX 版 30 秒峰值 14.2GB。差一个数量级
网络 HF ❌ / hf-mirror ❌ / pypi ✅ / 国内 API ✅ / fal·replicate·stability ✅ 开源权重下载不下来,这条路今天不成立
许可链 引擎要交付给第三方客户 有营收阈值的许可,你无法替客户保证

第四条的杀伤力最容易被低估:稳定音频那类"营收 <100 万美元免费商用"的条款,作为自用工具没问题,作为引擎内置能力就是定时炸弹——你交付给一个年营收 200 万的客户,他就在违约。


2. 清单逐条核验

2.1 开源模型

模型 宣称 核验结果 裁决
Meta AudioGen 文生音效 代码 MIT,但权重 CC-BY-NC 4.0;16kHz 单声道;10 秒上限 ⛔ 商用出局。且 16kHz 意味着 8kHz 以上频段全无——金属、玻璃、水花这些靠高频质感的声音会变闷响
Stable Audio Open 47 秒 / 44.1kHz 立体声 47 秒是 1.1B 那个;Small 版是 341M / 11 秒。许可是 Stability 社区许可:营收 <$1M 免费商用;2026 年 5 月的 SA3 Small-SFX 还叠加 Gemma 条款(文本编码器是 T5Gemma) ⚠️ 自用可,交付不可。质量确实好,留作"编辑器内试听/临时素材"
MOSS-SoundEffect v2.0 国内开源 ✅ 确认为真:1.3B DiT + DAC VAE + Qwen3-1.7B,48kHz、中文提示、30 秒、Apache-2.0(模型/代码/组件全是) ✅ 许可与规格都是最优解,但本机跑不动,且权重下不来。列长期兜底
小米 Dasheng-AudioGen 文生音效 Apache-2.0 干净,但输出 16kHz;定位是"结构化混合场景"(对白+音效+音乐一条出) ⚠️ 用它出单个开门声是错配;出一整段带台词剧情音频才是它的用法

2.2 线上产品

产品 核验结果 裁决
ElevenLabs SFX v2 最长 30 秒;全清单唯一服务端支持 loop=true;48kHz WAV(非循环);$0.12/分钟;免费层仅限个人非商用,付费层才商用 ✅ 音质基准。缺点是英文提示词,中文场景会掉
Adobe Firefly SFX 版权友好,但主要落在 Premiere / Firefly 应用内;独立 API 不明确 ⛔ 不作为引擎后端(无法程序化接入)
可灵 / 即梦 有文生音效,但没有公开的开放 API ⚠️ 只能走"网页生成 → 下载 → ingest 导入"这条手工路径
字节 Seed-Audio 1.0 ✅ 确认开放 API:POST https://openspeech.bytedance.com/api/v3/tts/create,model: seed-audio-1.0,最长 120 秒,48kHz,支持 wav/ogg_opus,中文提示词原生 ✅ 国内首选,理由见下

2.3 清单漏掉的一整类:视频 → 音效

这类东西确实存在且很值钱(画面里的动作自动配对声音),但商用全军覆没:

模型 许可真相
HunyuanVideo-Foley(腾讯) 混元社区许可,EU / UK / 韩国不适用,48kHz,帧级同步
MMAudio(Sony/UIUC) 代码 MIT,权重 CC-BY-NC
ThinkSound / PrismAudio(阿里) 仓库挂 Apache-2.0,README 却写明仅研究教育用途
Woosh(Sony) 代码 MIT,权重非商用

ThinkSound 这一类最危险:法务看仓库标签会放过它,实际条款禁止商用。许可必须读 README 和 NOTICE,不能读仓库 badge。

而且它解决的是另一类问题——不是"我要一个开门的声音",而是"我已经有画面,让声音踩在动作上"。这属于流程差异,不是模型强弱。


3. 我实际能调用什么(实测)

我在本机跑了一遍真实探测,结果如下(python genai.py probe):

后端 端点 实测 状态
volc-seedaudio openspeech.bytedance.com HTTP 400 fail to convert model to resource_id ✅ 链路通,缺 VOLC_AUDIO_API_KEY
eleven-sfx api.elevenlabs.io HTTP 401 Neither authorization header nor xi-api-key received ✅ 链路通,缺 ELEVENLABS_API_KEY
fal-eleven fal.run HTTP 401 Cannot access application "fal-ai/elevenlabs" ✅ 链路通,缺 FAL_KEY

401 / 400 说明端点活着,只缺匙;000 才是真不通。 同期实测 huggingface.co 与 hf-mirror.com 都是 000(超时),api.openai.com 也是 000。

所以直接回答你的问题:


4. 选型决定

分三档,不要只选一个——用途不同:

主用:火山 Seed-Audio 1.0

四个理由,都不是参数表能看出来的:

  1. 中文提示词原生。写"北方乡村集市,人群嘈杂,远处有人叫卖"直接可用;英文模型要先翻译,而"叫卖"这种词翻译完味道就变了。
  2. 一个模型覆盖人声+音效+音乐+环境。这正是配方永远做不到的三类(真人声/方言、人群嘈杂、独特奇观音)——它精准补上 SfxForge 已知的能力空洞。
  3. 48kHz + 120 秒 + 直接出 ogg_opus。省一次转码,环境床长度也够。
  4. 国内节点:支付、发票、合规、延迟都在同一侧。

个人有 30 分钟免费额度,够验证 60~100 条。

质量基准:ElevenLabs SFX v2(直连或经 fal)

只在两种情况下用:需要 loop=true 的服务端无缝循环(这是它独有的),或英文场景要一版最高音质的参照。

长期兜底:MOSS-SoundEffect v2.0

唯一能同时满足"Apache-2.0 + 48kHz + 中文 + 可微调 + 可私有化"的。等换 32GB 以上机器或租卡时切换。它的战略价值不是现在能用,而是引擎产品化时的许可安全底线。

明确不选


5. 接入架构:生成只做"补缺口"

5.1 三个分区(物理隔离,不是逻辑标记)

library/sfx/
  wav/  ogg/  index.json      可重建区:配方渲染,逐字节可复现,进 CI
  generated/                  冻结区:生成/导入,不可复现,靠 sha256 保真
  scenes/                     场景音景清单

为什么必须物理隔离:可重建区的资产可以随时 rm -rf 再跑一遍;冻结区不能——删了就永远回不来(同 prompt 再生成是另一条音频)。混在一起,一次误清理就把花了钱和时间的东西全毁掉。

5.2 三条规则(写进代码,不是写进文档)

R1 生成资产不进可重建区。 generated/ 的 provenance.zone = "frozen"。

R2 不可复现的资产必须冻结字节。 deterministic: false + sha256_wav。而且禁止在 CI 里重新生成来"验证"——那是测不出来的,只能测字节有没有被换。

R3 生成不是资产库主力。 配方负责常规音效(可复现、0 KB、换种子出新变体),生成只补三类配方永远做不到的。

R2 的执行不是口号:python genai.py verify 会重算 sha256。我实测过——改一个字节即报错、退出码 1,并拒绝保留旧 provenance。

5.3 生成必须过同一道闸门

生成产物和配方产物走完全相同的七项硬校验(时长/峰值/直流/循环接缝/声道/响度/体积)。不通过就进 generated/rejected/,入库标准不因"这是花钱生成的"而降级。

实测细节:单声道环境床要变立体声,我没有用"延迟 1ms"那种相位把戏(手机外放会相位抵消掉 3dB),而是干声完全相同 + 湿声两路独立扩散,干声占 82% 保单声道兼容。位置音源则强制单声道——立体声文件做不了 3D 定位,这是硬约束。

5.4 为什么生成不能进运行期

一段 20 秒 48kHz 立体声未压缩约 3.8MB,超过小游戏主包 4MB 的全部预算。所以生成只能在工具期烘焙(bake-time),产出物再经 opus 压缩进包。想"运行时生成变体"在小游戏上是不成立的;那是主机/PC 才有的奢侈。


6. 成本:不是决策变量

方案 单价 100 条一过性(1.5s) + 10 条环境床(20s)
火山 Seed-Audio ≈¥0.05/秒* ≈ ¥18
ElevenLabs(直连/fal) $0.002/秒 ≈ ¥5
MOSS 自建 仅算力 ≈ 0

* 火山单价来自第三方整理,官方单价未完整公开,以控制台为准。

一百多块钱以内的差别,不构成选型理由。真正的决策变量是:许可、中文、包体、可复现性。这也是我建议不要在这上面做比价优化的原因。


7. 需要你做的两件事

第一件(决定能不能动手):选一个后端注册拿试用额度,把 key 给我。

export VOLC_AUDIO_API_KEY=...        # 火山方舟控制台 → 豆包语音 → Seed-Audio
# 或
export ELEVENLABS_API_KEY=...        # elevenlabs.io → Profile → API Keys
# 或
export FAL_KEY=...                   # fal.ai → Keys

拿到后一条命令就能出声音并自动过闸门:

python genai.py gen --provider volc-seedaudio \
  --prompt "北方乡村集市,人群嘈杂,远处有人在叫卖" \
  --seconds 8 --kind ambience --id market_crowd

第二件(不需要 key 就能做):核对请求体。--dry-run 会打印将要发出的完整请求,你把这个和火山控制台的文档对一遍——契约字段错一个字符,调用就是失败的。

python genai.py gen --provider volc-seedaudio --prompt "test" --dry-run

8. 命令速查

python genai.py list                      # 11 个后端总览(含不能商用的,作为决策记录)
python genai.py probe                     # 实测可达性 + 密钥状态
python genai.py gen --provider X --prompt "..." --seconds 3 --kind one-shot --id foo
python genai.py gen --provider X --prompt "..." --dry-run      # 只打印请求
python genai.py ingest --file ~/Downloads/xx.mp3 --id foo \
       --kind ambience --source "即梦" --license "..." --commercial unknown
python genai.py verify                    # 校验冻结区字节未被替换

ingest 这条路径比看起来重要:可灵、即梦只有网页端没有开放 API,手动下载再导入是目前唯一合法的接入方式,而且导入后与 API 产物结构完全同构——后续检索、装配、打包不受影响。

三层计划粒度、P0-P3 路线、六个里程碑 DoD、WBS 与 88 人周、关键路径、降级方案

09 · 开发总计划:路线图、里程碑与执行

05 号文档回答"分几个阶段、什么时候该停"。 这一份回答"下周谁做什么、做到什么算完成"。

基准日:2026-11-02(周一)。P0 起算,26 周,2027-04-30 结项。

配套:可交互甘特图见 plan/gantt.html(数据源 plan/p0-plan.json); 逐迭代任务与人日见 10-p0-sprint-plan.md。


1. 计划的四个前提(不成立则计划作废)

前提 具体值 不成立会怎样
有一个真实项目 悦居自有产品,能上线、有真实用户、有留存指标 变成"为验证引擎而造需求",Gate 0 数据全是自欺
人力 基准 4 人(3 全职 + 1 半职 TA/美术协调) 3 人 → 砍范围(见 §11);2 人 → 只做 §12 的单人 MVP
周期 26 周硬上限,不可延期 延期等于把 P1 的预算烧在 P0,且证明不了假设
AI 可用性 编码 Agent + 一个强模型 API,成本可忽略 退回传统开发,工期 ×1.8,P0 目标作废

第一条是一票否决项。 没有真实项目,就不该启动这个计划——应该先做一个 Cocos 项目,再回来。


2. 计划分三层,每层回答不同问题

层 粒度 回答什么 谁看 变更频率
路线图 阶段(P0–P3) 值不值得投、什么时候停 决策者 一年一次
里程碑 6–8 周 这一段的产出是否成立 全员 双周对齐
迭代计划 2 周 本周谁做什么、卡在哪 执行者 每周

三层之间是承诺关系:迭代承诺给里程碑,里程碑承诺给路线图。任何一层失守,必须向上报告,不允许在迭代层偷偷吸收。


3. 全景路线图

        2026                                    2027                    2028            2029+
  ────────────────────────────────────────────────────────────────────────────────────────────
  P0  ├── 2D/2.5D 小游戏上线(26 周)──┤
  P1                                  ├──── 3D 移动双端(12 个月)────┤
  P2                                                                ├──── PC/主机预研(18 个月)────┤
  P3                                                                                            └─ 3A/商业化
      ▲Gate0              ▲Gate1                    ▲Gate2
阶段 时间 一句话目标 唯一决策门
P0 2026-11 → 2027-04 一款微信小游戏真实上线,主包 ≤4MB,低端安卓 30fps,零手写 shader Gate 0:六项指标 ≥4 项通过
P1 2027-05 → 2028-04 同一款游戏 3D 版上线微信+抖音,AI 生成关卡占比 >50% Gate 1:双端上线 + Perf Agent 采纳率 ≥30%
P2 2028-05 → 2029-10 同一份 MIR 编出 PC 包,主机移植冒烟通过 Gate 2:PC 上线 + 外部团队独立使用
P3 2029-11 → 主机正式支持、大世界、第 3 方付费 商业验证

每个阶段只有一个门,门的判据在启动时就写死。 中途改判据等于没有门。


4. P0 的 13 个迭代(一览)

双周迭代,S0 起。每个迭代有唯一主题——一个迭代里塞两个主题,通常两个都做不完。

迭代 周 主题 关键产出 门
S0 W1–2 工程基线与语言决策 wasm 三角形上屏;Rust→C ABI→C++ 冒烟 D0
S1 W3–4 MIR v0 落地 解析/序列化/格式化/往返校验
S2 W5–6 编译链骨架 + 首个 RHI .mir → 屏幕上带纹理四边形 M0.2
S3 W7–8 ECS + 2D 渲染 1000 sprite 60fps
S4 W9–10 音频与资源流式 场景切换无白屏;混音 CPU <1.5ms
S5 W11–12 Agent 闭环 v0 一句话 → 可编译 MIR + diff review
S6 W13–14 编辑器 v0 场景树/Inspector/视口/构建发布
S7 W15–16 垂直切片 可玩关卡,真机 30fps,trace 回传 M0.3
S8 W17–18 包体攻坚 主包 ≤4MB,首帧 <3s M0.5
S9 W19–20 内容量产 10 关卡,AI 占比 ≥50%
S10 W21–22 稳定性与兼容 30 分钟无崩溃、无内存增长 M0.6
S11 W23–24 上线准备 提审通过、灰度 5%
S12 W25–26 上线与复盘 Gate 0 评审报告 Gate 0

S8 是最危险的一个迭代。 4MB 是一个物理约束,不是"再挤一挤"。它的解法必须在 S3–S7 就埋好(纹理压缩、wasm 体积、分包划分),S8 只是验收。如果 S8 才开始想包体,一定失败。


5. 里程碑与门禁(DoD 逐条可判)

里程碑不是"做完某个模块",而是"某个能力被真实证明"。每个里程碑都必须有可运行产物 + 可核对的数字。

D0 · 语言与基建决策门(W2)

判据 通过线
wasm 产物 在微信开发者工具里出画面,.wasm ≤ 800KB(release + wasm-opt)
FFI 冒烟 Rust → 手写 C ABI → C++ 后端,跑通一个三角形;调用开销 <2μs/次
构建耗时 全量构建 ≤10 分钟,增量 ≤60 秒
CI 三个目标(host / wasm32 / iOS-arm64)全部绿
决策 Rust + C++ 方案维持,或回退纯 C++(ADR-001 转 Accepted/Rejected)

这一关最重要的不是"技术可行",而是在写下 5 万行代码之前,确认语言选对了。改语言的成本在这里是 2 周,在 S6 之后是 4 个月。

M0.2 · 第一个真实渲染闭环(W6)

判据 通过线
端到端 .mir 文本 → 编译 → 屏幕出现带纹理的四边形,全程无手写 GLSL
预算门禁 故意把 tri 预算改成 10,编译失败,报错精确到节点 id
往返 1000 节点场景 mir→mirb→mir 字节级等义
确定性 同输入两次构建,产物 hash 一致

M0.3 · 可玩切片(W16)

判据 通过线
可玩性 3 分钟完整玩法循环(开始→关卡→结算→重开)
真机 中端安卓(骁龙 7 系)稳定 30fps,帧时间 p95 ≤33ms
内存 峰值 <600MB
可观测 真机 trace 能回传到编辑器,帧时间可归因到 MIR 节点

M0.5 · 包体与冷启动(W18)

判据 通过线
主包 ≤4MB(微信真机安装验证,不是构建产物估算)
首帧 冷启动首帧 <3s(中端安卓,4G 网络)
分包 总包 ≤30MB,分包加载成功率 ≥99.5%
纹理 全部走 ASTC/ETC2,无未压缩贴图进包

M0.6 · 内容与稳定性(W22)

判据 通过线
内容量 10 个关卡,AI 生成占比 ≥50%(按 MIR 节点数计,非人工估算)
质量 AI 生成内容人工 review 一次通过率 ≥80%
稳定 连续 30 分钟游玩无崩溃、无内存单调增长
覆盖 5 台真机(3 安卓低中端 + 2 iOS)全绿

Gate 0 · 六项指标(W26)

沿用 05 号文档判据,≥4 项通过即 Go。额外要求:一份工时台账——记录每个关卡的人工小时,与 Cocos 路线同内容量的估算对比。没有台账,"效率提升"就是感觉。


6. 工作分解与工时估算(WBS)

基准容量:4 人 × 26 周 = 104 人周。但要区分两本账:

账 人周 说明
可承诺工作量 88 下表 14 个工作包的净开发量
过程开销 12 站会、评审、联调、Code Review、文档
缓冲 4 预留给 §7.1 的中间窗口
合计 104 = 4 人 × 26 周

88 / 104 = 85% 利用率,这是可持续的上限。不要按 100% 排计划——按 100% 排的计划,第一个意外就会全盘崩。

工作包 人周 主责 迭代跨度
工程基线(仓库/CI/构建/发布脚本) 3 A S0–S1
me-core(数学/句柄/错误/Arena/日志) 4 B S0–S2
me-mir(schema/解析/序列化/校验/格式化) 8 A S1–S4
me-compiler(6 个 pass + 分包 link) 11 A S2–S6
me-rhi WebGL2 后端 8 B S2–S5
me-runtime(ECS/调度/内存/输入) 11 B S3–S6
2D/2.5D 渲染器(批处理/图集/文本/后处理) 9 B S3–S7
me-pal 微信(FS/网络/账号/广告/支付) 3 C S3–S6
音频子系统接入(混音器 + 配方运行时) 3 C S4–S5
资源流式与分包加载 4 B S5–S8
Agent 闭环 v0(Planner/Builder/Guardian) 6 A S5–S8
Magic Studio v0(Tauri + React) 6 C S6–S9
内容与关卡(10 关,含世界语法) 7 D S7–S11
真机测试/兼容/上线运营 5 D S7–S12
合计 88

6.1 工时是怎么估的

按"A/B 类代码"分开估,这是本计划与常规估算最大的差别:

代码类型 占比 估算方式 系数
A 类:样板清晰、接口明确、可测试 ~60% 按接口数 × 单接口耗时 ×0.6(AI 生成 + 人工 review)
B 类:性能关键、平台贴边、架构决策 ~40% 按经验值,不打折 ×1.0(人写)

不要对 B 类打折。 渲染提交层、RHI 后端、ECS 内存布局、Agent 的校验器——这些地方的错误会在 S8 以"包体超 800KB""帧时间抖 8ms"的形式回来收利息。

6.2 B 类代码清单(禁止 AI 生成,必须人写)

这份清单要贴在仓库里,作为 Code Review 的第一条检查项:

判断标准很简单:如果这段代码错了,会让性能或包体变成"说不清原因的问题",它就属于 B 类。


7. 关键路径与不可压缩项

S0 基建 ──▶ S1 MIR ──▶ S2 编译器 ──▶ S3 ECS/渲染 ──▶ S7 切片 ──▶ S8 包体 ──▶ S11 审核 ──▶ S12 上线
             │            │              │
             └─▶ S5 Agent ┴──────────────┘(旁路,可晚 2 周但不能晚 6 周)

关键路径上的三个不可压缩项(这几件事无法靠加人缩短):

项 耗时 为什么不可压缩
4MB 攻坚 3–4 周 每一次纹理压缩/分包调整都要走真机安装验证,一轮 2–3 天
真机兼容 3 周 设备到货、驱动怪癖、厂商 ROM 差异,只能一台台过
平台审核 1–3 周 外部黑盒,被拒一次就是 3–5 天,且无法加速

这三个加起来约 8 周,必须显式排在 S8–S11,不能藏在"开发时间"里。

7.1 缓冲放在哪里

不放在最后,而是分布在 S8–S11:每个迭代预留 1 人周未承诺容量,共 4 人周。

两个理由:

  1. 不单独占日历周。 插一整周会让 26 周的日期全部后移,和"结项日期不动"的硬约束冲突;而且一旦写进日历,"保留的一周"就会自动被填满。
  2. 落在中后段,而不是末尾。 如果放在最后(S12 前两天),它一定会被当成"再多做点功能"的时间烧掉;放在 S8–S11,它是"补关键路径的债"的专用窗口——包体、真机兼容、Agent 质量恰好都在这一段收尾。

缓冲是"哪条线告急就给谁",不是平均分。 默认分配顺序:包体(S8 溢出)→ 真机兼容 → Agent 质量。三者都没告急,则用于 S9 的关卡扩量(10 → 12)。

这也是"承诺 88 / 容量 104"这组数字的实际含义:那 15% 的缺口不是浪费,它就是缓冲。 排到 100% 的计划没有缓冲,第一个意外就会全盘崩。


8. 人力配置与分工

8.1 角色

代号 角色 核心职责 不可替代性
A 架构 / 编译链 MIR、编译器、Agent 编排、技术决策 极高——全项目只有一个人能改 schema
B 引擎 / 渲染 RHI、渲染器、ECS、性能 极高——性能问题只有他能定位
C 工具 / 平台 编译器 CLI、Studio、微信 PAL、CI 中——可外包部分
D TA / 内容 关卡、资产、真机测试、运营 中——可用外包 + AI 补

8.2 RACI(关键交付物)

交付物 A B C D 飞哥
MIR schema R C C I A
编译链 R C I I A
RHI / 渲染器 C R I I A
运行时 / ECS C R I I A
Studio C I R C A
Agent 闭环 R C C I A
内容与关卡 I I C R A
上线发布 I I C R R

R=负责执行 A=最终问责 C=需咨询 I=需知会

A 是单点。 这不是好设计,是小团队的必然。缓解手段:MIR schema 与编译链 pass 的每一处决策都写 ADR,保证换人时能接上。这是本计划里唯一"为离职做设计"的部分,值得。

8.3 每周节奏(固定,不可协商)

时间 事项 时长 产出
周一 10:00 迭代规划 30 min 本周承诺清单(≤5 项)
每日 站会(异步文字即可) 5 min 阻塞项上墙
周五 17:00 Demo + 指标更新 30 min 可运行产物 + 8 个指标数字
双周五 迭代评审 + 回顾 60 min 完成率、下迭代范围调整

周五 Demo 的硬规则:只演示能跑的,不演示 PPT。 演示不了的,就是没做完。


9. 工程规范(决定 AI 能否真的提效)

9.1 仓库与分支

main                    ← 永远可构建、可发布
 └─ feat/<sprint>-<topic>   ← 双周迭代分支
     └─ ai/<agent>-<task>   ← Agent 产出分支,自动开 PR

9.2 AI 生成代码的三条准入规则

规则 内容 违反后果
R-AI-1 所有 AI 生成的代码在 commit message 里标 ai: 前缀 + 模型名 + prompt hash 无法评估 AI 的真实贡献,§12 的止损判据失效
R-AI-2 A 类代码可 AI 生成;B 类(§6.2 清单)禁止 AI 生成,只能 AI 建议 性能问题变成玄学
R-AI-3 AI 生成的功能代码必须有测试,覆盖率不低于人工代码(≥70% 行 / ≥60% 分支) 组合 50 个特性包后留下 50 个隐患

R-AI-1 看起来只是规范,实际是整个项目的度量基础。 如果分不清哪行是 AI 写的,Gate 0 的"AI 生成占比"就只能靠感觉——那这一整年的核心假设就没被验证。

9.3 确定性三连(每个 PR 必过)

  1. MIR 往返:mir → mirb → mir 字节级等义
  2. 可复现构建:同 commit 两次构建,产物 hash 一致
  3. golden 对比:渲染产物与基准图的 SSIM ≥0.98(容差按场景配置)

第 2 条最容易破:时间戳、路径、HashMap 迭代顺序、并行任务完成顺序都会破坏它。在 S0 就要把 SOURCE_DATE_EPOCH、稳定排序、确定性 RNG 全部处理掉,否则后期补是灾难。


10. 测试与度量

10.1 六类测试,各管一件事

类型 频率 管什么 失败处理
单元测试 每次提交 纯逻辑正确性 阻断合并
MIR golden 每次提交 编译产物不漂移 阻断合并
视觉金图 每次提交 渲染不回归 阻断合并(人工确认后更新基准)
真机自动化 每日 真实设备能跑 阻断发布
性能回归 每日 帧时间/内存/包体 超阈值 5% 报警,超 10% 阻断
确定性 每次发布 可复现 阻断发布

10.2 看板指标(每周五更新,只有 8 个)

指标 目标 说明
主包体积 ≤4096KB 从 S2 就开始画曲线,不要等到 S8
首帧时间 <3s 中端安卓真机
帧时间 p95 ≤33ms 目标场景,不是空场景
峰值内存 <600MB 真机
AI 生成占比 ≥50% 按 MIR 节点数,脚本统计
AI patch 采纳率 ≥80% 一次通过率,不是"改改能用"
CI 全绿率 ≥90% 低于 80% 说明测试不可信
迭代完成率 ≥85% 连续两迭代 <70% → 触发范围裁剪

指标超过 8 个就没人看了。 想看细节去 dashboard,看板只放这 8 个。


11. 预算(P0,基准 4 人)

项 金额 说明
人力(4 人 × 6.5 月,含社保) 95–130 万 按 3.5–5 万/月全成本
真机与设备 8–12 万 安卓低中高端 8 台 + iOS 3 台 + 测试机
外包美术/音效 15–30 万 10 关卡的场景、UI、音效
模型与 API 2–5 万 编码 Agent + 生图 + 生成式音频
软件与云服务 3–6 万 CI runner、CDN、云真机、设计工具
备用金(15%) 18–27 万 不解释用途
合计 140–210 万 落在 05 号文档"150–300 万"区间下沿

这个数字的意义是判断可行性,不是预算书。 如果只能拿出 50 万,正确做法是把 P0 缩到 §12 的单人 MVP,而不是砍架构——砍架构省不下钱,只会让后面重做。


12. 三种降级方案(计划失效时用)

计划的价值有一半在"提前想好怎么缩"。以下三个方案预先定义,触发即执行,不再讨论。

方案 触发条件 范围 周期 产出
A. 基准 默认 全部 13 个迭代 26 周 上线游戏 + 完整引擎
B. 单人 MVP 人力 <2 人 或 预算 <60 万 砍 Studio(用文本编辑 MIR)、砍 Agent 自动生成(人工写 MIR)、只做 1 个关卡 12–16 周 能上线的小游戏 + 引擎核心
C. 只做工具 AI 生成采纳率连续 2 迭代 <40% 停止引擎开发,把 Agent + MIR 做成"跑在 Cocos 上的内容生成工具" 8 周 保住 AI 生产效率,放弃自研运行时

方案 C 听起来像失败,其实是最优止损。 如果 AI 的价值在内容生产而不在运行时,那么把 AI 挂到成熟引擎上,是投入产出比最高的形态——而且这条路今天就能走。


13. P1/P2/P3 的季度级计划

P1(2027-05 → 2028-04,12 个月)

季度 主题 里程碑
Q1 3D 渲染基础:Clustered Forward+、PBR、级联阴影 3D 场景跑通,中端机 30fps
Q2 Metal 后端(Tier1)+ compute 路径 + 蒙皮动画 M6:GPU 粒子跑通
Q3 物理集成、材质图编辑器、Perf Agent M9:Perf Agent 首个被采纳的优化 diff
Q4 抖音端 + MIR schema v1 冻结 + 双端上线 M12 上线,M15 schema 冻结

P2(2028-05 → 2029-10,18 个月)

季度 主题
Q1–Q2 Virtual Geometry(Tier1 软件光栅版)+ SDF-DDGI
Q3 Character Stack(皮肤/毛发/眼球)+ D3D12 后端
Q4 PC 端上线 + 构建农场 + 多人协作
Q5–Q6 主机移植冒烟(Xbox ID@Xbox 先行)+ HWRT-DDGI

P3(2029-11 起)

主机正式认证、大世界流式、运行时 AI(NPC/叙事)、商业化三选一(授权 / 云烘焙 / 垂直方案)。

P1 之后不再做详细计划。 12 个月后的细节一定会错,写细了只会让人误以为可控。P1 只做季度级,每季度末重排下季度。


14. 这版计划里最可能错的三处

诚实地标出不确定性,比假装精确有用:

  1. S8 包体攻坚的 2 周可能不够。 若 S7 结束主包已 >6MB,S8 需要扩到 4 周,直接从缓冲里扣,并砍 S9 的关卡数(10 → 6)。
  2. Agent 闭环(S5)可能拖到 S8。 这是全项目最不确定的部分。缓解:把 Guardian 校验器先做完(它是确定性的,好做),生成质量靠 prompt + 模板迭代,不追求一次到位。
  3. Studio(S6–S9)的 8 人周偏乐观。 Tauri 的离屏纹理共享在 macOS/Windows 上都有坑。若 S6 结束视口仍不通,降级为"弹出独立渲染窗口",不阻塞主线。

15. 一句话

这份计划的骨架是"三不可压缩 + 一个中间缓冲":包体、真机、审核三件事没法加速,所以它们必须早开始、占满 S8–S11;缓冲放在 S9–S10 之间而不是最后,因为最后的时间一定会被功能吃掉。

计划的成功不看"是否按期完成全部功能",而看Gate 0 的六项指标能不能用数字回答。

13 个双周迭代的逐条任务与人日、DoD、前 10 个工作日排班

10 · P0 迭代执行计划(26 周 / 13 个双周迭代)

09 号是总计划,回答"分几段、门在哪"。 这一份是排班表:每个迭代做什么、多少人日、什么算做完。

容量口径:每迭代 4 人 × 10 工作日 = 40 人日,按 85% 利用率 → 可承诺 34 人日。 表内人日合计 ≈ 34/迭代,超出即代表该迭代已经排满,不能再加需求。


0. 怎么用这份文档

  1. 周一看这张表:把本迭代的"任务"栏拆成这周的 5 件事,写进承诺清单。
  2. 周五看 DoD:DoD 的每一条都必须是能演示或能跑脚本验证的,不能是"基本完成"。
  3. DoD 不达标不要进下一个迭代——宁可砍本迭代范围,也不要带着半成品往前走。带病前进的债,在 S8 会以"包体超 900KB""帧时间抖 10ms"的形式一次性还回来。

人日口径:1 人日 = 1 个有效工作日(不含会议)。A=架构/编译链,B=引擎/渲染,C=工具/平台,D=TA/内容。


1. 迭代总表

迭代 周 主题 人日 里程碑
S0 W1–2 工程基线与语言决策 33 D0
S1 W3–4 MIR v0 35
S2 W5–6 编译链骨架 + 首个 RHI 35 M0.2
S3 W7–8 ECS + 2D 渲染 34
S4 W9–10 音频与资源流式 34
S5 W11–12 Agent 闭环 v0 33
S6 W13–14 Magic Studio v0 34
S7 W15–16 垂直切片 33 M0.3
S8 W17–18 包体攻坚 33 M0.5
S9 W19–20 内容量产与资产库 33
S10 W21–22 稳定性与兼容 34 M0.6
S11 W23–24 上线准备 30
S12 W25–26 上线与 Gate 0 32 Gate 0

缓冲(20 人日)不占日历周:它是每个迭代"40 人日容量 − 34 人日承诺 = 6 人日"里的一部分,分布在 S8–S11 优先使用。哪条线告急给谁,分配顺序固定为 包体 → 真机兼容 → Agent 质量。详见 09 号文档 §7.1。

工时账对得上:上表 13 个迭代合计 433 人日(≈86.6 人周);每迭代承诺 34 人日 × 13 = 442,余 9 人日。每迭代另有 6 人日未承诺(共约 78 人日 ≈ 15.6 人周),用于会议、联调、Code Review 与缓冲,正好对应 09 号文档的"过程开销 12 + 缓冲 4 = 16 人周"。 如果某个迭代排入超过 34 人日,说明它已经超载——砍范围,不要借钱。


2. S0(W1–2)工程基线与语言决策

目标:在写下 5 万行代码之前,确认三件事——wasm 能进微信、Rust 能调 C++、构建是确定性的。

# 任务 人日 主责 依赖
1 仓库骨架 + Rust workspace(9 个 crate)+ 目录约定 2 A —
2 CI 三目标构建:host / wasm32-unknown-unknown / aarch64-apple-ios 3 A 1
3 wasm 最小运行时:WebGL2 context + 三角形 4 B 2
4 微信开发者工具最小工程:加载 wasm 并上屏 3 C 3
5 me-rhi/ffi.h 设计 + C++ dummy 后端(模拟 GNM 的对象式接口) 5 A —
6 Rust → C ABI → C++ 冒烟:三角形 + 调用开销测量 4 A+B 5
7 确定性构建基座:SOURCE_DATE_EPOCH、稳定排序、确定性 RNG 3 B 2
8 me CLI 骨架(build / fmt / validate 占位) 3 C 1
9 MIR schema v0 草案(SceneGraph 子集,约 40 个节点类型) 4 A —
10 工程规范 + PR 模板 + AI commit 规则(§R-AI-1~3) 2 C —

交付物:可构建的仓库、三目标 CI、FFI 冒烟测试报告、MIR schema v0 草案、规范文档。

DoD

风险:微信开发者工具对 wasm 的限制(体积、SIMD、内存上限)。若 800KB 达不到,先记录数字继续走,包体优化放 S8——但不能因此放弃"包体从 S2 就画曲线"这条纪律。


3. S1(W3–4)MIR v0

目标:让"场景"成为一种可读、可 diff、可往返验证的文本程序。

# 任务 人日 主责 依赖
1 文本语法定稿(块语法 + 稳定属性顺序,不用 S-expression) 3 A S0-9
2 parser:手写递归下降,错误带行列号与修复建议 5 A 1
3 AST → 强类型 IR(schema 驱动代码生成) 4 A 1
4 规范化序列化器(排序规则、浮点格式、转义规则) 4 A 3
5 二进制 mirb(版本头 + 零拷贝 + 可 mmap) 4 A 4
6 往返校验 + 属性测试(proptest ≥1000 用例) 3 B 5
7 me fmt / me validate 实装 4 C 4
8 校验规则首批:引用完整性、类型、循环依赖、预算字段合法性 3 A 3
9 示例场景 12 个(覆盖 2D 全要素:精灵/文本/九宫/层级/九层遮罩) 3 D 7
10 MIR 语法手册(20 个节点类型 + 10 个反例) 2 C 1

DoD

为什么不用 S-expression:MIR 要被人和 LLM 同时读写。S-expr 对机器友好、对人可读性差,且 diff 时嵌套层级难对齐。块语法 + 稳定排序,diff 噪声最小——这条直接影响 AI 改动的可 review 性。


4. S2(W5–6)编译链骨架与第一个真实渲染闭环

目标:打通 .mir → 屏幕,并让"预算"第一次真正拦住东西。

# 任务 人日 主责 依赖
1 pass 框架:注册、依赖、单独运行、逐 pass 日志 4 A S1
2 legalize:Tier0/Tier1 能力表 + 首批降级规则 5 A 1
3 budget:树形分配、父子借贷、超限定位到节点 5 A 1
4 lower:2D 场景 → 绘制列表 + 图集分配 4 B 1
5 RHI WebGL2:buffer / texture / pipeline / draw / command buffer 6 B S0-6
6 着色器生成器 v0:材质节点 → GLSL(全程无手写) 4 B 5
7 link/pack:单包最小产物(本迭代不做分包) 3 C 4
8 预算错误 UX:文案 + 建议("删 3 个装饰物可满足") 2 C 3
9 基准场景 3 个(10 / 100 / 1000 sprite) 2 D 7

DoD

风险:着色器生成器容易滑向"半个 Shader Graph"。本迭代只支持 5 种材质节点(常量、贴图、乘法、lerp、UV 变换),够用即可。


5. S3(W7–8)ECS 与 2D 渲染器

目标:运行时骨架成型,且性能数字是可测的。

# 任务 人日 主责 依赖
1 archetype 存储 + 组件注册 + 句柄表 5 B S0
2 HierarchyIndex(父子稀疏数据)+ 变换传播 4 B 1
3 系统调度器:静态依赖图 + 单线程时间切片(2ms 预算) 4 B 1
4 内存模型:FrameArena / AssetHeap / Persistent 3 B 1
5 2D 批处理渲染器:排序、合批、状态缓存 5 B S2-4
6 图集打包工具 + 运行时图集切换 4 C S2-7
7 文本渲染:位图字体 + 动态字形缓存 3 C 5
8 输入系统 + 微信触摸适配 3 C —
9 性能基准 + 自动回归阈值(±5% 报警) 3 B 5

DoD


6. S4(W9–10)音频与资源流式

目标:让场景"有声音、能切换、不白屏",并把 SfxForge 接到运行时。

# 任务 人日 主责 依赖
1 轻量混音器:16 通道、总线、距离衰减、单声道定位 4 C S3
2 wasm DSP 最小集:噪声/滤波/包络/混响(复用 SfxForge 配方) 5 C 1
3 音频管线:配方 → 烘焙 ogg 或运行时合成(按包体预算自动选) 3 C 2
4 场景音景:分层音床 + 随机变体调度 3 C 2
5 资源系统:AssetHandle、引用计数、按分包粒度整体卸载 5 B S3-4
6 流式加载:占位资产 → 渐进精化 + 相邻分包预下载 5 B 5
7 微信 PAL:FS、网络、分包加载 API 4 C —
8 场景切换:无白屏(<300ms,含资源预热) 3 B 6
9 音频 CPU 预算测量(16 通道同时播放) 2 B 1

DoD

音频这块有一条纪律:生成式音频(08 号文档)只做工具期烘焙,运行期零推理。 一段 20s/48kHz 立体声未压缩 3.8MB,超过整个主包预算。


7. S5(W11–12)Agent 闭环 v0

目标:AI 第一次能产出可编译、可 review、可回滚的 MIR。

# 任务 人日 主责 依赖
1 Agent 运行时骨架:Intent → Task DAG → 执行器(可中断/重试) 4 A S2
2 Planner:意图 → 任务分解(prompt 模板带预算约束) 4 A 1
3 Builder:MIR patch 生成(schema 约束解码,不允许自由文本) 5 A S1-3
4 Guardian:确定性校验器(不调模型),20 条规则 4 A 3
5 Patch 应用器:三方合并 + 冲突检测 + 单步回滚 3 A 3
6 Provenance:seed / model_version / recipe_hash + 一条复现命令 3 A 5
7 AI Workbench 最小界面:意图输入、MIR diff、渲染前后对比 5 C —
8 评测集:20 个生成任务 + 人工评分标准(可接受/需修改/不可用) 3 D —
9 --no-ai 复现开关 + 回归测试 2 B 6

DoD

这是全项目技术风险最高的一环。 缓解办法是顺序:先做 Guardian(确定性,好做),再做 Builder(难)。如果 Builder 质量不达标,Guardian 仍然有用——它能拦住其他所有来源的错误。


8. S6(W13–14)Magic Studio v0

目标:编辑器能替代文本编辑,且"看到的 = 玩家看到的"。

# 任务 人日 主责 依赖
1 Tauri 壳 + React 布局 + IPC(MessagePack) 5 C —
2 me-studio 服务:文档模型 + 命令栈(undo/redo) 5 C 1
3 视口:引擎离屏渲染 → 共享纹理(macOS 优先) 6 B S3-5
4 场景树 + 拖拽 + 多选 4 C 2
5 Inspector:MIR 节点属性编辑(所见即 MIR) 4 C 2
6 热重载 L1:材质/光照参数 <50ms 3 B 3
7 热重载 L2:结构变更 <300ms,实体按 id 映射 4 B 6
8 构建发布面板:一键构建 + 包体分析 3 C S2-7

DoD

已知风险(预先定好降级):Tauri 的跨进程共享纹理在 macOS/Windows 都有坑。若 S6 结束视口仍不通,降级为"弹出独立渲染窗口"——牺牲一体化体验,保住主线,S9 再回来补。


9. S7(W15–16)垂直切片与 M0.3

目标:第一次完整的"能玩",并让真机性能可归因。

# 任务 人日 主责 依赖
1 玩法框架:状态机、关卡流程、结算 5 D S6
2 关卡 1–3:手工 + AI 混合生产 6 D 1
3 UI 层:HUD、菜单、弹窗 4 C 1
4 真机 profile 隧道:WebSocket trace → 编辑器 5 B —
5 归因:draw call → MIR 节点链 4 B 4
6 存档 / 设置(本地存储 + 跨端) 3 C 1
7 首次真机全流程测试 + 问题清单 3 D 2
8 性能预算热力图 v0(编辑器内高亮超预算节点) 3 C 4

DoD


10. S8(W17–18)包体攻坚与 M0.5

目标:把主包压进 4MB,把首帧压进 3 秒。这是全项目最不可压缩的一环。

# 任务 人日 主责 依赖
1 纹理压缩管线:ASTC / ETC2 + 质量档 + 按用途自动选 5 B S7
2 wasm 体积:wasm-opt -Oz、panic=abort、no_std 子集、去 fmt 5 B S0-3
3 音频:opus 低码率 + 大文件改运行时合成 3 C S4
4 分包图划分:按场景可达性做图划分(最小割近似) 5 A S4-6
5 包体分析器:按模块/资产类型归因,输出可执行建议 4 C —
6 首帧优化:首场景最小化 + 占位资产 + 并行下载 5 B 4
7 真机安装验证 5 台(含最差机型) 4 D 1
8 冷启动埋点(分段计时:wasm 加载/初始化/首场景) 2 C 6

DoD

纪律:包体曲线从 S2 就要画。如果 S7 结束时主包已经 >6MB,S8 需要 4 周 → 从缓冲扣 1 周 + S9 关卡数 10→6。


11. S9(W19–20)内容量产与资产库

目标:把"AI 能生成一个关卡"变成"AI 能生成十个关卡且质量稳定"。

# 任务 人日 主责 依赖
1 世界语法 v0:8 条布局规则(乡村 / 小镇 / 室内各一组) 5 D S6
2 构件库 v0:120 个构件 + 元数据(结构规格 + 语义标签) 5 D —
3 资产库双索引:语义向量 + 结构规格过滤 5 A 2
4 规范化闸门:重拓扑/UV/单位朝向/LOD/材质烘焙 + 拒绝原因 5 B 2
5 关卡生成器:语法 + 构件 + 预算约束 → MIR 5 A 1,3
6 关卡 4–10 生产(AI 生成 + 人工 review) 5 D 5
7 采纳率统计脚本(按 MIR 节点数,非人工估算) 3 C —

DoD

冷启动现实:库 <500 个资产时,智能复用会空转。所以这一迭代的重点不是"库大",而是"配方优先"——8 条世界语法带来的变化量,远大于 120 个孤立的模型。


12. S10(W21–22)稳定性与兼容

目标:把"能玩"变成"能上线"。

# 任务 人日 主责 依赖
1 5 台真机兼容矩阵(3 安卓低中端 + 2 iOS) 6 D S8
2 崩溃收集 + 符号化(wasm 栈还原) 4 C —
3 内存排查:30 分钟循环 + heap 快照 diff 5 B —
4 低端机降级:动态分辨率 + 画质档位下发 4 B 1
5 弱网 / 断网 / 后台切换 / 来电中断 3 C —
6 留存埋点 + 漏斗(进入/过关/失败/退出) 3 C —
7 压力测试:连续 100 次场景切换 3 B 3
8 Bug 修复缓冲 6 全员 1–7

DoD


13. S11(W23–24)上线准备

目标:过审、灰度、可回滚。这一迭代的外部依赖最多,必须留足时间。

# 任务 人日 主责 依赖
1 隐私协议、用户协议、权限最小化 3 D —
2 审核自查(微信审核要点逐条)+ 整改 5 D —
3 广告 SDK + 激励视频(如采用 IAA 模式) 4 C S10
4 埋点校验 + 后台看板 4 C S10-6
5 灰度方案:5% → 20% → 100% + 回滚预案 3 A —
6 提审 + 应对驳回(预留 2 轮) 6 D 2
7 运营素材:icon / 截图 / 简介 / 分类 3 D —
8 客服与反馈通道 2 D —

DoD

审核是黑盒。唯一有效的应对是"提前一轮"——不要等 S11 才第一次提审。


14. S12(W25–26)上线与 Gate 0

# 任务 人日 主责 依赖
1 全量发布 + 监控值守(前 72 小时) 5 D S11
2 留存与漏斗分析(7 日) 4 D 1
3 工时台账汇总 + 与 Cocos 路线对比测算 5 A —
4 六项指标核对表(每项给出数字与采集方式) 4 A 1–3
5 Gate 0 评审报告 + P1 范围建议 6 A 4
6 技术债清单 + 架构复盘(哪条 ADR 要改) 4 B —
7 文档收尾:MIR 手册、构建手册、FAQ 4 C —

DoD


15. 每个迭代的固定检查点

时点 检查 不合格的动作
周一 承诺清单 ≤5 项,每项有验收方式 超过 5 项 → 砍到 5 项
周三 中期检查:是否出现"预计延期" 出现即上报,不等到周五
周五 Demo(只演示能跑的)+ 8 指标更新 演示不了 = 没做完
迭代末 DoD 逐条勾选 有未勾选 → 不带入下迭代,砍范围

15.1 连续两个迭代完成率 <70% 时的强制动作

按顺序执行,不再讨论:

  1. 砍掉本阶段"可以后补"清单里最上面的一项(见 04 §9 右列)
  2. 若仍不足,砍内容量(10 关 → 6 关)
  3. 若仍不足,触发 09 §12 方案 B(单人 MVP)或方案 C(只做工具)

不允许的应对方式:延期、加人、降低 DoD 标准。前两个在这个阶段无效,第三个会让 Gate 0 失去意义。


16. 前 10 个工作日(S0 逐日)

这一段最值得写细,因为它是唯一"下周就要执行"的部分。

日 A(架构/编译链) B(引擎/渲染) C(工具/平台) D(内容)
D1 仓库骨架、workspace、目录约定 读架构文档,列 RHI 接口草案 微信开发者工具环境搭好 确认首个项目的玩法方向
D2 CI 三目标构建 wasm + WebGL2 三角形 微信最小工程跑通 玩法原型纸面推演
D3 ffi.h 第一版 三角形上屏调通 wasm 加载进微信 关卡结构草案
D4 ffi.h 评审 + C++ dummy 后端 调用开销测量脚手架 me CLI 骨架 美术需求清单
D5 C++ dummy 后端完成 确定性构建基座 CLI 接入 CI 资产采购/外包询价
D6 FFI 冒烟:Rust→C++ 三角形 修确定性(时间戳/路径/顺序) PR 模板 + 规范文档 12 个示例场景规划
D7 冒烟通过 + 开销数据 二次构建 hash 对比 微信包体基线测量 示例场景 1–3
D8 MIR schema v0(节点类型 1–20) wasm 体积基线 + 优化试验 me fmt 设计 示例场景 4–6
D9 MIR schema v0(21–40) 体积报告 me validate 设计 示例场景 7–9
D10 D0 评审材料 D0 评审材料 D0 评审材料 示例场景 10–12

D10 的评审只需要回答一个问题:要不要按这个语言组合往下写 5 万行代码。


17. 一句话

这份排班表唯一的硬规则是"DoD 不达标不许进下个迭代"。 13 个迭代里有 3 个(S8 包体、S10 兼容、S11 审核)受外部约束、无法靠加班压缩,所以它们必须准点开始;其余 10 个都可以通过砍范围来保时间。 砍范围不丢人,带病前进才丢人。

四类冲突、扇区模型、crate 内分权、共享面设计、并发度曲线、同步协议、守卫脚本实测

11 · 四 Agent 并行开发:扇区模型

09 号是总计划,10 号是排班表,这一份解决「四路并行怎么不互相踩」。

一句话结论:撞车的主因不是模块没拆好,是"拆到目录级"停手了。 目录拆完,每个目录内部还有共享文件;而共享文件才是撞车的唯一物理来源。


1. 先说清楚:撞车有四种,只有一种是 git 会报警的

类型 现象 git 会报冲突吗 为什么"按模块拆"治不了
① 同文件双写 两人同时改 Cargo.toml / mod.rs / 索引文件 会 模块拆分不改变"这个文件只能有一个作者"的事实
② 契约漂移 没人冲突,但 A 改了 schema,B 编译不过 不会 最阴的一类。等编译报错时,B 已经写了 200 行"临时适配"
③ 产物污染 target/、生成物、site/ 互相覆盖 不会 谁都不认为自己在改产物,但清理动作会
④ 语义重复 两个人各实现了一份 ResourceLoader 不会 目录不同、名字不同、功能一样,合并时才发现

你过去遇到的"那个模块没拆分好",绝大多数是 ② 和 ④。 它们的共同点是:git 全程安静,直到某一天突然全炸。

所以真正的解法不是"把模块拆得更细",而是四件事:

  1. 文件所有权(治 ①③)——每个路径只有一个 owner,机读、可断言
  2. 契约冻结(治 ②)——接口文件带版本号和哈希,改了必 bump
  3. 构建隔离(治 ③)——每个 Agent 一个 worktree、独立 target/
  4. 越界自动检测(治全部)——脚本判定,不靠自觉

2. 扇区,而不是模块

模块(crate)不等于扇区。 扇区是"写权边界",一个扇区可以跨多个 crate,一个 crate 也可以被两个扇区按文件切开。

最典型的例子是 me-rhi:

crates/me-rhi/src/ffi.h        → A1(C ABI 定义)
crates/me-rhi/src/abi.rs       → A1
crates/me-rhi/src/lib.rs       → A2(实现)
crates/me-rhi/backends/**      → A2(各后端)
crates/me-rhi/Cargo.toml       → A2

为什么必须这样切:C ABI 一旦由实现方自己定,主机 SDK 那一层(GNM / GDK,全 C++ 且受 NDA)就再也换不动了。这不是洁癖,是 ADR-001 里那条"语言可换"的前提。

按 crate 拆的话,这条约束根本无法表达——这就是"模块拆了还是会撞"的具体机制。


3. 四个扇区

Agent 代号 职能 核心产出 谁依赖他
A1 kernel 内核与编译链 interface/**、MIR、编译器、me-core 全部
A2 runtime 运行时与渲染 RHI 后端、ECS、2D 渲染、音频 A4
A3 tools 平台与工具链 PAL、CLI、Studio、构建与 CI 全部
A4 content 内容与验证 世界、资产库、测试、发布验证 无(他是消费者)

依赖是单向的:A1 定义 → A2/A3 实现与消费 → A4 使用。A4 在链条末端,全靠反馈说话。

A4 有一条硬规则:一行引擎代码都不许改。 他改不动的地方,就是接口设计有缺陷的证据。如果他能随手改引擎让它跑通,这个缺陷会一直留到第三方开发者手里。

这条规则把"撞车"转成了"信号"——这也是四个角色里唯一"越被动越有价值"的设计。

四个 Agent 的完整扇区定义(含可写 glob、只读区、禁区、每迭代 FTE)在 plan/agents.json,是机读的唯一事实源。


4. 把"必然共享"设计掉——减少 90% 冲突的真正手段

大部分共享文件是可以被设计掉的,只是没人愿意在第一天做。这六条做完,冲突从"每次提交都可能撞"降到"少数真冲突":

# 手法 消灭哪一类冲突
1 根 Cargo.toml 用 members = ["crates/*"] "新增 crate 必改根文件"
2 mod 声明由 build.rs 生成到 src/generated/ "两个人都要往 lib.rs 加一行 mod"
3 注册表分片:一目录一文件,启动时扫目录 "三个人的组件都注册在同一个数组里"
4 索引与产物一律脚本产出(进 forbidden) 手改生成物后又被脚本覆盖
5 CHANGELOG.md 按日期分区 append 整文件重写导致的整段冲突
6 trait 与 impl 分文件 接口定义和实现抢同一个文件

第 1 条最容易被忽略,但它消灭的是最高频的那类冲突。 目录结构永远比文件内容稳定——把"变化的东西"放进目录,把"稳定的东西"放进文件。


5. 并发度:四个 Agent 不等于四个同时在跑

关键路径本身是串行的。S0 阶段 A3、A4 如果硬要开工,只能做无效功——因为骨架还没出来。

按 plan/agents.json 的 FTE 分配实测(每迭代 10 个工作日,预算 = 人日/10):

迭代 预算 FTE A1 A2 A3 A4 合计 同时活跃
S0 3.3 1.3 1.0 0.8 0.2 3.3 3
S1 3.5 1.5 0.9 0.8 0.3 3.5 3
S2 3.5 1.0 1.5 0.7 0.3 3.5 3
S3 3.4 0.6 1.4 1.0 0.4 3.4 4
S4 3.4 0.3 1.4 1.0 0.7 3.4 3
S5 3.3 1.1 1.0 0.7 0.5 3.3 4
S6 3.4 0.5 1.0 1.3 0.6 3.4 4
S7 3.3 0.2 1.1 0.7 1.3 3.3 3
S8 3.3 0.2 1.3 0.5 1.3 3.3 3
S9 3.3 0.2 0.8 0.8 1.5 3.3 3
S10 3.4 0.5 1.2 0.5 1.2 3.4 4
S11 3.0 0.3 0.7 1.0 1.0 3.0 3
S12 3.2 0.3 0.5 1.1 1.2 3.1 3

("活跃" = FTE ≥ 0.4。全部 13 个迭代合计 43.2 FTE·迭代,预算合计 43.5,无超支。)

结论:四个 Agent 同时有实质任务的窗口只有 S3、S5、S6、S10 四个迭代,共 8 周。 其余 18 周都是 2–3 个。

这不是排期偷懒,是盲目四并发反而更慢:多出来的那个 Agent 要么在等接口,要么在写后来要推翻的东西。开四个对话之前先看这张表——多数时候你只需要开三个。


6. 同步协议:四个节奏

节奏 动作 谁做 不做的后果
每次提交 check_ownership.py files --as <id> 各 Agent 自己 越界累积到合并时才爆
每天开始 git rebase 到主干,跑一次构建 各 Agent 分支活过 3 天,合并成本翻倍
契约变更时 改 interface/ + bump 版本 + 更新 MANIFEST + 通知消费方 契约 owner 静默漂移,消费方编译期踩雷
每周一次 集成窗口:全员 rebase + 全量构建 + 跑 tests/ A3 主持 只在最后集成 = 一次炸四个

契约提案是唯一允许的跨扇区通道。 流程固定四步:

  1. 提出方写清:要改哪个文件、加什么、为什么本扇区解决不了、影响多少处调用点
  2. owner 决定:接受(bump 版本)/ 拒绝(给替代方案)/ 延后(进 backlog)
  3. 接受了:owner 改 interface/ + MANIFEST.json 的 version 与 sha256
  4. 消费方同步升级,编译器断言版本号

没有第 5 步"我先在自己这边临时改一下"。 那一步之后两份接口就永久分叉了。


7. 开工:四个对话怎么开

# 1. 每个 Agent 一个独立 worktree(共用 .git,互不干扰)
cd /path/to/magic-engine
git worktree add ../me-A1 -b agent/A1
git worktree add ../me-A2 -b agent/A2
git worktree add ../me-A3 -b agent/A3
git worktree add ../me-A4 -b agent/A4

# 2. 每个 worktree 独立构建目录,不抢 target/ 锁
export CARGO_TARGET_DIR=/tmp/me-target-A1   # A2/A3/A4 同理

为什么必须 worktree 而不是同一个目录切分支:同一个工作目录下切分支,会把别人未提交的改动一起带走——这是最隐蔽也最致命的一种"撞车"。

然后四个对话分别粘 plan/agent-briefs/ 下对应的那份。简报是自包含的,因为新对话没有上下文。

开对话的顺序:先 A1、A3(S0 关键路径在 A1,共享设施在 A3),S2 再加 A2,S3 再加 A4。不要第一周就开四个。


8. 守卫脚本:tools/ci/check_ownership.py

三个检查,全是确定性判定,plan/agents.json 是唯一事实源。

python tools/ci/check_ownership.py files --as A2 --git   # 越界断言
python tools/ci/check_ownership.py contracts             # 契约静默漂移
python tools/ci/check_ownership.py dupes                 # 跨 crate 同名符号

匹配规则:取"最具体"(非通配字符最多)的那条 glob,所以 crates/me-rhi/src/ffi.h(A1)能压过 crates/me-rhi/src/**(A2)。判定顺序是 forbidden → generated → shared → owned → unowned。

实测结果(真跑,非设计意图)

场景 输入 结果
A2 顺手改了 C ABI interface/rhi.ffi.h + 自己的后端 FAIL 属于 A1,退出码 1
A4 改了引擎代码 crates/me-runtime/src/ecs.rs FAIL 属于 A2,退出码 1
同一 crate 内分权 me-rhi 的 5 个文件 ffi.h/abi.rs → A1,其余 → A2,全部 ok
生成物 library/sfx/index.json、ogg/** note 生成物:须由脚本产出(不 FAIL,见局限)
纯本地产物 target/**、library/sfx/wav/** FAIL 纯本地产物,永不进版本控制
新目录未登记 crates/me-net/src/lib.rs warn 未注册扇区
契约静默漂移 往 rhi.ffi.h 追加注释、不 bump DRIFT,退出码 1,sha256 从 ff2eec… 变为 e8d503…
还原后 git checkout -- interface/rhi.ffi.h sha256 回到 ff2eec…,通过:无静默漂移

真实仓库的覆盖验证

假的路径测一百遍,不如拿真仓库跑一次。首次提交 80 个文件跑下来,当场暴露两个设计错误:

错误一:把"进版本控制的生成物"放进了 forbidden。 初始提交合法地新增了 31 个 ogg 和 index.json,却被判 33 处 FAIL。 根因是把"不许手改"和"不许提交"混成了一件事。修正后语义分开:

错误二:仓库根的基础设施文件没登记。 .gitignore、.gitattributes、build_site.py 全部 warn 未注册扇区。 修正后归 A3(构建设施)。

修正后:80 个文件 → 42 ok + 38 note,0 FAIL,0 warn。

过程中的真实缺陷修复:--base main 原本被实现成 git diff main HEAD,比较的是两次提交而不是"工作区 vs 基线",所以提交前自检永远返回空集。改成 git diff main 后才真正可用——这类 bug 只有真跑才会出现,纯看代码看不出来。

过程中修掉一个真实缺陷:library/sfx/index.json 最初被判给了 A4 的 library/**,因为生成物判定排在归属判定之后。顺序错了,生成物就会被当成"可手改"——这是最隐蔽的一类污染源。修正后 generated 提前到 owned 之前。

已知局限(不掩饰)


9. 什么时候说明拆分错了

四个可观测信号。出现任意一个,先改扇区划分,不要再加 Agent:

信号 具体阈值 说明什么
契约提案频繁 一周超过 2 次 扇区切在了不该切的地方,把该归一个人的东西拆开了
越界反复 同一文件连续 2 周被 2 个 Agent 越界 agents.json 写错了,不是纪律问题
集成持续失败 连续 2 个集成窗口构建不过 共享面还没设计掉,第 4 节那六条没做完
等待时间上升 任一 Agent 每周 > 1.5 天在等上游 依赖方向错了,或有扇区应该合并

"多开一个 Agent"从来不是解药。 四个扇区对应四条真实依赖链,第五条链不存在——多开的那个只会制造冲突。

一条补充规则:架构角色不计入扇区

扇区定义本身(plan/agents.json、docs/、共享骨架、CI 守卫)由架构角色写,它不参与四路并行。

但这条必须收紧使用:一旦进入日常开发,架构角色的改动也要交回对应扇区 owner。 否则守卫会退化成"有例外的人"——那比没有守卫更糟,因为它给越界提供了一个永远可用的借口。

写这份文档时守卫就抓到了我自己一次:tools/ci/check_ownership.py 按扇区属于 A3(构建设施),我以 A1 身份写它被判定越界。这恰好说明规则是有效的——它没有因为作者是"制定规则的人"就放过。

Rust 内核 + C++ RHI 后端

ADR-001:内核语言选择 —— Rust 内核 + C++ RHI 后端

Status

Proposed(有条件接受,需 P0 第 8 周完成 FFI 冒烟测试后转 Accepted)

Context

引擎需要同时覆盖:WASM(小游戏)、移动原生、PC、主机。

Options

方案 优势 劣势
A. 纯 C++(UE 路线) 主机最顺、性能天花板最高、招人容易、生态最全 内存安全问题长期累积;编译慢;工具链开发效率低;WASM 产物体积大;无内置包管理
B. 纯 Rust 内存安全、并发友好、cargo 生态、工具链开发极快、WASM 一流支持 主机 SDK 无法直接调用;渲染后端仍需 C++;引擎人才稀缺;学习曲线陡
C. Rust 内核 + C++ RHI 后端(C ABI 边界) 兼顾:工具链/编译器/ECS/Agent 用 Rust(迭代快、安全);渲染后端贴 SDK 用 C++(唯一可行) 跨语言调试成本;需自建 C ABI 绑定层;构建系统双轨

Decision

采用 C:Rust 承担 L5–L8(运行时、渲染器上层、编译器、Agent、编辑器后端),C++ 承担 L3 的 RHI 后端实现(Metal/Vulkan/D3D12/GNM/GNMX/GDK),边界是手写 C ABI(me-rhi/ffi.h)。

约束条件:

  1. C ABI 边界必须极窄:只暴露 command buffer 录制、资源创建、PSO 创建、sync 原语。不做对象级高频调用(避免 FFI 开销)。
  2. 不允许 C++ 侧回调到 Rust 的业务逻辑(除 allocator 与 log)。控制流单向:Rust 驱动,C++ 执行。
  3. P0 第 2 周(S0 的 D0 门)必须完成冒烟测试:在主机 SDK 环境(或伪造的 C++ 后端)上,验证 Rust → C ABI → C++ 后端能跑通一个三角形。

    原定第 8 周,编排 P0 计划时提前到第 2 周。理由:改语言的成本在写第一行业务代码前是 2 周,在 S6 之后是 4 个月——决策越早越便宜,没有理由等。

  4. 若冒烟测试失败或成本超预期,回退到 A(纯 C++),此时 L3 以上的架构文档与 C ABI 设计不变,只替换实现语言。

Consequences

变容易: - 编译链、MIR 解析、Agent 编排这类"逻辑密集"代码的开发速度提升显著(Rust + cargo 的迭代速度约为 C++ 的 2–3 倍) - WASM 产物体积与启动性能更优(无 libstdc++ 拖累) - 内存安全在长期(5 年+)显著降低崩溃率 - 编译器(Rust)能强制模块边界(workspace + crate 可见性)

变困难: - 跨语言调试需要专门基建(gdb/lldb 混合栈、tracing 关联) - 招募:懂 Rust + 图形学的工程师国内稀缺且贵 - 主机平台的构建流程需双轨(Rust 交叉编译 + MSVC/Clang 后端) - 一旦 C 边界设计错了(例如暴露了太细的对象),后期重构成本高

可逆性:中高。 因为边界在 C ABI,语言替换是"重写 L5–L8",不是"重写整个项目"。这是选 C 而非 B 的关键理由——它保留了回退到 A 的路。

附:为什么不用 C# / TypeScript 做内核

wasm32 是一等编译目标

ADR-002:WASM 是一等编译目标(WASM-first)

Status

Proposed

Context

小游戏是 ME 的第一战场(微信 5 亿 MAU,抖音增长快)。而小游戏的运行环境是 WASM + WebGL2 / 原生 Metal(iOS),不是原生二进制。

现有引擎的路径是"AOT 转换":

引擎 小游戏方案 问题
Unity unity-webgl-transform:原生引擎 → WebGL 转换 转换层引入额外开销;il2cpp 产物大;需要大量裁剪;同步 IO 要改异步
Unreal 无官方支持 / 第三方 基本不可行
Cocos TS 原生,天然在 Web 上跑 优势明显,但缺高端渲染能力
Godot Web export,非小游戏定制 社区反馈适配困难

ME 若走"原生优先、再转 Web"的路,会重复 Unity 的所有坑,且无法在 4MB 主包里做出优势。

Decision

从第一天起,wasm32-unknown-unknown(或 wasi 子集)就是引擎的正式编译目标,不是附属产物。

具体约束:

  1. 禁止任何依赖"原生假设"的设计: - 无阻塞 IO(所有资源加载必须异步,哪怕原生平台也一样) - 不依赖 OS 线程做正确性(Job 系统必须支持"零线程退化",用时间切片) - 不使用 C++ 异常做控制流(Rust 侧 panic=abort) - 文件系统抽象为"包 + 虚拟路径",不假设真实目录树
  2. 体积是设计约束而非优化项:主包预算 ≤1.2MB(gzip 后),每次 PR 检查体积回归
  3. 能力分级以"后端能力"为准(compute 有无),不以"平台名"为准,因为微信 iOS 侧已有原生 Metal
  4. 原生平台是另一个编译目标,允许有更多能力,但不允许有不同的语义

Consequences

变容易: - 小游戏端零转换损耗,启动快、包体可控 - 一套代码,多目标编译,无"平台特化分支"技术债 - 天然获得"沙箱友好"的设计(无全局可变状态、无隐式 IO)

变困难: - 原生平台的性能会被"最保守假设"拖累(例如不能随意用线程池)——需要"渐进增强"设计:能力探测 + 可选路径 - 异步化贯穿全引擎,API 复杂度上升(回调/Future) - panic 处理、错误传播需要统一设计(不能靠异常)

不可逆性:高。 这是全项目最不可逆的决策之一,必须在 P0 之前定死。

附:为什么不用 WebGPU 作为统一后端

WebGPU 很强(compute、显式管线),但:

结论:WebGPU 作为 Tier1.5 的可选后端(P2 再评估),不作为主力。

附:为什么不基于 Emscripten + C++(UE 风格)

技术上可行,但: 1. 产物体积难压(4MB 主包下没有余量) 2. GL 胶水层开销(微信已推 Emscripten GLX 模式缓解,但仍不如直接产 WASM + 精简绑定) 3. Rust 的 wasm32 产物更精简、无异常开销

如果 ADR-001 回退到纯 C++,此 ADR 需要重写。

MIR 是唯一真相源,AI 只操作 MIR

ADR-003:MIR 是唯一真相源,AI 只操作 MIR

Status

Accepted(架构基石,除非项目方向改变否则不复议)

Context

"从 0 融入 AI"有多种实现路径,架构不同,天花板也不同:

方案 AI 的操作对象 可 review 可复现 可回滚 跨端
A. 命令式 API 引擎运行时对象(createObject()) ✗ ✗ ✗ 差
B. 直接改资产文件 二进制/blob 资产 ✗ 部分 难 中
C. 操作结构化 IR MIR(文本、带类型、带预算) ✓ ✓ ✓ 好

Decision

  1. MIR 是引擎的唯一真相源。 运行时不接受绕过 MIR 的资产直读。凡是不能表达为 MIR 的东西,AI 就碰不到,也就无法优化——这是刻意的取舍。
  2. Agent 与引擎之间只有三个 API:mir.query / mir.patch / mir.measure。Agent 不得直接调用引擎 API,不得直接写文件。
  3. 所有 AI 产出必须是可 review 的 MIR diff,像 code review 一样过。
  4. Guardian(硬约束校验)必须是确定性代码,不是 LLM。
  5. MIR 节点必须携带三样元数据:budget(预算)、provenance(生成溯源)、id(稳定标识)。

Rationale

为什么可复现如此重要: 如果 AI 生成不可复现,那么三年后没人能维护这个工程——改一个参数,整个场景"重新长一遍",且长出来的不一样。这会让项目变成一次性黑盒。

为什么预算必须在 MIR 里: 如果预算只存在于"目标平台配置"里,AI 就无法在生成时做正确选择,只能生成后被裁剪。局部化预算是"AI 能做对"的前提。

为什么硬约束不能交给 LLM: LLM 有幻觉,且在"看起来对"和"确实对"之间没有可靠界限。一个放过去的坏包就是线上事故。硬约束(引用完整性、预算、变体数、碰撞体闭合)必须是代码。

Consequences

变容易: - 所有 AI 改动可 review / 可回滚 / 可合并 / 可审计 - 多人协作回归正常 git 流程(对比 Unity prefab / UE uasset 的痛苦) - 跨端编译成为可能(MIR 是中间语言,天然多目标) - 测试与 CI 可以做全量静态校验

变困难: - 需要设计一套 MIR schema 及其演进机制(成本高,P1 末必须冻结) - MIR 文本序列化的性能与体积需要优化(不能成为运行期负担 → 所以有二进制形态) - 团队学习成本:开发者要理解"资产即程序" - 所有第三方格式都需要写导入器(不能直接吃 FBX 当运行时资产)

不可逆性:极高。 这是全项目最核心的决策。

双管线共享 Render Graph

ADR-004:渲染管线 —— 双管线共享 Render Graph

Status

Proposed

Context

渲染目标区间跨越 4 个数量级:每帧 5 万三角面(WebGL2 小游戏)到 3000 万+(主机)。

同时,硬件架构有根本差异:

如果用单一管线硬套全平台,结果必然是"两端都不够好"。

Options

方案 说明 问题
A. 统一 Deferred 一套 GBuffer 全平台 移动端带宽爆炸,TBDR 上严重掉帧
B. 统一 Forward+ 一套前向,高端靠叠加 主机上做不了 3000 万面的场景,光照复杂度受限
C. 双管线 + 共享描述层 移动 Forward+,高端 Visibility Buffer;共享 Render Graph 需要两套实现,测试矩阵翻倍

Decision

采用 C,并加三条约束来控制成本:

  1. 两条管线共享同一个 Render Graph 描述接口。pass 声明"读/写哪个虚拟资源 + ms 预算",具体实现由 pass 内部的 backend 分支决定,不在 Graph 层分支。
  2. 管线选择由 MIR 的 target 在编译期决定,不是运行期判断。同一份 MIR,me build --target=wechat-android 与 --target=ps5 产出的 pass 图不同。
  3. 能力分级以"后端能力"为准(compute / indirect / RT 有无),不以平台名为准。

具体分配

Tier 管线 关键 pass
Tier0(WebGL2) Forward + 烘焙光照 depth prepass、forward opaque、透明、bloom、无 TAA(或简易 FXAA)
Tier1(小游戏+Metal) Clustered Forward+ + compute light culling、+ GPU 粒子、+ TAA
Tier2(移动原生) Clustered Forward+ + 稀疏纹理、+ 更好阴影
Tier3/4 Visibility Buffer → Deferred Material + 虚拟几何、+ HWRT GI、+ 体积雾

Consequences

变容易: - 每个平台都能用最适合自己的管线,不互相拖累 - Render Graph 的预算注解让"性能契约"可落地到 pass 级 - 新增平台只需实现一个 backend,不动上层

变困难: - 两套 pass 实现 → 视觉一致性难保证(同一场景在手机上与 PC 上"看起来不是同一个游戏") - 测试矩阵:管线 × 平台 × 画质档位,组合爆炸 - 需要"参考渲染器"(reference renderer,慢但正确)用于对比验证两条管线的视觉偏差

不可逆性:中。 管线选型可以换,但换的成本是重写渲染器。

附:为什么不在 Tier0 上追求 TAA

WebGL2 无 compute,TAA 需要的 velocity buffer + neighborhood clamp 在 fragment 里做代价高,且小游戏端 GPU 弱。Tier0 用 MSAA + 高质量边缘处理,Tier1 起才上 TAA。

但这个取舍有代价:Tier0 的画面会有闪烁。 缓解手段是美术规范(避免高频细节、避免细长几何),这也意味着Tier0 的内容不能直接复用到 Tier3,需要不同的美术策略。这是必须接受的现实。

附:Virtual Geometry 的分层实现

不追求"一次做到 Nanite"。分三步:

  1. P2 初:编译期生成 cluster LOD 链 + CPU 选择(Tier1/2 可用)
  2. P2 中:compute 软件光栅到 vis-buffer(Tier2/3)
  3. P2 末/P3:mesh shader 路径 + 完整 DAG(Tier3/4)

每步都可独立交付价值,不需要"全做完才能用"。

自研渲染与 MIR,集成物理与音频

ADR-005:自研 vs 集成 —— 明确的买/建边界

Status

Accepted

Context

引擎项目最容易死法之一是"什么都自己写"。判断标准只有一个:

这块东西是不是我们的差异化?如果不是,且市场有成熟方案,就集成。

Decision 矩阵

领域 决策 选型 理由
渲染器 自研 — 核心差异化(AI 生成 + 预算编译),必须自研
MIR / 编译链 自研 — 核心差异化,无替代品
AI Agent 层 自研 — 核心差异化
ECS 自研 — 与 MIR/预算深度耦合,且代码量可控
编辑器 UI 框架 集成 Tauri + React 非差异化,生态成熟
物理(3D) 集成 Jolt Physics(MIT) 30 年成熟领域;Jolt 性能优秀、支持多平台、许可宽松
物理(2D) 自研轻量 — 小游戏端要极致小,Jolt 太重
角色控制器 自研 — 手感是游戏性核心,通用方案都不够
音频(中高端) 集成 Wwise / FMOD 主机认证必需,自研无法通过认证
音频(小游戏) 自研轻量 WebAudio 封装 包体约束,Wwise 塞不进 4MB
导航网格 集成 Recast & Detour 成熟、可裁剪、MIT
纹理压缩编码 集成 ISPC Texture Compressor / Basis 编码质量与速度是专门领域,自研不划算
超分 抽象 + 集成 FSR / XeSS / MetalFX 见下
光照烘焙 自研外层 + 集成求解器 自研管线,求解器可接第三方 烘焙管线必须与 MIR/预算打通
序列化 自研 — 与 MIR 同源,用集成库反而绕
动画压缩 自研 — 与 MIR/预算耦合,且算法不复杂
网络同步 P3 再定 — 视 P3 项目需求,不预先设计
视频解码 集成平台原生 — 无差异化

关于超分的特别说明

三个选择:

方案 优点 缺点
自研 TAAU 完全可控、无授权问题、可深度定制 需要 2–3 年积累才能达到 FSR 水平
集成 FSR(AMD,开源 MIT) 免费、跨平台、质量好 主机认证需确认;对特定硬件优化不足
集成 DLSS / XeSS 质量最好(AI 超分) 需要特定硬件;授权与主机认证复杂

决策:做抽象层(me-upscaler),默认集成 FSR,硬件专有方案作为可选插件。

理由:超分不是我们的差异化,但它对"性能+画质"的贡献极大(等效 30–50% 性能)。花 2 年自研是浪费。

风险:主机认证(TRC/TCR)对超分实现有要求,需在 P2 提前确认。

关于物理的特别说明

选 Jolt 而非 PhysX/Bullet/Havok:

引擎 评价
Jolt MIT、C++、性能优秀(比 Bullet 快 2–4 倍)、活跃维护、已被 Horizon Forbidden West 等商业项目使用
PhysX NVIDIA 主导,主机支持需确认,近年重心转向 GPU
Bullet 老、性能一般、维护弱
Havok 商业授权贵,但主机最成熟

若 P3 需要主机级品质与官方支持,可换 Havok——因为物理被封装在 me-physics 接口后,替换成本可控。

Consequences

变容易: - 团队精力集中在渲染 + MIR + AI 三条差异化线上 - 减少 60% 以上的"重复造轮子"工作量 - 成熟组件自带稳定性与工具链

变困难: - 依赖管理与许可合规(MIT/Apache 与商业授权混杂) - 第三方库的 WASM 兼容性需要逐个验证(这是 P0 的真实风险:Jolt 能编到 wasm32,Wwise 不能) - 集成层需要写得足够薄,否则"集成"变成"深度改造",失去集成的意义

关键约束:所有集成组件必须藏在接口后,且接口由我们定义。 否则替换成本会失控。

补缺口而非替换、三分区、冻结字节、限于工具期烘焙

ADR-006: 生成式音频只作为"补缺口",且限于工具期烘焙

Status

Accepted(2026-10-22)

Context

MagicEngine 的音频子系统 SfxForge 已有 12 个程序化配方、31 个资产,能覆盖常规音效 (UI、脚步、门、雨、火、风、虫鸣、爆炸)。但它有三个结构性空洞,配方永远填不上:

  1. 真人声 / 方言 / 叫卖——需要真实录音或语音生成,程序化合成做不到
  2. 人群嘈杂——是几十个弱源的统计叠加,不是几个振荡器能凑出的"密度感"
  3. 独特奇观音——"这一声"必须专家级音效师或生成模型才做得出来

2026 年可用的生成式音频后端已经成熟到可用(Seed-Audio 1.0 出 120 秒 48kHz、 ElevenLabs SFX v2 支持服务端 loop、MOSS-SoundEffect v2.0 是 Apache-2.0)。 于是问题变成:接进来之后,它应该在架构里占什么位置?

有两条路:

Decision

选 B。生成式后端接入为工具期(bake-time)的补缺口通道,并受三条规则约束:

R1 物理隔离。 配方产物在 library/sfx/wav|ogg/(可重建区,逐字节可复现,进 CI); 生成产物在 library/sfx/generated/(冻结区,不可复现)。两者不混放。

R2 冻结字节。 生成资产 deterministic: false + sha256_wav,并提供 verify 命令校验字节未被替换。禁止在 CI 里重新生成来"验证"——同 prompt 两次结果不同, 这条路测不出任何东西。

R3 过同一道闸门。 生成产物必须通过七项硬校验(时长/峰值/直流/循环接缝/声道/ 响度/体积),不通过进 rejected/。入库标准不因"这是花钱生成的"而降级。

同时确定:生成不在运行期发生。

Consequences

变得容易

变得困难

被否掉的选项及理由

A(替换) 被否掉的核心不是质量,是包体。生成音频的体积下限由采样率决定, 配方音频的体积下限由参数决定(可以 0 字节,运行时算)。在小游戏这个首要目标平台上, 这条差距无法用质量弥补。

选 AudioGen / MMAudio 被否掉:权重 CC-BY-NC,商用直接出局。 选 ThinkSound 被否掉:仓库挂 Apache-2.0 但 README 禁止商用,标签与条款冲突, 是最危险的一类。 选 Stable Audio 被否掉:营收 <$1M 的条件许可 + Gemma 条款。自用无妨, 但引擎要交付给第三方客户时,你无法替客户保证营收。 把生成接到运行期 被否掉:见上,包体数学不成立。

备注

许可状态是易腐信息,本 ADR 的结论有效期按季度复核。复核清单: AudioGen 是否改许可、Stable Audio 是否去掉营收阈值、MOSS-SoundEffect 是否上 可用推理端点、火山是否公开书面条款。

判断许可的正确读法是读 LICENSE 与 NOTICE 原文,不是读仓库 badge, 也不是读第三方评测页的摘要。