Add Chromium-only Blender WebEngine parity work
This commit is contained in:
10
docs/status/N-001.md
Normal file
10
docs/status/N-001.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# N-001 Native Depsgraph 安全求值
|
||||
|
||||
状态:`done`(持续回归)
|
||||
|
||||
`empty.blend`、`basic_scene.blend`、`rigged_shape_scene.blend` 已通过 Blender 5.2
|
||||
headless full loader、WASM Depsgraph 和结构化 modifier 报告;frame/pose golden 已加入
|
||||
默认回归。重复求值和发布级内存门仍由 N-008 复核。
|
||||
|
||||
验收:`bash tools/web/check-dual-engine.sh`、`npm --prefix web run test:depsgraph`。
|
||||
|
||||
21
docs/status/N-002.md
Normal file
21
docs/status/N-002.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# N-002 Modifier/Depsgraph 能力矩阵
|
||||
|
||||
状态:`done`(能力矩阵契约)
|
||||
|
||||
当前报告覆盖 modifier UID、堆栈顺序、viewport/render/edit/cage 开关、目标对象依赖和
|
||||
`EVALUATED`/`DISABLED`/`BLOCKED` 结构化状态。跨对象循环返回
|
||||
`MODIFIER_DEPENDENCY_CYCLE`,缺目标返回 `MODIFIER_TARGET_MISSING`。native target 遍历覆盖
|
||||
Array、Mirror、Boolean、Lattice、Curve、Armature、Hook、Mesh Deform、Shrinkwrap、
|
||||
Surface Deform、Screw 和 Displace mapping object。
|
||||
|
||||
本轮继续加入受控 Displace:无纹理、无顶点组、Local Space 的常量 X/Y/Z/Normal 位移与
|
||||
Blender 5.2 golden 一致;纹理、RGB 和 mapping object 返回
|
||||
`MODIFIER_CONFIGURATION_UNSUPPORTED`。Geometry Nodes 白名单从 Transform Geometry 扩为
|
||||
constant-offset Set Position,二者都使用桌面 golden 比较。simulation zone/bake 不执行不确定
|
||||
状态,保留输入几何并返回 `GEOMETRY_NODES_SIMULATION_UNAVAILABLE`。机器门逐项覆盖 Blender
|
||||
5.2 的 0–86 共 87 个类型:27 类进入 native 白名单,60 类保留身份并使用 disabled sentinel,
|
||||
启用时结构化阻断。完整 lazy-function runtime、deterministic simulation cache、Grease Pencil
|
||||
求值不是该能力矩阵的隐含承诺;未来扩白名单必须新增 Blender golden。
|
||||
|
||||
验收:`npm --prefix web run test:modifier-goldens`、`npm --prefix web run test:modifier-cycle`、
|
||||
`npm --prefix web run test:depsgraph`、`npm --prefix web run test:modifier-matrix`。
|
||||
12
docs/status/N-003.md
Normal file
12
docs/status/N-003.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# N-003 骨骼、Shape Key、约束和多帧误差
|
||||
|
||||
状态:`done`
|
||||
|
||||
已修复 Web RNA 浮点属性默认 `0..0` 钳制、显式补齐 headless transform 更新,并统一
|
||||
SceneIR 矩阵为 Blender Python/glTF 使用的列主序展开;animation 和 pose constraint
|
||||
golden 已扩为 frame 1/5/10/15。当前 fixture 使用四根骨骼、独立 Auxiliary 分支、两骨 IK、
|
||||
Copy Rotation、非单位 mesh bind、Armature 对象变换和父级非均匀缩放;每帧同时比较全部
|
||||
pose matrix、constraint target/pole target 和最终蒙皮顶点的最大/RMS 误差。
|
||||
|
||||
验收:`npm --prefix web run test:frame-evaluation`、
|
||||
`npm --prefix web run test:pose-constraint-goldens`。
|
||||
18
docs/status/N-004.md
Normal file
18
docs/status/N-004.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# N-004 Packed Image 覆盖
|
||||
|
||||
状态:`completed_current_scope`
|
||||
|
||||
单 PackedFile 与 PackedFile 列表已覆盖。`image_resource_matrix.blend` 进一步覆盖两个独立
|
||||
asset ID 的 packed UDIM tile、generated image 元数据、缺失外部路径和 linked library;
|
||||
`corrupt_packed_image.blend` 验证 PNG 签名损坏返回 `PACKED_IMAGE_SIGNATURE_INVALID`。
|
||||
SceneIR 公开 `sourceKind`、`assetStatus`、tile、library 和稳定错误码,Worker 可按 tile asset
|
||||
ID 提取字节。
|
||||
|
||||
packed/tile 字节现按 SHA-256 写入
|
||||
`projects/<project>/assets/sha256/<prefix>/<digest>`;重复内容只保留一份,读取时复验长度和
|
||||
摘要,IndexedDB 保存项目级 asset metadata。Storage Worker 重启后可重新列举并读取 OPFS
|
||||
资产。Blender `//` 相对路径会规范化;绝对路径、URI、反斜杠、百分号编码和 `..` 逃逸均以
|
||||
`ASSET_PATH_INVALID`/`ASSET_PATH_OUTSIDE_PROJECT` 阻断。
|
||||
|
||||
验收:`npm --prefix web run test:image-resources`,以及 E2E
|
||||
`content-addresses assets, deduplicates them, and rediscovers them after worker restart`。
|
||||
11
docs/status/N-005.md
Normal file
11
docs/status/N-005.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# N-005 GLB Blender 级往返
|
||||
|
||||
状态:`completed_current_scope`
|
||||
|
||||
Web 严格 GLB 解析和 SceneIR 语义比较保留为快速门。独立回归现在调用项目 TypeScript
|
||||
exporter,随后使用桌面 Blender 5.2 headless importer,比较网格/对象变换、帧 1/25 动画、
|
||||
PBR、显式 sampler、嵌入 PNG/sRGB、morph、双骨骼层级、skin modifier、vertex group 和
|
||||
权重归一化。该门同时修复了 glTF 动画首帧被平移到 0 的问题。
|
||||
|
||||
验收:`npm --prefix web run test:glb-blender-roundtrip`。未来新增 interpolation、相机/灯光
|
||||
或材质扩展时,必须同步扩大该 Blender 语义摘要,不能退回仅解析 Web GLB。
|
||||
30
docs/status/N-006.md
Normal file
30
docs/status/N-006.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# N-006 Blender Main 权威回写与恢复
|
||||
|
||||
状态:`completed_current_scope`
|
||||
|
||||
`setFrame`、`setObjectVisibility`、`setModifierEnabled` 现在直接更新持久化
|
||||
Blender Main;保存通过非 undo 的标准 write-file callback 写出内存 `.blend`。动画与 Pose
|
||||
constraint fixture 已连续执行两代保存/重开,并在 1/5/10 帧比较网格、world matrix 和 bone
|
||||
pose matrix。权威 Main dirty 后的 Depsgraph 现在直接使用 writer 输出,不再回退原始 reader
|
||||
buffer。当前协议命令集中的 frame、visibility、modifier 开关和无 skin/shape-key 的
|
||||
`decimateMesh` 均回写 Main。decimate 会重建三角 Mesh,并保存 UV、corner color 和 material
|
||||
index;Collapse/Un-Subdivide/Dissolve 都经过保存门。带 skin/shape-key 的 decimate 继续保持
|
||||
snapshot-only,保存返回 `BLEND_WRITE_REQUIRES_MAIN_AUTHORITY`,不会丢失 Key/vertex-group 后
|
||||
伪造成功。
|
||||
|
||||
历史项现同时保存 SceneIR 与可重开的 Main buffer;Main 命令 undo/redo 后可立即保存,撤销
|
||||
snapshot-only 状态会恢复权威性。OPFS 保存使用 SHA-256、staging、journal、提交后复验和
|
||||
manifest;新 Worker 可从 staging 后或 scene commit 后两种故障点恢复,并串行化同项目的并发
|
||||
保存。AutosaveScheduler 复用同一事务。N-007/W-080 新增的 Mesh Edit、UV、材质、packed
|
||||
image、动画、约束、层级、Collection、Join/Separate、Apply Transform 和 Origin 已全部复用
|
||||
Main mutation、undo/redo、原子保存和保存重开契约。
|
||||
|
||||
验收命令:
|
||||
|
||||
```bash
|
||||
node tools/web/run-web-engine-smoke.mjs
|
||||
bash tools/web/check-dual-engine.sh
|
||||
npm --prefix web run test:main-roundtrip
|
||||
npm --prefix web run test:authoring-roundtrip
|
||||
WEB_TEST_PORT=5193 npm --prefix web run test:e2e -- --grep "atomic|journal|concurrent saves"
|
||||
```
|
||||
17
docs/status/N-007.md
Normal file
17
docs/status/N-007.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# N-007 建模和 UI 对标
|
||||
|
||||
状态:`completed_current_scope`
|
||||
|
||||
Cube/Plane primitive、独立 Mesh duplicate、delete、完整 TRS、Edit Mode 顶点平移,以及
|
||||
Merge/Dissolve/Extrude/Inset/Bevel/Loop Cut 均直接 mutation Blender Main。结构变化统一通过
|
||||
Main 内存写出再生成 SceneIR,失败会恢复前一历史项;shape key、linked data 和非法选择会
|
||||
结构化阻断。
|
||||
|
||||
UI 已接入视口 raycast、Shift/Ctrl 多选、隐藏对象过滤、删除清理、X/Y/Z 可拖拽 gizmo、
|
||||
Object/Edit Mode、点/边/面选择、Tab/Delete/Shift+D/Ctrl+Z/Ctrl+Y/G/R/S 快捷键。对象层级
|
||||
已覆盖 Parent/Unparent、Collection、新命名、Join/Separate、Apply Transform 和 Origin。
|
||||
材质/UV 与关键帧编辑复用相同 Main/history/save 契约。
|
||||
|
||||
验收:`node tools/web/run-web-engine-smoke.mjs`,以及 E2E
|
||||
`runs Main-authoritative object and edit-mode modeling workflows`,以及
|
||||
`npm --prefix web run test:authoring-roundtrip`。
|
||||
13
docs/status/N-008.md
Normal file
13
docs/status/N-008.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# N-008 发布门
|
||||
|
||||
状态:`done`
|
||||
|
||||
发布门现覆盖 100k 三角形 0.9 Collapse 与 1M 三角形 native 建网格/校验;本机结果分别为
|
||||
86.1s/64MiB 和 0.51s/346,554,368 bytes,默认门限 120s/180s 与 1.5GiB。Chromium、Firefox、
|
||||
WebKit(Safari engine)核心启动、离线资源、SceneIR、非空 WebGL 和 Main 建模全绿;OPFS、
|
||||
IndexedDB、quota 与 Worker commit 故障由 Chromium 专项覆盖。WebKit headless 不提供 Worker
|
||||
IndexedDB 时明确显示 `Storage: unavailable`,不影响引擎门。
|
||||
|
||||
五个恶意/截断 `.blend` 均返回有界错误;notice、GPL、GMP/OpenSubdiv、本地依赖和 dist 远程
|
||||
URL 扫描进入发布命令。验收:`test:release-performance`、`test:malicious-blends`、
|
||||
`test:cross-browser`、`test:release-package`。
|
||||
12
docs/status/N-009.md
Normal file
12
docs/status/N-009.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# N-009 快照、操作日志和崩溃重放
|
||||
|
||||
状态:`done`
|
||||
|
||||
Storage schema 5 加入 `operation_quarantine`;schema 6 新增经过哈希验证的
|
||||
`simulation_manifest`,不改变既有日志/快照语义。命令按 revision/时间/ID 确定排序,非法记录移入
|
||||
隔离区,revision 冲突结构化失败;显式保存后清理已提交日志。每 10 条命令写一份 SHA-256
|
||||
`.blend` 快照,默认保留 5 份且总量不超过 256MiB;保存点也写快照。恢复入口优先打开原子
|
||||
提交项目,缺失时使用最新快照,然后只重放提交 revision 之后的可重放 Main 命令。
|
||||
|
||||
验收:E2E `retains bounded snapshots and returns a validated operation replay plan`,以及原子恢复、
|
||||
并发保存和 quota 专项。
|
||||
11
docs/status/N-010.md
Normal file
11
docs/status/N-010.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# N-010 可复现离线发布包
|
||||
|
||||
状态:`done`
|
||||
|
||||
`release:offline` 生成 `release/blender-web-offline.tar.gz` 与
|
||||
`release/blender-web-corresponding-source.tar.gz`。二进制包包含同源 app、WASM、GPL、GMP、
|
||||
OpenSubdiv license、第三方 notice、文件 SHA-256 manifest 和 source offer;源码包包含 Blender
|
||||
5.2、Web app/protocol、锁文件、Web 构建脚本与状态/构建文档。tar 使用固定排序、mtime、owner
|
||||
和 `gzip -n`,连续生成两次后必须得到相同的两个 SHA-256;顶层 `SHA256SUMS.txt` 覆盖交付物。
|
||||
|
||||
验收:`npm --prefix web run release:offline`。
|
||||
20
docs/status/N-011.md
Normal file
20
docs/status/N-011.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# N-011 Sculpt 子集
|
||||
|
||||
状态:`in_progress(属性 + 有界 Main stroke 子集)`
|
||||
|
||||
详细分解、依赖、错误码、停止条件和验收命令见
|
||||
[`docs/UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md`](../UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md)。
|
||||
|
||||
本轮已交付 `SculptStrokeIR`、Mask/Face Set 校验、单用户/linked/Shape Key/拓扑
|
||||
modifier 能力门、点数和属性预算。SceneIR 及 WBG1 header version 2 可携带并校验
|
||||
`sculptMask` 和 `faceSets`,`MeshGeometryDelta` 可对两个字段执行 replacement/range patch。
|
||||
`setSculptMeshAttributes` 已通过 Blender Main 写入、undo 历史、保存重开和 WBG 二进制
|
||||
回归;非持久的 active Face Set 仍返回 `CAPABILITY_MISSING`。
|
||||
|
||||
`sculptStroke` 现在开放一个明确受限的 native Main 顶点事务:Draw/Inflate/Grab/Smooth、
|
||||
压力、Mask、对象空间对称、2048 samples/10000 path/250000 vertices 预算,以及 Shape Key、
|
||||
linked、单用户和启用拓扑 modifier 安全门。它不是 Blender PBVH/BMesh 等价求值,仍不声明
|
||||
动态拓扑、多分辨率、纹理笔刷、法线/切线 golden、Sculpt UI 或浏览器故障恢复;这些继续
|
||||
返回结构化阻断并由 N-011-C2/D/E 负责。
|
||||
|
||||
验收:`npm --prefix web run test:authoring-roundtrip`。
|
||||
20
docs/status/N-012.md
Normal file
20
docs/status/N-012.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# N-012 Geometry Nodes 与 Simulation
|
||||
|
||||
状态:`in_progress(资源/Simulation cache 安全层)`
|
||||
|
||||
详细分解、GraphIR、字段/实例闭包、deterministic simulation cache、错误码和验收命令见
|
||||
[`docs/UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md`](../UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md)。
|
||||
|
||||
本轮已交付版本化 `GeometryNodeGraphIR`、node/socket/link/domain 校验、支持节点白名单、
|
||||
循环依赖和自递归 group 检测。Object/Collection/Image Info 资源现在按 SceneIR stable ID、
|
||||
资源类型、owner cycle 和 linked/missing/corrupt 沙箱校验。合法图仍只通过协议门,native
|
||||
lazy-function evaluator 未启用时返回 `CAPABILITY_MISSING`。
|
||||
|
||||
`SimulationCacheManifestIR` 已绑定 graph/source blend/input hash、Blender 5.2、完整帧范围、
|
||||
连续 byte range、总 payload 和逐帧 SHA-256。StorageWorker schema 6 使用 OPFS 内容寻址资产
|
||||
和 `simulation_manifest` 索引,写入前核对当前 committed blend,Worker 重启后重新逐帧验证;
|
||||
缺失、版本不符和损坏均结构化阻断。
|
||||
|
||||
仍未声明:浏览器生成 bake、WASM Simulation Zone 求值、cache frame seek 接入 GN modifier、
|
||||
任意 lazy-function/field/instance graph。验收:`npm --prefix web run test:simulation-cache`、
|
||||
`npm --prefix web run test:capability-gates`。
|
||||
21
docs/status/N-013.md
Normal file
21
docs/status/N-013.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# N-013 Shader Node 图
|
||||
|
||||
状态:`in_progress(七节点 Main + 常量 PBR 映射子集)`
|
||||
|
||||
详细分解、ShaderIR、typed socket 校验、Main 写回、Web 编译、GLB 映射和验收命令见
|
||||
[`docs/UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md`](../UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md)。
|
||||
|
||||
本轮已交付版本化 `ShaderGraphIR`、单 Material Output、typed socket/隐式转换、图循环、
|
||||
Material/Image stable ID 以及 linked/missing/corrupt image 资源门。首个 native Main 写回
|
||||
子集开放 RGB、Value、有限 Math、Principled、Image Texture、Normal Map 和 Material
|
||||
Output;整图替换在一个 history transaction 中完成,并通过节点/链接及 RGB/Value
|
||||
defaultValue 保存重开回归。
|
||||
|
||||
Math 已开放 ADD/SUBTRACT/MULTIPLY/DIVIDE/MINIMUM/MAXIMUM 的 Main `custom1` 写回和
|
||||
operation 保存重开;其他运算继续结构化阻断。RGB/Value 到 Principled Base Color、
|
||||
Roughness、Metallic 的有限常量链接现可确定性映射为 glTF PBR factor;缺值、越界、
|
||||
重复输入和未知链接继续返回 `SHADER_GRAPH_UNMAPPABLE`。Mix、Mapping、Texture
|
||||
Coordinate、Bump 及任意节点仍返回 `SHADER_NODE_UNSUPPORTED`。node properties 仅开放
|
||||
Math operation;受限 Web 编译、完整色彩管理、完整 GLB 图映射和桌面渲染 golden 仍为 planned。
|
||||
验收:`npm --prefix web run test:authoring-roundtrip`、`npm --prefix web run test:capability-gates`
|
||||
以及 Shader GLB mapping E2E。
|
||||
20
docs/status/N-014.md
Normal file
20
docs/status/N-014.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# N-014 NLA
|
||||
|
||||
状态:`in_progress(Action Clip Main/求值 + reverse/repeat 子集)`
|
||||
|
||||
详细分解、AnimationIR strip/track、Main 编辑、原生 NLA 求值、UI、GLB 映射和验收命令见
|
||||
[`docs/UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md`](../UNDECLARED_CAPABILITIES_EXECUTION_PLAN.md)。
|
||||
|
||||
本轮已交付 `NlaTrackIR`/`NlaStripIR`、Action 存在性、owner/path、稳定排序、不重叠、
|
||||
range/scale/repeat/influence 一致性、blend/extrapolation 和 time-warp 阻断。SceneIR reader
|
||||
可恢复 Track/Action Clip 摘要;`setNLAStack` 以整栈替换事务写 Blender Main,并经过
|
||||
undo 历史、保存重开和 frame 5 native depsgraph 求值。Action Clip `reverse` 已映射到
|
||||
Blender `NLASTRIP_FLAG_REVERSE`,reader 可恢复该标志;反向正例得到预期线性位置约
|
||||
`[0.555556, 1.111111, 1.666667]`。
|
||||
同一正例已扩为 `repeat=2`,frame 5 与第二周期 frame 14 的 native Depsgraph 矩阵一致。
|
||||
|
||||
当前只支持单对象 Action Clip、正 scale、Replace/Add/Multiply/Combine 和有限外插。
|
||||
Transition/Meta/Sound、Animated Time、Drivers、细粒度拖动/resize 命令、NLA UI、
|
||||
骨骼/约束混合矩阵及 GLB 展开仍为 planned/结构化阻断。
|
||||
|
||||
验收:`npm --prefix web run test:authoring-roundtrip`、`npm --prefix web run test:capability-gates`。
|
||||
113
docs/status/N-015.md
Normal file
113
docs/status/N-015.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# N-015 非 Mesh 几何数据块
|
||||
|
||||
状态:`in_progress`(本地有界切片已落地,VDB renderer/完整交互仍阻断)
|
||||
|
||||
更新时间:2026-08-12
|
||||
|
||||
## 当前声明
|
||||
|
||||
当前声明覆盖 Blender 5.2 `.blend` 中有限非 Mesh 数据的稳定识别、Main 权威写回、undo/redo、
|
||||
保存重开、真实 evaluated mesh 报告和 WNM 二进制分块。Curve cyclic/handle 目前只有有界
|
||||
属性读写,未声明完整 topology editor、handle/cyclic gizmo、VDB 体渲染、完整 USD loss
|
||||
fixture 或跨浏览器性能等价。
|
||||
|
||||
| 数据族 | Reader | Web 预览 | 当前门 |
|
||||
| --- | --- | --- | --- |
|
||||
| legacy Curve | 控制点、spline offset、resolution | WNM 控制折线;depsgraph 真 mesh | `READY` |
|
||||
| legacy Surface | 控制点、spline offset、resolution | WNM 控制折线;depsgraph 真 mesh | `READY` |
|
||||
| Font | body、对齐、extrude/bevel/offset 与摘要 | depsgraph 真 mesh(源文本仍保留) | `READY`(无控制笼) |
|
||||
| Metaball | 元素类型、位置、半径、尺度 | bounded sphere proxy;depsgraph implicit mesh | `READY` |
|
||||
| PointCloud | position/radius/POINT 属性 | WNM 分块 Points | `READY`(空数据为 `summary-only`) |
|
||||
| Curves/Hair | position/radius/curve/POINT 属性 | WNM 分块 Points/curve line | `READY`(缺数据阻断) |
|
||||
| Volume | 项目内 OpenVDB path/grid metadata | 无 renderer;可取消 decoder API | `NON_MESH_RESOURCE_MISSING` 或预算阻断 |
|
||||
|
||||
## 已实现任务
|
||||
|
||||
1. `NonMeshDataIR` 加入 SceneIR schema 1,可选字段保持旧快照兼容。
|
||||
2. parser 校验类型、状态、有限数、三元控制点、spline offset、Metaball 元素和错误码。
|
||||
3. native reader 为数据块生成稳定 ID,并把对象 `dataId` 指向同一 ID;Web runtime 注册
|
||||
`ID_MB`、`ID_PT` 和 `ID_VO`,不再把三类对象降为 Empty。
|
||||
4. 单数据块最多读取 1M 点;越界或不完整数据返回
|
||||
`NON_MESH_DATA_BUDGET_EXCEEDED`。
|
||||
5. `NonMeshGeometryChunk` WNM schema 1 提供 65,536 点分块、SHA-256、属性 domain/storage、
|
||||
256 MB 场景预算和 1M 点性能门;Worker/主线程/Offscreen 均传输并消费分块。
|
||||
6. native reader 读取 PointCloud/Curves/Hair 的 position、radius、curve offset 和属性值,
|
||||
不以摘要计数伪造点;Volume 提供项目路径、OpenVDB grid metadata 和可取消 decoder。
|
||||
7. depsgraph 对 Curve/Surface/Font/Metaball 通过 `BKE_mesh_new_from_object` 输出真实位置、法线、
|
||||
边/三角索引、UV、材质槽和 source face/edge mapping,并在 1M/2M 拓扑预算处结构化阻断。
|
||||
Web ID registry 已注册 `ID_VF` 并在加载时恢复 Blender 未写入 `.blend` 的 `<builtin>` 字体
|
||||
引用;Curve/Surface/Font/Metaball 的几何计数、边界、面积和位置/索引矩均通过 Blender
|
||||
5.2 desktop golden。
|
||||
8. Main 已支持 Curve/Surface 控制点、resolution、有界 cyclic/handle 类型与 Bezier 左右 handle
|
||||
坐标、Font body/geometry/layout 标量属性(spacing、line distance、word space、shear、font
|
||||
size、x/y offset)、逐字符 kern/material/style flags 和最多 256 个 textbox、
|
||||
`.blend` 内已有/packed VFont 的 regular/bold/italic/bold-italic 四样式链接、
|
||||
Metaball element 写回,以及 bounded Poly Curve create、delete、1D Poly/Bezier/NURBS conversion、
|
||||
二维 Surface U/V dimensions/order/rational weight 网格替换和 Curve/Surface/Font/Metaball 数据块
|
||||
重命名;一维多 spline 创建/删除/重排和批量 handle/cyclic 已由单个原子 Main 事务覆盖。
|
||||
多 handle 选择拖拽/gizmo UI 仍阻断。单用户、undo/redo、save/reopen 由
|
||||
`check-nonmesh-roundtrip.mjs` 验证。
|
||||
9. 主线程与 OffscreenCanvas 对 PointCloud/Curve 控制点和 Bezier handle 代理提供 bounded raycast,并对 Mesh 的
|
||||
VERT/EDGE/FACE 使用一致的三角顶点、边索引解析,回传既有 selection callback;完整
|
||||
gizmo、跨对象 selection history 与精确范围 patch 仍未声明;新增 local bounded selection
|
||||
history 仅用于 revision/stale-hit 门和撤销栈验收。Bezier 左/右 handle 现以全局控制点映射
|
||||
独立拾取,轴向 gizmo 通过精确 Main 命令写回并通过 undo/redo、save/reopen;多选拖拽、跨对象
|
||||
history 和 range patch 仍未声明。
|
||||
10. `queryNonMeshCapability(dataId)` 返回 N-015 `READY/BLOCKED` 与机器可读错误码;GLB 对未求值
|
||||
非 Mesh 拒绝导出。Font/Metaball/二维 NURBS Surface 的 depsgraph 三角网格与 Curve 的
|
||||
evaluated edge line primitive 已通过 GLB 导出和 Blender 5.2 桌面回导几何校验;零三角且零边的结果仍返回
|
||||
`GLB_NON_MESH_UNMAPPED`,不生成空 primitive。确定性 USDA 1.0 序列化器将三角求值写为
|
||||
`UsdGeomMesh`、edge-only 求值写为 `UsdGeomBasisCurves`,缺 buffer/空场景结构化阻断;四对象
|
||||
已通过 USD-enabled Blender 5.2.0 LTS desktop reimport。PointCloud 使用 GLB `POINTS`/USD
|
||||
`UsdGeomPoints`,Curves/Hair 使用 GLB `LINES`/USD `UsdGeomBasisCurves`;radius 映射 USD
|
||||
widths,typed WNM 属性映射 primvars,GLB 属性损失结构化报告,7 对象 desktop reimport 已通过。
|
||||
Volume loss fixture 仍由 VDB 资源/renderer 阻断。
|
||||
11. Blender 5.2 fixture 已包含真实 PointCloud/Curves 属性;Chromium 主线程/Offscreen、真实
|
||||
depsgraph、WNM 1M 性能测试均接入。
|
||||
|
||||
## 后续分解
|
||||
|
||||
1. N-015-B3:接入真实 OpenVDB decoder 与体素纹理/射线步进;在此之前保持 Volume renderer 阻断。
|
||||
2. N-015-C1:多 handle 选择拖拽与 gizmo UI;多 spline 创建/删除/重排、批量 handle/cyclic
|
||||
editor transaction 和二维 Surface U/V topology/order/rational weight 网格替换已完成。
|
||||
3. N-015-C2:任意外部路径的新字体导入与资源沙箱;已有/packed VFont 的四 style link Main
|
||||
写回、字符级样式、kern/material 与 textbox 已完成并通过 PFB desktop/WASM golden。
|
||||
4. N-015-D1:跨对象 selection history、多 handle 拖拽和 SceneDelta range patch;左右 handle
|
||||
identity raycast、单 handle 轴向 gizmo/Main 写回已完成。
|
||||
5. N-015-D2:evaluated preview 与源控制笼分层显示、WebGPU 等价。
|
||||
6. N-015-E1:补齐 Volume 的完整 loss fixture;PointCloud/Curves/Hair、Curve line bake、真实
|
||||
4x4 NURBS Surface mesh、desktop geometry golden、7 对象 GLB 与 USDA desktop round-trip 已通过。
|
||||
7. N-015-E2:100k/1M WASM/GPU 内存、Worker restart 和 Chromium OPFS quota;Chromium
|
||||
64 KiB 真实 quota、失败后旧 revision 保持、Worker restart 恢复已通过。后续浏览器验收
|
||||
仅以 Chromium 为基线,不配置 Firefox/WebKit。
|
||||
|
||||
## 停止条件
|
||||
|
||||
- `summary-only` 不得进入 `READY`。
|
||||
- legacy 控制折线不得标记为 evaluated/tessellated curve。
|
||||
- Metaball sphere proxy 不得用于导出或保存为求值曲面。
|
||||
- Volume decoder/renderer、Hair 属性 buffer 缺失时不得生成占位几何。
|
||||
- Metaball sphere proxy 不得进入 GLB;GLB 只能消费 depsgraph evaluated mesh。
|
||||
- 任意新增 Main authoring 命令在 save/reopen 与 undo/redo 完成前不得开放 UI。
|
||||
|
||||
## 验收命令
|
||||
|
||||
```bash
|
||||
source tools/web/emscripten-env.sh
|
||||
cmake --build build_web_blender6 --target web_engine -- -j8
|
||||
bash tools/web/install-web-engine-assets.sh
|
||||
build_blender_5.2.0/bin/blender -b --factory-startup \
|
||||
--python tools/web/generate-nonmesh-fixture.py -- tests/files/web/nonmesh_scene.blend
|
||||
npm --prefix web run typecheck
|
||||
npm --prefix web run lint
|
||||
npm --prefix web run test:nonmesh-roundtrip
|
||||
npm --prefix web run test:nonmesh-desktop-golden
|
||||
npm --prefix web run test:nonmesh-glb-blender-roundtrip
|
||||
npm --prefix web run test:nonmesh-usd-serialization
|
||||
BLENDER_BIN=/path/to/usd-enabled/blender \
|
||||
npm --prefix web run test:nonmesh-usd-blender-roundtrip
|
||||
npm --prefix web run test:nonmesh-binary
|
||||
npm --prefix web run test:vdb
|
||||
WEB_TEST_PORT=5349 npm --prefix web run test:e2e -- -g "real OPFS quota|reports quota exhaustion"
|
||||
WEB_TEST_PORT=5201 npm --prefix web run test:e2e -- -g "N-015|non-mesh"
|
||||
```
|
||||
39
docs/status/N-016.md
Normal file
39
docs/status/N-016.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# N-016 Grease Pencil
|
||||
|
||||
状态:`BLOCKED`(协议、有限 reader 和有限 Main transaction 已落地;完整 2D/3D 编辑器、onion skin、modifier 语义和桌面 golden 仍阻断)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-016-A:SceneIR 中提供 Layer/Frame/Drawing/Stroke/Point/Attribute schema,校验
|
||||
finite position、radius、opacity、vertex color、cyclic、material index,并以
|
||||
1024 layer、100k frame、1M stroke、1M point、65,536 attribute 预算拒绝越界输入。
|
||||
超预算只允许 `blocked + GREASE_PENCIL_BUDGET_EXCEEDED` 摘要。
|
||||
2. N-016-A:Blender 5.2 Main reader 输出真实 Grease Pencil layer/frame/drawing/stroke
|
||||
数据,稳定映射 `grease-pencil:*` 与 `grease-pencil-layer:*` ID;对象 dataId 不再降级
|
||||
为 Empty。
|
||||
3. N-016-B:Main 支持有界 create/remove/reorder layer、insert/remove frame,以及整帧
|
||||
`setGreasePencilStrokes` transaction(空 stroke 数组用于擦除)。命令要求单用户数据块,
|
||||
使用既有 authoritative Main、undo/redo 和 save/reopen 流程。
|
||||
4. N-016-C(部分):radius、opacity、vertex color、cyclic stroke 和 material index
|
||||
已读写;onion skin 仅输出 layer 状态,不声明时间邻帧渲染。
|
||||
5. N-016-D(部分):共享 Three.js 适配器按当前 frame 选择每个可见 layer 最近的有效
|
||||
drawing,渲染真实 3D stroke/闭环;Chromium 主线程与 OffscreenCanvas 均通过非空像素门。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-016-C:material datablock 事务、onion skin preview 和完整 Grease Pencil modifier reader。
|
||||
- N-016-D:2D editor、stroke/point selection、timeline/dope integration、gizmo 和 worker restart;
|
||||
3D current-frame stroke viewport 已完成。
|
||||
- N-016-E:desktop drawing hash、Chromium 像素 golden、GLB/USD loss report 和 OPFS。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
npm --prefix web run typecheck
|
||||
npm --prefix web run lint
|
||||
npm --prefix web run test:grease-pencil
|
||||
WEB_TEST_PORT=5202 npm --prefix web run test:e2e -- --grep "N-016 Grease Pencil"
|
||||
```
|
||||
|
||||
`test:grease-pencil` 使用 `modifier_grease_pencil_scene.blend`,覆盖 reader、layer/frame/stroke
|
||||
Main transaction、undo/redo 和保存重开。它不替代桌面 drawing hash。
|
||||
33
docs/status/N-017.md
Normal file
33
docs/status/N-017.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# N-017 Paint 与权重
|
||||
|
||||
状态:`BLOCKED`(stroke/patch schema、Main 顶点色/权重 transaction 已落地;真实命中、texture paint 和 GPU/image 生命周期未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-017-A(部分):`PaintStrokeIR` 覆盖 Vertex Color、Weight、Texture Paint,携带
|
||||
object/revision、radius/strength、pressure、PBVH face/barycentric hit 和 UV hit。
|
||||
2. N-017-A(部分):`WeightPatchIR` 覆盖有界 vertex index/value、normalize 和 mirror 意图。
|
||||
3. 预算限制为单 stroke 100k samples/64 MiB 估算、单 weight patch 1M entries、单 texture
|
||||
tile 256 MiB;非法 barycentric、pressure、color、weight 和非有限数会结构化拒绝。
|
||||
4. N-017-B(部分):`setVertexColors` 在单用户 Mesh 上创建/转换 `POINT` 或 `CORNER`
|
||||
`FLOAT_COLOR` 属性,并更新 active color;`setVertexWeights` 在真实 Object/Mesh 上创建顶点组、
|
||||
写入/移除 `MDeformWeight`,支持逐顶点 normalize。
|
||||
5. 顶点色和权重都已通过 Main undo/redo 与 `.blend` save/reopen;`mirror:true` 在没有已验证
|
||||
对称拓扑映射时返回 `CAPABILITY_MISSING`,不会伪造镜像结果。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-017-A:真实 PBVH/UV raycast 与 brush falloff 对桌面语义的对应。
|
||||
- N-017-B:limit/clean、已验证拓扑映射上的 mirror、桌面 brush/falloff 对照。
|
||||
- N-017-C:packed/UDIM tile transaction、色彩空间、dirty tile 和原子保存。
|
||||
- N-017-D/E:armature golden、seam bleed、mask/selection、GPU dispose、quota、坏图和 UI。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5203 npm --prefix web run test:e2e -- --grep "N-017 paint"
|
||||
npm --prefix web run test:paint-roundtrip
|
||||
```
|
||||
|
||||
`test:paint-roundtrip` 覆盖 CORNER color、vertex group patch、normalize、mirror 错误门、
|
||||
undo/redo 与 save/reopen。
|
||||
30
docs/status/N-018.md
Normal file
30
docs/status/N-018.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# N-018 Physics 与 Simulation
|
||||
|
||||
状态:`BLOCKED`(family capability、settings/dependency/cache manifest 与错误帧门已落地;
|
||||
cache playback、WASM solver 和 bake job 未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-018-A:Rigid Body、Soft Body、Cloth、Fluid、Dynamic Paint、Particle、Hair
|
||||
使用固定枚举能力清单;metadata/cache manifest 为 `LOCAL_BOUNDED`,cache playback、
|
||||
local solver、server job 均保持 `BLOCKED`。
|
||||
2. N-018-B(部分):`PhysicsSimulationManifestIR` 绑定 owner Object、settings SHA-256、
|
||||
有界设置摘要、依赖 stable ID 和 desktop bake cache;系统依赖环、重复依赖和超预算拒绝。
|
||||
3. N-018-C(门):cache 绑定 source blend/settings/input/cache SHA-256、帧范围和实际已缓存帧;
|
||||
`COMPLETE` 必须逐帧连续,frame seek 只返回精确命中帧,禁止复用相邻错误帧。
|
||||
4. 单 manifest 上限 4096 systems、每系统 1024 dependencies、256 settings/64 KiB、
|
||||
100k frames。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-018-A/B:从真实 Main 提取完整 family settings、collection/effector/collision 依赖。
|
||||
- N-018-C:desktop bake payload 的 family decoder、depsgraph frame playback 和 100 帧 golden。
|
||||
- N-018-D:逐 family WASM solver 初始化、线程、内存和确定性验证。
|
||||
- N-018-E:bake start/cancel/commit、服务端 job、故障恢复、进度与 UI。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5204 npm --prefix web run test:e2e -- --grep "N-018 physics"
|
||||
npm --prefix web run test:simulation-cache
|
||||
```
|
||||
33
docs/status/N-019.md
Normal file
33
docs/status/N-019.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# N-019 灯光与渲染
|
||||
|
||||
状态:`BLOCKED`(Camera/Light/World/Scene metadata、Light/World 有界 Main 写回与
|
||||
Three exposure/shadow 映射已落地;完整 Camera/颜色管理 writer 和渲染等价未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-019-A(部分):Camera 区分 Perspective/Orthographic/Panoramic/Custom,读取 sensor、
|
||||
shift、clip、panorama 和 DOF;Light 读取 energy/exposure/temperature/shadow/shape;World
|
||||
读取环境、exposure 和 mist;Scene 读取 render engine、display/view/look/exposure/gamma/白平衡。
|
||||
2. N-019-A(部分):Light 与 World 使用严格属性白名单写入真实 Main,覆盖 color、energy、
|
||||
exposure、temperature、shadow、World color/mist,已通过 undo/redo 与 save/reopen。
|
||||
3. N-019-B(部分):主线程和 OffscreenCanvas renderer 都优先使用 Scene color-management
|
||||
exposure,World exposure 仅作旧数据回退;Light exposure 转换为强度,`castsShadow:false`
|
||||
不再被 Three 强制打开。
|
||||
4. 白平衡读取有完整性门:Main Light/World 重写若导致 Blender 5.2 tint 序列化为异常近零值,
|
||||
不暴露垃圾数值而返回 `whiteBalanceStatus: BLOCKED`。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-019-A:Camera 与 Scene color-management writer;直接 DNA 写入会破坏 white balance,
|
||||
必须改接 Blender/RNA 颜色管理 API 后才能开放。
|
||||
- N-019-B/C:AgX/Standard/Raw 的视觉等价、temperature 颜色、Area spread、Mist、DOF、
|
||||
transparent sorting、probe 和高级 shadow 参数。
|
||||
- N-019-D:Cycles/Freestyle/denoise 服务端 job 协议与结果 hash。
|
||||
- N-019-E:desktop/Chromium 像素 golden、设备丢失和 1M triangles。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
npm --prefix web run test:lighting-roundtrip
|
||||
WEB_TEST_PORT=5319 npm --prefix web run test:e2e -- --grep "N-019 Scene exposure"
|
||||
```
|
||||
29
docs/status/N-020.md
Normal file
29
docs/status/N-020.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# N-020 Compositor
|
||||
|
||||
状态:`BLOCKED`(GraphIR 与有界 CPU executor 已落地;真实 Main graph、WebGPU、HDR golden
|
||||
和服务端执行未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-020-A:版本化 `CompositorGraphIR` 覆盖 Image、Render Layer、Constant Color、
|
||||
Transform、Invert、Exposure、Alpha Over、Blur、Mix、Viewer、Composite 与 Unsupported;
|
||||
节点/资源 ID、重复 input socket、缺失引用和 graph cycle 会拒绝。
|
||||
2. N-020-B(CPU 子集):线性 sRGB Float32 RGBA executor 按拓扑序执行 Transform、颜色、
|
||||
Alpha Over、Blur、Mix,并返回 Composite 与多 Viewer 输出。
|
||||
3. N-020-C(部分):最大 4096 nodes、16384 links、4096 resources、8192 dimension、
|
||||
16M pixels、256 MiB image 和 100M blur operations;分配前检查,支持 worker cancellation。
|
||||
4. N-020-D(门):Unsupported node 保留 Blender type metadata,并返回
|
||||
`COMPOSITOR_NODE_UNSUPPORTED`,不会删节点后继续运行。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-020-A:从真实 Main 读取/写回 compositor node tree、socket defaults、Render Layer pass。
|
||||
- N-020-B/C:WebGPU executor、tile/frame cache、增量 invalidation 和 GPU dispose。
|
||||
- N-020-D:服务端 Blender job、source hash 和结果提交。
|
||||
- N-020-E:desktop HDR/alpha/color-space golden、OOM/fault/device-loss。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5320 npm --prefix web run test:e2e -- --grep "N-020 CPU compositor"
|
||||
```
|
||||
31
docs/status/N-021.md
Normal file
31
docs/status/N-021.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# N-021 Sequencer 与音频
|
||||
|
||||
状态:`BLOCKED`(strip schema、确定性时间编辑和 codec 能力门已落地;真实 Main
|
||||
写回、媒体解码/渲染、音频波形和服务端编码仍未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-021-A(部分):版本化 `SequencerTimelineIR` 覆盖 Scene、Movie、Image、Sound、
|
||||
Effect、Meta strip、channel、帧范围、source range、speed、proxy 和依赖;strip、
|
||||
image、dependency 数量以及帧范围都有预算,资源路径经过项目沙箱规范化。
|
||||
2. N-021-B(部分):`MOVE`、`TRIM`、`SPLIT` 以 revision 乐观并发控制作用于内存
|
||||
timeline;编辑后重新解析依赖和预算,锁定 strip 与 stale revision 会拒绝。
|
||||
3. N-021-B/C:`sequencerSourceFrame` 对 speed、trim、split 使用确定性的 source-frame
|
||||
映射,避免左右片段复用越界源帧。
|
||||
4. N-021-C/D(门):运行时只报告 WebCodecs/HTMLMedia 需要精确 probe;codec 必须
|
||||
出现在已验证 MIME 集合中才可放行,本地编码固定为 `BLOCKED`。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-021-A/B:从真实 Main 读取并写回 scene sequence editor 的 strip、transition、
|
||||
modifier、undo/redo、save/reopen。
|
||||
- N-021-C:WebCodecs 精确 seek/decode、音频 waveform、proxy 生成、A/V sync、丢帧和
|
||||
损坏媒体处理。
|
||||
- N-021-D:浏览器不支持的 codec、混音与最终编码的服务端 Blender job。
|
||||
- N-021-E:桌面/Chromium golden、OPFS 和大规模媒体性能门。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5321 npm --prefix web run test:e2e -- --grep "N-021 sequencer"
|
||||
```
|
||||
28
docs/status/N-022.md
Normal file
28
docs/status/N-022.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# N-022 Tracking 与 Mask
|
||||
|
||||
状态:`BLOCKED`(资源 schema、marker/mask 有界事务和 solve 能力门已落地;真实 Main、
|
||||
跟踪/相机求解、编辑器 overlay 与桌面 golden 未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-022-A:版本化 project schema 覆盖 MovieClip、Track/Marker、Plane Track、Camera
|
||||
Solve metadata、Mask Layer/Spline/Point 及 compositor/scene binding。
|
||||
2. N-022-A/B:clip 路径限制在项目内,source 与 solve 绑定 SHA-256;marker frame、
|
||||
plane track 引用、mask point/handle、资源 binding、重复 ID 与总量预算都严格校验。
|
||||
3. N-022-B(部分):marker upsert/delete、track selection、mask point 与 spline cyclic
|
||||
修改使用 revision 事务,锁定项和 stale revision 会拒绝,提交后再次完整解析。
|
||||
4. N-022-C(门):marker/mask schema edit 可用;browser tracking 只有显式 probe 成功后
|
||||
放行,camera solve 保持 `BLOCKED` 并要求受验证的服务端 Blender。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-022-A/B:真实 Blender Main MovieClip/Mask 读取、写回、undo/redo、save/reopen。
|
||||
- N-022-C:浏览器 tracking 实现、完整 camera/plane solve 与服务端 job/hash 提交。
|
||||
- N-022-D:Clip/Mask editor、overlay、selection/raycast 和 compositor/scene 实际绑定。
|
||||
- N-022-E:desktop solve/error golden、媒体故障和 Chromium 测试。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5322 npm --prefix web run test:e2e -- --grep "N-022 tracking"
|
||||
```
|
||||
27
docs/status/N-023.md
Normal file
27
docs/status/N-023.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# N-023 Asset、Library 与 IO
|
||||
|
||||
状态:`BLOCKED`(asset catalog、来源/许可证元数据、库依赖与 IO 安全门已落地;真实
|
||||
Append/Link/Override Main、非 GLB 本地导入和跨桌面重导入未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-023-A:版本化 manifest 覆盖 catalog、asset kind/tag、preview、author、license、
|
||||
source path/SHA-256、library source/dependency/read-only metadata;重复 ID、缺 catalog、
|
||||
缺许可证和哈希不匹配会拒绝。
|
||||
2. N-023-A/B(部分):catalog 与 library dependency 图做确定性拓扑检查并返回 load order;
|
||||
content-addressed index 报告 `LOCAL_BOUNDED`,OPFS 只在运行时 API 存在时报告 `PROBE_REQUIRED`。
|
||||
3. N-023-C(门):现有 GLB 导出与 USD semantic analysis 可放行;GLTF/OBJ/PLY/STL、
|
||||
USD/Alembic 实际导入保持 `IO_FORMAT_UNSUPPORTED`,库 mutation 需要真实 Main。
|
||||
4. N-023-E:项目路径、外部 URI、archive entry 数量/单项/总量、压缩展开比率均有边界。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-023-B:Append/Link/Library Override、reload/relocate 和真实 Main transaction。
|
||||
- N-023-C/D:GLTF/OBJ/PLY/STL、USD/Alembic import/export/save/reopen/desktop reimport。
|
||||
- N-023-E:zip fuzz、OPFS quota/recovery、license/source offer 发布审计和大文件流式性能。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5323 npm --prefix web run test:e2e -- --grep "N-023 asset"
|
||||
```
|
||||
27
docs/status/N-024.md
Normal file
27
docs/status/N-024.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# N-024 Editors 与工作流
|
||||
|
||||
状态:`BLOCKED`(统一 context、只读 editor manifest、selection sync、keymap 和布局预算
|
||||
已落地;完整 Blender editor writer、gizmo/触控和跨设备 golden 未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-024-A:版本化 workflow manifest 统一 workspace、area、region、active editor、mode、
|
||||
view layer、pinned data 与 revision;13 类 editor 可被明确识别。
|
||||
2. N-024-B(部分):只读 editor context、区域可见性、workspace/area 切换使用同一份
|
||||
workflow state,rect 边界与不可重叠布局经过校验。
|
||||
3. N-024-C(部分):selection sync 以 revision 事务更新 active object 与 selected IDs,
|
||||
active object 必须属于 selection,过期 revision 会拒绝。
|
||||
4. N-024-D(门):keymap 绑定和预算可验证;writer、gizmo 与 touch drag 保持能力阻断。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-024-B/C:Properties、UV/Image、Node、Graph、Dope Sheet、NLA、Spreadsheet 等真实
|
||||
Blender 数据读取/写回、selection history、operator search 和 context menu。
|
||||
- N-024-D/E:Blender-compatible keymap 执行、gizmo/drag preview/commit、桌面/mobile/笔
|
||||
触控布局、无重叠截图和 accessibility golden。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5324 npm --prefix web run test:e2e -- --grep "N-024 editor"
|
||||
```
|
||||
28
docs/status/N-025.md
Normal file
28
docs/status/N-025.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# N-025 Scripting 与平台
|
||||
|
||||
状态:`BLOCKED`(默认拒绝策略、签名 manifest、权限/资源预算、平台报告和服务端 hash
|
||||
门已落地;本地隔离执行、真实 server job 与发布审计未实现)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-025-A:脚本默认拒绝网络、autorun、driver expression 和 add-on 安装;entry/dependency
|
||||
path 必须在项目内,未知权限和重复 ID 会拒绝。
|
||||
2. N-025-B(部分):脚本 manifest 要求 SHA-256、固定长度签名、publisher/keyId、权限
|
||||
allowlist、CPU/内存/墙钟预算,并检查脚本依赖图。
|
||||
3. N-025-C(门):合法脚本仍要求隔离 sandbox;server job 需要 script/source/input
|
||||
hash 一致,但当前 endpoint 未配置,返回 `SERVER_JOB_UNAVAILABLE`。
|
||||
4. N-025-D:Worker/WebGPU/OffscreenCanvas/OPFS 与 native/CUDA/Metal/HIP/OptiX capability
|
||||
报告只反映 API 存在或显式 `BLOCKED`。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- N-025-B/C:签名验证密钥管理、无网络 CPython/native sandbox、server Blender job 和
|
||||
output hash 提交。
|
||||
- N-025-D/E:真实 GPU/native window/file watcher 适配、恶意脚本/依赖混淆/逃逸/重放、
|
||||
审计日志和发布门。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5325 npm --prefix web run test:e2e -- --grep "N-025 script"
|
||||
```
|
||||
37
docs/status/N-026.md
Normal file
37
docs/status/N-026.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# N-026 全域发布门
|
||||
|
||||
状态:`BLOCKED`(machine-readable parity manifest、依赖/状态检查、证据聚合和确定性
|
||||
序列化已落地;跨浏览器、离线包、OPFS、性能/故障、SBOM 与发布审计证据未齐)
|
||||
|
||||
## 已验证切片
|
||||
|
||||
1. N-026-A:版本化 `ReleaseManifestIR` 为每个 family 记录 `LOCAL_EXACT`、
|
||||
`LOCAL_BOUNDED`、`SERVER` 或 `BLOCKED`、roadmap 状态、完成/阻断切片、验收命令和
|
||||
依赖;缺失 family、非法非阻断状态或依赖环会拒绝。
|
||||
2. N-026-B/C:Chromium 主线程/OffscreenCanvas、offline/Worker restart/OPFS recovery、
|
||||
1M/10M geometry、4K/8K texture、长媒体、simulation cache、OOM/device loss/网络
|
||||
中断/损坏 blend/zip bomb 等证据字段必须逐项为 true 才能放行。
|
||||
3. N-026-D/E:license、SBOM、source offer、deterministic package 为发布必需证据;
|
||||
manifest family 排序可确定性序列化,当前缺证据聚合为 `BLOCKED`,没有虚报发布通过。
|
||||
4. 当前 Chromium smoke 已通过引擎启动/Main 编辑与内容寻址资产恢复,并通过真实 64 KiB
|
||||
OPFS quota 下的失败保持旧 revision、Worker 重启恢复门。这只计为 partial evidence,不等于
|
||||
完整 suite 或其余 family 的桌面 golden。发布门 schema 2 仅接受 Chromium 浏览器证据。
|
||||
5. N-015 Curve/Surface/Font/Metaball 已通过 Blender 5.2 desktop geometry golden;这四类及
|
||||
PointCloud/Curves/Hair 共 7 对象已通过 GLB/USDA desktop round-trip。Volume/VDB 仍无 renderer
|
||||
与 loss fixture,这些证据也不替代其余 family 的 desktop golden。
|
||||
6. 当前发布包已通过本地 third-party notices、Blender/Three license 文件、无远程运行时依赖、
|
||||
非空 SHA-256 manifest、离线二进制/源码包确定性复建和 100k/1M decimate + 5 类损坏 blend
|
||||
拒绝门;这些是 partial evidence,不等于完整 SBOM/source offer、10M/长媒体或 OPFS quota。
|
||||
|
||||
## 仍然阻断
|
||||
|
||||
- 完整跨浏览器矩阵、跨 family 桌面 golden、离线/OPFS quota、1M/10M/长媒体基准和 fault fuzz 尚未有
|
||||
真实证据;上游 N-015 至 N-025 的阻断能力会传递到发布门。
|
||||
- 完整 release package 审计、许可证/source offer/SBOM、10M/长媒体性能和 OPFS quota 发布流程仍未完成;
|
||||
当前离线包确定性检查只覆盖已有二进制/源码归档门。
|
||||
|
||||
## 验收
|
||||
|
||||
```bash
|
||||
WEB_TEST_PORT=5326 npm --prefix web run test:e2e -- --grep "N-026 release"
|
||||
```
|
||||
17
docs/status/W-000.md
Normal file
17
docs/status/W-000.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# W-000 Status
|
||||
|
||||
status: done
|
||||
task: 固定源码和版本
|
||||
|
||||
## Evidence
|
||||
|
||||
- Blender source: `blender-5.2.0/`
|
||||
- Native binary: `build_blender_5.2.0/bin/blender`
|
||||
- Blender report: `Blender 5.2.0 LTS`
|
||||
- Toolchain: CMake 3.31.6, Ninja 1.12.1, Emscripten 3.1.69, Node 20.19.2, npm 9.2.0
|
||||
- Reference Git commit: `fbe6228777e7d9afefcd61a413844e790ae75db7`
|
||||
|
||||
## Risk
|
||||
|
||||
The reference `blender/` checkout was dirty before this work. It is not modified
|
||||
by the Web implementation.
|
||||
15
docs/status/W-001.md
Normal file
15
docs/status/W-001.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# W-001 Status
|
||||
|
||||
status: done
|
||||
task: 建立依赖和许可证清单
|
||||
|
||||
## Evidence
|
||||
|
||||
- Matrix: `docs/web/dependency-matrix.md`
|
||||
- Notices: `docs/web/third-party-notices.json`
|
||||
- No CAD kernel or Bitbybit/OCCT dependency is included.
|
||||
- Local runtime audit: `cd web && npm run check:local-deps` -> `local-dependencies-ok`.
|
||||
- Browser assets are vendored under `web/app/src/vendor/` and
|
||||
`web/app/public/vendor/`; no CDN/remote ESM URL is present in source or `dist/`.
|
||||
- Offline bootstrap check: `npm ci --offline --ignore-scripts` passed with the
|
||||
existing local npm cache.
|
||||
10
docs/status/W-002.md
Normal file
10
docs/status/W-002.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# W-002 Status
|
||||
|
||||
status: done
|
||||
task: 建立浏览器能力矩阵
|
||||
|
||||
## Evidence
|
||||
|
||||
- Capability implementation: `web/app/src/platform/capabilities.ts`
|
||||
- The probe is side-effect free and returns explicit false values when a browser
|
||||
API is unavailable. Browser screenshot validation is scheduled by W-015.
|
||||
11
docs/status/W-003.md
Normal file
11
docs/status/W-003.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# W-003 Status
|
||||
|
||||
status: done
|
||||
task: 建立 golden 场景目录
|
||||
|
||||
## Evidence
|
||||
|
||||
- Fixtures: `tests/files/web/empty.blend`, `tests/files/web/basic_scene.blend`
|
||||
- Manifest: `tests/files/web/manifest.json`
|
||||
- Golden manifest: `tests/golden/W-003/manifest.json`
|
||||
- Blender validation: empty scene has 0 objects; basic scene has 3 named objects.
|
||||
10
docs/status/W-004.md
Normal file
10
docs/status/W-004.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# W-004 Status
|
||||
|
||||
status: done
|
||||
task: 定义错误、进度和 revision 规范
|
||||
|
||||
## Evidence
|
||||
|
||||
- Error schema: `web/protocol/error.ts`
|
||||
- Progress schema: `web/protocol/progress.ts`
|
||||
- Protocol version: `web/protocol/schema-version` (`1`)
|
||||
10
docs/status/W-005.md
Normal file
10
docs/status/W-005.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# W-005 Status
|
||||
|
||||
status: done
|
||||
task: 规定数据坐标和颜色语义
|
||||
|
||||
## Evidence
|
||||
|
||||
- Contract: `docs/web/coordinate-color-contract.md`
|
||||
- Golden inputs: `tests/files/web/empty.blend`, `tests/files/web/basic_scene.blend`
|
||||
- Full adapter screenshot comparison is scheduled by W-051.
|
||||
11
docs/status/W-006.md
Normal file
11
docs/status/W-006.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# W-006 Status
|
||||
|
||||
status: done
|
||||
task: 建立任务状态和日志模板
|
||||
|
||||
## Evidence
|
||||
|
||||
- Status files are stored in `docs/status/`.
|
||||
- Golden manifests are stored under `tests/golden/<task-id>/`.
|
||||
- Baseline checker: `tools/web/check-baseline.sh`.
|
||||
- Task-card and validation rules: execution plan sections 4.1~4.3.
|
||||
21
docs/status/W-010.md
Normal file
21
docs/status/W-010.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# W-010 Status
|
||||
|
||||
status: done
|
||||
task: 创建 React 工程
|
||||
|
||||
## Evidence
|
||||
|
||||
- Package: `web/package.json`
|
||||
- Lockfile: `web/package-lock.json`
|
||||
- Build: `npm run build` passed with Vite 8.2.0.
|
||||
- Three.js: `0.185.1` vendored under `web/app/src/vendor/three/` (latest stable
|
||||
version selected from npm registry, then copied into the project).
|
||||
- Screenshot: `tests/golden/W-010/desktop-1440x900.png`
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
```
|
||||
15
docs/status/W-011.md
Normal file
15
docs/status/W-011.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# W-011 Status
|
||||
|
||||
status: done
|
||||
task: 建立应用布局和状态层
|
||||
|
||||
## Evidence
|
||||
|
||||
- App shell: `web/app/src/app/App.tsx`
|
||||
- UI styles: `web/app/src/app/app-shell.css`
|
||||
- Entry point: `web/app/src/main.tsx`
|
||||
- Screenshot: `tests/golden/W-011/layout-1440x900.png`
|
||||
|
||||
The first shell includes Blender-style Topbar, Workspace tabs, Viewport,
|
||||
Outliner, Properties, Timeline and StatusBar. Workspace selection and timeline
|
||||
frame state are local UI state; no geometry arrays are stored in React state.
|
||||
21
docs/status/W-012.md
Normal file
21
docs/status/W-012.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# W-012 Status
|
||||
|
||||
status: done
|
||||
task: 建立 EngineClient 和 Worker 通信
|
||||
|
||||
## Evidence
|
||||
|
||||
- Client: `web/app/src/engine-client/EngineClient.ts`
|
||||
- Worker: `web/app/src/workers/engine.worker.ts`
|
||||
- Protocol: `web/protocol/engine.ts`, `web/protocol/scene-ir.ts`
|
||||
- The browser status changes to `Mock Engine: r0` after init and snapshot.
|
||||
- Screenshot: `tests/golden/W-012/mock-worker-1440x900.png`
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
Chrome headless --virtual-time-budget=4000 # Mock Engine: r0
|
||||
```
|
||||
26
docs/status/W-013.md
Normal file
26
docs/status/W-013.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# W-013 Status
|
||||
|
||||
status: done
|
||||
task: 建立 Three.js 视口烟测
|
||||
|
||||
## Evidence
|
||||
|
||||
- Adapter: `web/app/src/three-adapter/viewport.ts`
|
||||
- Uses vendored Three.js `0.185.1` from `web/app/src/vendor/three/`,
|
||||
`WebGLRenderer`, `Scene`, `PerspectiveCamera`,
|
||||
`OrbitControls`, `GridHelper`, lights, resize observer and disposal.
|
||||
- No runtime CDN request is required; Playwright asserts all requests stay on
|
||||
the local dev origin.
|
||||
- Screenshot: `tests/golden/W-013/three-viewport-1440x900.png`
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
Chrome headless --use-gl=swiftshader --virtual-time-budget=60000 # rendered cube/grid
|
||||
```
|
||||
|
||||
The renderer failure path is contained in the viewport component, so browsers
|
||||
without a WebGL context keep the editor shell available.
|
||||
24
docs/status/W-014.md
Normal file
24
docs/status/W-014.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# W-014 Status
|
||||
|
||||
status: done
|
||||
task: 建立 StorageWorker 烟测(原生 IndexedDB)
|
||||
|
||||
## Evidence
|
||||
|
||||
- Client: `web/app/src/storage/StorageClient.ts`
|
||||
- Worker: `web/app/src/workers/storage.worker.ts`
|
||||
- Backend: browser-native IndexedDB in a dedicated Worker
|
||||
- Screenshot: `tests/golden/W-014/storage-viewport-1440x900.png`
|
||||
|
||||
The worker writes and reads a smoke record through IndexedDB and reports whether
|
||||
the Worker can also access OPFS. SQLite WASM is intentionally deferred because
|
||||
it is not required for the current project metadata and file workflow.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
npm run test:e2e # Storage: IndexedDB (or IndexedDB + OPFS)
|
||||
```
|
||||
20
docs/status/W-015.md
Normal file
20
docs/status/W-015.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# W-015 Status
|
||||
|
||||
status: done
|
||||
task: 建立 Playwright 冒烟测试
|
||||
|
||||
## Evidence
|
||||
|
||||
- Config: `web/playwright.config.ts`
|
||||
- Tests: `web/tests/e2e/smoke.spec.ts`
|
||||
- Browser: system Google Chrome with SwiftShader flags
|
||||
|
||||
The smoke suite covers editor startup, mock EngineWorker initialization,
|
||||
IndexedDB/OPFS capability status, Canvas presence, orbit input and Outliner
|
||||
scene content.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run test:e2e # 2 passed
|
||||
```
|
||||
23
docs/status/W-016.md
Normal file
23
docs/status/W-016.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# W-016 Status
|
||||
|
||||
status: done
|
||||
task: 建立资源 manifest 和 WASM 校验
|
||||
|
||||
## Evidence
|
||||
|
||||
- Manifest: `web/app/public/engine-manifest.json`
|
||||
- Protocol and loader: `web/protocol/manifest.ts`
|
||||
- App status reports `Manifest: verified r1`; the optional local `web_engine.wasm`
|
||||
resource is available for the real ABI worker path.
|
||||
|
||||
Version mismatch, malformed manifests, unavailable resources and digest
|
||||
mismatches reject before a required resource is accepted by the loader.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
npm run test:e2e # passed with manifest verification
|
||||
```
|
||||
18
docs/status/W-017.md
Normal file
18
docs/status/W-017.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# W-017 Status
|
||||
|
||||
status: done
|
||||
task: 完成 Web 壳里程碑
|
||||
|
||||
React + Three.js + EngineWorker + StorageWorker + versioned manifest now run
|
||||
together with the local minimal WebEngine ABI. The mock SceneIR remains the
|
||||
scene source in this milestone; Blender data libraries and `.blend` loading are
|
||||
deliberately deferred to W-030 and later.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
npm run test:e2e # 4 passed
|
||||
```
|
||||
21
docs/status/W-018.md
Normal file
21
docs/status/W-018.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# W-018 Status
|
||||
|
||||
status: done
|
||||
task: 定义 Blender 风格 UI 协议和上下文
|
||||
|
||||
## Evidence
|
||||
|
||||
- Protocol: `web/protocol/ui-schema.ts`
|
||||
- Golden: `tests/golden/W-018/ui-schema.json`
|
||||
- State includes versioned Workspace/Area/Region layout, active Editor,
|
||||
Blender mode, active object, selection, view layer, pinned data and revision.
|
||||
- `reduceUICommand()` keeps UI revisions separate from EngineWorker revisions.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck # passed
|
||||
npm run lint # passed
|
||||
npm run build # passed
|
||||
npm run test:e2e # 3 passed
|
||||
```
|
||||
23
docs/status/W-019.md
Normal file
23
docs/status/W-019.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# W-019 Status
|
||||
|
||||
status: done
|
||||
task: 实现 Blender 风格默认工作区和交互
|
||||
|
||||
## Evidence
|
||||
|
||||
- Shell: `web/app/src/app/App.tsx`
|
||||
- Styles: `web/app/src/app/app-shell.css`
|
||||
- Default areas: 3D Viewport, Outliner, Properties and Timeline.
|
||||
- Interactions: Layout/Modeling/Animation tabs, Object/Edit mode context and
|
||||
F3 Operator Search are wired through the UI command reducer.
|
||||
- Golden: `tests/golden/W-019/ui-layout-1440x900.png`
|
||||
|
||||
The current milestone implements the default shell and context routing. Area
|
||||
split/join and full OperatorRegistry commands remain later work, as specified
|
||||
by W-069 and the subsequent modeling packages.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run test:e2e # 3 passed
|
||||
```
|
||||
21
docs/status/W-020.md
Normal file
21
docs/status/W-020.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# W-020 Status
|
||||
|
||||
status: done
|
||||
task: 建立 Emscripten 工具链
|
||||
|
||||
## Evidence
|
||||
|
||||
- Environment: `tools/web/emscripten-env.sh`
|
||||
- Smoke runner: `tools/web/check-emscripten.sh`
|
||||
- Source: `web/engine/emscripten_smoke.c`
|
||||
- Golden: `tests/golden/W-020/toolchain.json`
|
||||
|
||||
The fixed toolchain is Emscripten 3.1.69. The smoke runner builds both a
|
||||
single-thread and pthread WASM module with ES module, Worker environment,
|
||||
memory growth and filesystem flags.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
tools/web/check-emscripten.sh # emscripten-toolchain-ok
|
||||
```
|
||||
22
docs/status/W-021.md
Normal file
22
docs/status/W-021.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# W-021 Status
|
||||
|
||||
status: done
|
||||
task: 添加 Web CMake 平台
|
||||
|
||||
## Evidence
|
||||
|
||||
- Platform policy: `blender-5.2.0/build_files/cmake/platform/web.cmake`
|
||||
- Standalone target: `web/engine/CMakeLists.txt`
|
||||
- Configure/build runner: `tools/web/configure-web-engine.sh`
|
||||
- Golden: `tests/golden/W-021/cmake-cache.json`
|
||||
|
||||
The Web platform fragment enforces Emscripten, disables desktop GHOST,
|
||||
Python, Cycles and optional desktop codecs, and sets ES module/Worker output
|
||||
flags. It is currently consumed by the isolated smoke target; the full Blender
|
||||
target integration remains the next C-stage task.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
tools/web/configure-web-engine.sh # web-cmake-ok
|
||||
```
|
||||
23
docs/status/W-022.md
Normal file
23
docs/status/W-022.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# W-022 Status
|
||||
|
||||
status: done
|
||||
task: 建立最小 web_engine target
|
||||
|
||||
## Evidence
|
||||
|
||||
- C ABI header: `blender-5.2.0/source/blender/web_engine/web_engine_api.h`
|
||||
- C ABI implementation: `blender-5.2.0/source/blender/web_engine/web_engine_api.cpp`
|
||||
- CMake target: `web/engine/CMakeLists.txt`
|
||||
- Golden: `tests/golden/W-022/web-engine-api.json`
|
||||
|
||||
The standalone target remains an ABI-only smoke target and links a test reader
|
||||
stub. The canonical Blender data target is `blender-5.2.0` with
|
||||
`WITH_WEB=ON` (`build_web_blender6/bin/web_engine.*`); it links BLO/DNA and the
|
||||
vendored zlib/zstd readers behind the same handle boundary.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
tools/web/configure-web-engine.sh # standalone ABI gate
|
||||
node tools/web/run-web-engine-smoke.mjs # web-engine-blend-ok
|
||||
```
|
||||
20
docs/status/W-023.md
Normal file
20
docs/status/W-023.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# W-023 Status
|
||||
|
||||
status: done
|
||||
task: 处理 Emscripten 运行参数
|
||||
|
||||
## Evidence
|
||||
|
||||
- Platform flags: `blender-5.2.0/build_files/cmake/platform/web.cmake`
|
||||
- Variant runner: `tools/web/build-web-engine-variants.sh`
|
||||
- Golden: `tests/golden/W-023/runtime-profiles.json`
|
||||
|
||||
Single-thread and pthread builds use `MODULARIZE`, `EXPORT_ES6`,
|
||||
`ENVIRONMENT=web,worker`, memory growth and filesystem flags. The pthread
|
||||
artifact is explicitly marked as requiring COOP/COEP at runtime.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
tools/web/build-web-engine-variants.sh # passed
|
||||
```
|
||||
21
docs/status/W-024.md
Normal file
21
docs/status/W-024.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# W-024 Status
|
||||
|
||||
status: done
|
||||
task: 固定内存和分配策略
|
||||
|
||||
## Evidence
|
||||
|
||||
- Memory ABI: `web_engine_get_memory_stats()` and scalar accessors
|
||||
- Golden: `tests/golden/W-024/memory-stats.json`
|
||||
- Node smoke: `tools/web/run-web-engine-smoke.mjs`
|
||||
|
||||
The ABI reports live handles and allocated bytes without exposing WASM heap
|
||||
pointers to React. Document memory is held inside the engine state and output
|
||||
buffers are explicitly freed after save; the first mesh snapshot also retains
|
||||
bounded arrays before the later transferable-buffer path.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
node tools/web/run-web-engine-smoke.mjs # blend open/save, then destroy
|
||||
```
|
||||
22
docs/status/W-025.md
Normal file
22
docs/status/W-025.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# W-025 Status
|
||||
|
||||
status: done
|
||||
task: 建立 Web C ABI
|
||||
|
||||
## Evidence
|
||||
|
||||
- Header: `blender-5.2.0/source/blender/web_engine/web_engine_api.h`
|
||||
- Implementation: `blender-5.2.0/source/blender/web_engine/web_engine_api.cpp`
|
||||
- Golden: `tests/golden/W-025/c-api.json`
|
||||
|
||||
The ABI now has stable POD pointer/length entry points for create/destroy,
|
||||
open, apply, snapshot, save and buffer release. Open accepts an empty input;
|
||||
command and full `.blend` serialization return an explicit not-implemented
|
||||
code until Blender libraries are linked.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
tools/web/build-web-engine-variants.sh # passed
|
||||
node tools/web/run-web-engine-smoke.mjs # passed
|
||||
```
|
||||
20
docs/status/W-026.md
Normal file
20
docs/status/W-026.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# W-026 Status
|
||||
|
||||
status: done
|
||||
task: 接入 Blender 报告系统边界
|
||||
|
||||
## Evidence
|
||||
|
||||
- Error ABI: `web_engine_last_error_code()` and
|
||||
`web_engine_last_error_message()`
|
||||
- Golden: `tests/golden/W-026/error-report.json`
|
||||
- Error codes are deterministic and do not expose raw WASM pointers to the UI.
|
||||
|
||||
The native Blender `ReportList` bridge is deferred until W-030 data libraries
|
||||
are linked; this task freezes the Web-facing error contract first.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
node tools/web/run-web-engine-smoke.mjs # explicit -3 not-implemented path
|
||||
```
|
||||
27
docs/status/W-027.md
Normal file
27
docs/status/W-027.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# W-027 Status
|
||||
|
||||
status: done
|
||||
task: 建立真实 WebEngineWorker ready 路径
|
||||
|
||||
## Evidence
|
||||
|
||||
- Worker: `web/app/src/workers/web-engine.worker.ts`
|
||||
- Client: `web/app/src/engine-client/WebEngineClient.ts`
|
||||
- Vendored runtime: `web/app/src/vendor/blender/web_engine.js` and
|
||||
`web/app/src/vendor/blender/web_engine.wasm`
|
||||
- Static deployment copies: `web/app/public/vendor/blender/`
|
||||
- Install script: `tools/web/install-web-engine-assets.sh`
|
||||
- Golden: `tests/golden/W-027/worker-ready.json`
|
||||
|
||||
The worker dynamically imports the local Emscripten glue, fetches the local
|
||||
WASM asset, initializes the ABI and returns deterministic memory stats. The UI
|
||||
reports this as `WASM ABI: ready`; `.blend` loading now uses the same real ABI
|
||||
and returns SceneIR snapshots. The legacy mock EngineClient remains only for
|
||||
protocol regression tests.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run test:e2e # 4 passed, including local web_engine worker
|
||||
npm run build # web-engine.worker and vendor/blender assets present
|
||||
```
|
||||
22
docs/status/W-028.md
Normal file
22
docs/status/W-028.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# W-028 Status
|
||||
|
||||
status: done
|
||||
task: 原生/WASM 双端回归
|
||||
|
||||
## Evidence
|
||||
|
||||
- Native runner: `web/engine/web_engine_native_smoke.cpp`
|
||||
- Dual runner: `tools/web/check-dual-engine.sh`
|
||||
- Golden: `tests/golden/W-028/dual-engine.json`
|
||||
|
||||
The same C ABI returns matching create, invalid-empty-open, and destroy
|
||||
results in native C++ and Emscripten builds. The WASM runner additionally
|
||||
opens local `.blend` fixtures, checks SceneIR, verifies an authoritative
|
||||
Main save/reopen, verifies ordinary decimate Main write/save/reopen, and verifies that the
|
||||
skin/shape-key decimate boundary blocks save with `BLEND_WRITE_REQUIRES_MAIN_AUTHORITY`.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
tools/web/check-dual-engine.sh # dual-engine-ok
|
||||
```
|
||||
23
docs/status/W-029.md
Normal file
23
docs/status/W-029.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# W-029 Status
|
||||
|
||||
status: done
|
||||
task: 完成最小引擎里程碑
|
||||
|
||||
## Evidence
|
||||
|
||||
- Gate: `tests/golden/W-029/min-engine-gate.json`
|
||||
- Local browser worker: `web/app/src/workers/web-engine.worker.ts`
|
||||
- Native/WASM check: `tools/web/check-dual-engine.sh`
|
||||
|
||||
The Web runtime has a reproducible Blender/Emscripten CMake target, local
|
||||
worker loading and a stable C ABI gate. The canonical target links the local
|
||||
Blender BLO/DNA reader and is vendored into both source and public asset trees;
|
||||
the UI opens `.blend` ArrayBuffers and displays the resulting SceneIR.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run build # passed
|
||||
npm run test:e2e # 5 passed
|
||||
tools/web/check-dual-engine.sh # passed, including empty/basic/save fixture
|
||||
```
|
||||
30
docs/status/W-030.md
Normal file
30
docs/status/W-030.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# W-030 Status
|
||||
|
||||
status: done
|
||||
task: 从内存读取 `.blend`
|
||||
|
||||
## Evidence
|
||||
|
||||
- Reader: `blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp`
|
||||
- ABI: `web_engine_open_blend(handle, data, length)` copies an `ArrayBuffer` into
|
||||
WASM memory and never receives a browser or POSIX path.
|
||||
- Worker: `web/app/src/workers/web-engine.worker.ts` reports started/progress/completed
|
||||
phases and maps malformed input to `BLEND_READ_FAILED`.
|
||||
- Golden: `tests/golden/W-030/manifest.json`
|
||||
|
||||
The reader accepts uncompressed, gzip and zstd Blender streams, validates the
|
||||
little-endian Blender header, decodes the embedded DNA1 schema and returns an
|
||||
empty or populated SceneIR snapshot. `empty.blend` and `basic_scene.blend` are
|
||||
both exercised by the WASM smoke.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
node tools/web/run-web-engine-smoke.mjs # empty + basic + save passed
|
||||
tools/web/check-dual-engine.sh # native ABI + WASM reader passed
|
||||
```
|
||||
|
||||
## Remaining risk
|
||||
|
||||
The first reader is deliberately bounded to a 1 GiB block and summary export;
|
||||
evaluated mesh buffers are W-033.
|
||||
29
docs/status/W-031.md
Normal file
29
docs/status/W-031.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# W-031 Status
|
||||
|
||||
status: done
|
||||
task: 定义 SceneIR v1
|
||||
|
||||
## Evidence
|
||||
|
||||
- TypeScript contract: `web/protocol/scene-ir.ts`
|
||||
- C++ serializer: `blender-5.2.0/source/blender/web_engine/web_engine_blend_reader.cpp`
|
||||
- Golden: `tests/golden/W-031/scene-ir-v1.json`
|
||||
|
||||
SceneIR v1 now carries versioned source metadata, Blender Z-up coordinate
|
||||
semantics, stable type/name IDs, nodes, collections, meshes, materials, images,
|
||||
cameras, lights, animations, scenes, frame bounds and active object. Browser
|
||||
validation rejects unsupported schema, coordinate, matrix and tuple shapes.
|
||||
IDs are generated from Blender ID names with deterministic duplicate suffixes;
|
||||
the wire format contains no raw WASM pointer.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm run typecheck
|
||||
node tools/web/run-web-engine-smoke.mjs
|
||||
```
|
||||
|
||||
## Remaining risk
|
||||
|
||||
Image and animation arrays are schema-ready but are still empty until their
|
||||
datablock extraction tasks are implemented.
|
||||
28
docs/status/W-032.md
Normal file
28
docs/status/W-032.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# W-032 Status
|
||||
|
||||
status: done
|
||||
task: 导出场景树和集合
|
||||
|
||||
## Evidence
|
||||
|
||||
- C++ collection/object traversal: `web_engine_blend_reader.cpp`
|
||||
- Dynamic Outliner: `web/app/src/app/App.tsx`
|
||||
- Golden: `tests/golden/W-032/basic-scene-tree.json`
|
||||
|
||||
The reader resolves Scene root collections, linked collection objects, object
|
||||
parent/data links, active camera, local/world matrices, viewport visibility and
|
||||
selectability. Collection and node arrays are sorted by stable IDs before
|
||||
serialization; parent cycles fall back to the local matrix instead of recursing
|
||||
without a bound.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
node tools/web/run-web-engine-smoke.mjs
|
||||
npm run test:e2e # local basic_scene.blend appears in Outliner
|
||||
```
|
||||
|
||||
## Remaining risk
|
||||
|
||||
The fixture proves one nested collection. View-layer overrides and evaluated
|
||||
depsgraph visibility remain part of the later scene-context work.
|
||||
37
docs/status/W-033.md
Normal file
37
docs/status/W-033.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# W-033 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 导出 MeshIR
|
||||
|
||||
## Implemented
|
||||
|
||||
Mesh summaries export vertex, edge, face and corner counts. Blender 5.2
|
||||
`AttributeStorage` DATA blocks are now resolved by exact old-pointer matches
|
||||
and by SDNA pointer width. The reader exports position floats, normals,
|
||||
triangulated corner indices, corner UV/color attributes, triangle material
|
||||
indices, material slot IDs and object-space bounds with
|
||||
`geometryStatus: "available"`. The Three adapter applies Z-up conversion,
|
||||
uses exported normals, expands corner attributes into render vertices, and
|
||||
binds local material groups.
|
||||
|
||||
## Accepted bounded scope
|
||||
|
||||
The exporter now includes tangent and corner split-normal buffers, seam/sharp
|
||||
edge flags, custom attribute metadata, vertex groups and UV-layer selection.
|
||||
The native WBG1 C ABI carries these buffers without JSON construction and the
|
||||
Worker validates/transfers them to Three.js. Mesh Edit operations rebuild
|
||||
topology metadata through Blender Main and reject linked/shape-key topology
|
||||
changes with structured errors.
|
||||
|
||||
Evaluated buffers for unsupported modifier/simulation families remain blocked
|
||||
by the N-002 capability matrix; this is an explicit boundary rather than a
|
||||
claim of universal modifier evaluation.
|
||||
|
||||
The field and future transferable layout is documented in
|
||||
`docs/web/mesh-buffer-layout.md`.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
node tools/web/run-web-engine-smoke.mjs # basic + attribute fixtures
|
||||
```
|
||||
29
docs/status/W-034.md
Normal file
29
docs/status/W-034.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# W-034 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 导出材质、贴图和颜色
|
||||
|
||||
## Implemented
|
||||
|
||||
The SceneIR contract includes Principled-compatible base color, roughness,
|
||||
metallic, emission, alpha and IOR fields. The native reader walks embedded
|
||||
Principled node inputs, collects Image Texture IDs, and emits warnings for
|
||||
linked inputs or unsupported nodes. Blender Image datablocks export stable
|
||||
asset IDs, MIME guesses, generated dimensions and the original (possibly
|
||||
`//`-relative) source path without embedding base64 pixels. The EngineWorker
|
||||
exposes a local `requestAsset` metadata path for external and
|
||||
packed-unavailable assets. The Three adapter applies the exported material
|
||||
color, metalness, roughness, emission and alpha to local materials.
|
||||
|
||||
## Accepted bounded scope
|
||||
|
||||
Material slots can be created, removed and assigned to selected faces through
|
||||
Blender Main. The Web authoring surface writes Principled values and creates a
|
||||
limited `Principled -> Output`, `Image Texture`, `Normal Map` and `UV Map` graph.
|
||||
PNG/JPEG imports become packed Blender Image datablocks without allocating a
|
||||
headless ImBuf, and active UV-map/planar/cube unwrap operations round-trip.
|
||||
Packed bytes remain available through the asset API and are covered by the
|
||||
UDIM/generated/linked/corrupt resource matrix.
|
||||
|
||||
Arbitrary node graphs and renderer-specific shader execution are deliberately
|
||||
outside this bounded contract; unsupported nodes are reported by SceneIR.
|
||||
24
docs/status/W-035.md
Normal file
24
docs/status/W-035.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# W-035 Status
|
||||
|
||||
status: in_progress
|
||||
task: 导出相机和灯光
|
||||
|
||||
## Implemented
|
||||
|
||||
Perspective/orthographic camera fields, sensor/shift values, clip range and
|
||||
orthographic scale are read from the file and are visible in the SceneIR
|
||||
snapshot. Light type/color/energy, radius, spot cone, area dimensions and sun
|
||||
angle are exported. World background color and exposure are also versioned.
|
||||
The Three adapter creates local point/spot/directional/area light objects and
|
||||
applies the exported World color to the viewport background.
|
||||
|
||||
## Not yet accepted
|
||||
|
||||
Sensor fit is exported numerically, but exact sensor-fit projection math,
|
||||
camera replacement for orthographic view, light target direction, and complete
|
||||
world node settings remain pending.
|
||||
|
||||
## Golden fixture
|
||||
|
||||
`tests/golden/W-035/camera-light-world.json` covers the real
|
||||
`basic_scene.blend` camera, area light and world linkage.
|
||||
28
docs/status/W-036.md
Normal file
28
docs/status/W-036.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# W-036 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 导出动画和帧状态
|
||||
|
||||
## Implemented
|
||||
|
||||
Scene frame current/start/end and object transforms are exported from the
|
||||
serialized Scene block. Legacy FCurve lists and Blender 5.2 layered Actions
|
||||
(keyframe strips/channelbags) are decoded into target-scoped `AnimationIR`
|
||||
channels with RNA paths, scalar keyframes and bounded frame ranges. The
|
||||
Timeline uses scene bounds instead of a fixed 250-frame range after a `.blend`
|
||||
is opened.
|
||||
|
||||
## Accepted bounded scope
|
||||
|
||||
Timeline keyframe insertion/deletion for object location, Euler rotation and
|
||||
scale writes Blender layered Actions through Main. The UI exposes frame range,
|
||||
key dots, active Action and CONSTANT/LINEAR/BEZIER interpolation selection.
|
||||
Object constraint enable/influence is editable and node constraints plus pose
|
||||
constraints are exported in SceneIR. Frame/pose goldens cover 1/5/10/15 and
|
||||
save/reopen compares evaluated matrices and vertices.
|
||||
|
||||
The N-014 bounded extension now reads and atomically replaces single-object
|
||||
Action Clip stacks, and Blender's native depsgraph evaluates the saved Main at
|
||||
the requested frame. Transition/meta/sound strips, Animated Time, reverse,
|
||||
Drivers, complete blending matrices and arbitrary constraint types remain
|
||||
structured future extensions; Three.js does not approximate them.
|
||||
26
docs/status/W-037.md
Normal file
26
docs/status/W-037.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# W-037 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 实现场景完整快照
|
||||
|
||||
## Implemented
|
||||
|
||||
`get_scene_snapshot` remains a validated JSON compatibility ABI, including
|
||||
bounded positions/index/normals and optional
|
||||
UV/color/material-slot arrays for available meshes. The Worker validates that
|
||||
fallback snapshot, packs the geometry into little-endian `Float32Array`/`Uint32Array`
|
||||
buffers, strips the large arrays from the browser snapshot, and transfers the
|
||||
buffers to React/Three.js. Browser parsing is centralized in
|
||||
`parseSceneSnapshotIR` and failures become stable worker error reports. The
|
||||
envelope and chunk rules are documented in `docs/web/mesh-buffer-layout.md`.
|
||||
|
||||
## Accepted bounded scope
|
||||
|
||||
The preferred native WBG1 metadata/geometry ABI now emits positions, indices,
|
||||
corner attributes, material/face/edge indices, tangents and split normals as
|
||||
tightly packed little-endian buffers. The Worker validates lengths/bounds and
|
||||
keeps large arrays out of React state. Per-mesh envelopes, Worker processing,
|
||||
Three.js frustum culling, linked-data `InstancedMesh` groups and LOD cover the
|
||||
current large-scene contract. `?offscreen=1` capability-gates real canvas/WebGL
|
||||
ownership in a render Worker with orbit, selection and nonblank-pixel E2E;
|
||||
unsupported browsers retain the main-thread renderer.
|
||||
29
docs/status/W-038.md
Normal file
29
docs/status/W-038.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# W-038 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 实现场景增量
|
||||
|
||||
## Implemented
|
||||
|
||||
`web/protocol/scene-delta.ts` defines revisioned node add/update/remove, active
|
||||
object/frame changes and mesh/material/camera/light/animation resources.
|
||||
`diffSceneSnapshots` emits changed node and resource fields;
|
||||
`applySceneDelta` rejects stale base revisions and returns sorted immutable node
|
||||
arrays. The native C ABI computes the same minimal delta whenever a new
|
||||
`.blend` is opened, and the Worker exposes it through the `delta` request after
|
||||
validating the envelope. The command registry covers scene/frame state,
|
||||
modifier switches, mesh editing, material/UV authoring, keyframes/constraints
|
||||
and object hierarchy operations. Each command mutates Blender Main and returns
|
||||
the corresponding revisioned delta through `applyCommand`.
|
||||
|
||||
## Accepted bounded scope
|
||||
|
||||
SceneDelta now covers resource collections for meshes, materials, cameras,
|
||||
lights and animations in addition to nodes/frame/active object. Mesh payloads
|
||||
transfer separately so topology and attribute changes replace the associated
|
||||
resource envelope, while node-only changes stay in place. All declared
|
||||
authoring commands are Main-authoritative and covered by save/reopen. Fine-
|
||||
grained `MeshGeometryDelta` patches now transfer only changed byte ranges when
|
||||
field lengths stay stable; topology/attribute layout changes replace only the
|
||||
affected per-mesh envelope. The main-thread client applies patches immutably
|
||||
and retains unchanged mesh buffers.
|
||||
25
docs/status/W-039.md
Normal file
25
docs/status/W-039.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# W-039 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 完成场景数据里程碑
|
||||
|
||||
## Current gate
|
||||
|
||||
The `.blend` -> Blender Main/WASM -> binary SceneIR -> Three.js path is proven
|
||||
for basic, animation, pose, modifier, resource and authoring fixtures. The
|
||||
browser opens files, renders geometry, keeps Outliner/viewport selection linked,
|
||||
and applies Main edits with revisioned snapshot/delta responses.
|
||||
|
||||
## Accepted bounded scope
|
||||
|
||||
W-034 through W-038 are complete for the declared bounded contract: binary
|
||||
SceneIR, resource deltas, packed assets, animation editing and Blender Main
|
||||
authoring all have native and browser regression evidence. New Blender
|
||||
families must add independent goldens instead of reusing W-080.
|
||||
|
||||
## Verification
|
||||
|
||||
```text
|
||||
npm --prefix web run test:e2e
|
||||
npm --prefix web run test:authoring-roundtrip
|
||||
```
|
||||
14
docs/status/W-040.md
Normal file
14
docs/status/W-040.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# W-040 Status
|
||||
|
||||
status: in_progress
|
||||
task: 固定 OPFS 目录布局
|
||||
|
||||
`web/app/src/storage/opfs-files.ts` validates project IDs and file names,
|
||||
creates `projects/<id>/scene.blend`, `snapshots/`, `assets/`, `thumbs/` and
|
||||
`tmp/`, and writes a complete scene buffer through a temporary file before
|
||||
replacement. The standard `FileSystemHandle.move` path is used when available;
|
||||
the copy-and-remove fallback is bounded to the same project directory.
|
||||
|
||||
Large asset hashing, crash-recovery manifests and cross-browser atomic rename
|
||||
guarantees remain subsequent tasks.
|
||||
|
||||
12
docs/status/W-041.md
Normal file
12
docs/status/W-041.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# W-041 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 建立 IndexedDB schema 和 migration
|
||||
|
||||
`web/app/src/storage/migrations.ts` upgrades `blender-web-metadata` to schema
|
||||
version 4 while preserving the existing smoke store. It creates `project`,
|
||||
`asset`, `snapshot`, `operation_log`, `setting` and `migration` stores and
|
||||
records each schema migration. Schema 4 adds content-addressed asset metadata;
|
||||
StorageWorker `info`, project layout and Worker-restart discovery are covered by Playwright.
|
||||
|
||||
Downgrade/rollback across older deployed browser builds remains outside the current scope.
|
||||
16
docs/status/W-042.md
Normal file
16
docs/status/W-042.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# W-042 Status
|
||||
|
||||
status: done
|
||||
task: 保存 `.blend` 原子事务
|
||||
|
||||
StorageWorker `saveProject` accepts a transferable ArrayBuffer, creates the
|
||||
OPFS project layout, writes and SHA-256-verifies `scene.blend.<uuid>.stage`, records a
|
||||
recovery journal, and uses same-directory move (or a complete-copy fallback) before re-verifying
|
||||
`scene.blend`. Only then does it write the manifest, clear the journal and update the IndexedDB
|
||||
`project` record with revision, byte count, digest, backend and timestamp.
|
||||
The React Save command now submits this transaction before downloading the
|
||||
`.blend` Blob, and keeps the StorageClient alive for the project session.
|
||||
When OPFS is unavailable, the record stores the buffer in IndexedDB instead.
|
||||
Playwright injects failures after staging and after scene commit, restarts the Worker, and verifies
|
||||
exact bytes/revision/digest through `readProject`. Concurrent same-project saves are serialized and
|
||||
the last submitted revision wins without journal races.
|
||||
13
docs/status/W-043.md
Normal file
13
docs/status/W-043.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# W-043 Status
|
||||
|
||||
status: done
|
||||
task: 自动保存和快照策略
|
||||
|
||||
`AutosaveScheduler` debounces a dirty project and submits the current engine
|
||||
buffer through StorageWorker after 1.5 seconds without triggering a download.
|
||||
The React Save button reuses the same persistence path before exporting a
|
||||
download. A browser regression confirms the dirty marker returns to saved.
|
||||
|
||||
Every ten commands and every explicit save now retain a SHA-256 verified blend snapshot. The
|
||||
StorageWorker enforces count and total-byte limits and can list/read retained revisions. Large-file
|
||||
writes remain Worker-isolated and never block the renderer thread.
|
||||
16
docs/status/W-044.md
Normal file
16
docs/status/W-044.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# W-044 Status
|
||||
|
||||
status: done
|
||||
task: 记录操作日志和恢复
|
||||
|
||||
StorageWorker now validates and persists operation records with project id,
|
||||
revision, payload, inverse payload and timestamp in IndexedDB's
|
||||
`operation_log` store. StorageClient exposes `appendOperation`, and the
|
||||
operation/inverse path has a browser regression.
|
||||
|
||||
Project file recovery is now separate and complete for the current save path:
|
||||
an OPFS SHA-256 journal recovers interrupted staging/commit after Worker restart.
|
||||
|
||||
Schema 5 adds corruption quarantine. Recovery sorts validated operations by revision/time/ID,
|
||||
rejects revision conflicts, opens the committed project or latest retained snapshot, and applies
|
||||
only uncommitted replayable commands to the native Main. A successful save prunes committed rows.
|
||||
22
docs/status/W-050.md
Normal file
22
docs/status/W-050.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# W-050 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: SceneIR adapter
|
||||
|
||||
ViewportRenderer now tags imported meshes and lights with
|
||||
`userData.blenderId`, `userData.sceneNodeId` and `userData.revision`, keeps a
|
||||
Blender-ID object index, and exposes `applyDelta()`. Pure node visibility and
|
||||
transform updates mutate the existing Three object; node lifecycle changes
|
||||
fall back to a validated snapshot rebuild so geometry/material ownership stays
|
||||
correct.
|
||||
|
||||
The adapter now performs mesh raycast selection and applies multi-selection
|
||||
highlights, consumes binary WBG1 mesh resources, and installs validated LOD
|
||||
levels with hysteresis. Resource-aware SceneDelta entries trigger a validated
|
||||
resource rebuild while node-only deltas update existing Three objects.
|
||||
|
||||
The Worker keeps the previous geometry generation and emits byte-range patches
|
||||
or affected-mesh replacements. Objects sharing one Blender Mesh datablock are
|
||||
coalesced into a raycastable `InstancedMesh` with per-instance transform and
|
||||
selection. A capability-gated OffscreenCanvas Worker owns WebGL when requested;
|
||||
browsers without that capability retain the same main-thread renderer.
|
||||
11
docs/status/W-052.md
Normal file
11
docs/status/W-052.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# W-052 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 相机和输入系统
|
||||
|
||||
OrbitControls, resize handling and mouse orbit are active in the local Three
|
||||
viewport. Timeline transport controls now implement first/previous/play/next/
|
||||
last frame state transitions over the imported SceneIR range. Exact Blender
|
||||
camera basis conversion is preserved at the adapter boundary. Object/Edit mode keyboard dispatch
|
||||
and draggable X/Y/Z transform handles route to Main commands; additional view presets and touch
|
||||
gesture variants remain additive UI work.
|
||||
12
docs/status/W-053.md
Normal file
12
docs/status/W-053.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# W-053 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 选择和 Outliner 联动
|
||||
|
||||
Outliner rows are keyboard- and pointer-activatable and update
|
||||
`SceneSnapshotIR.activeObjectId`; the Three adapter consumes the new snapshot
|
||||
and highlights the active object's material. Stable Blender IDs are used for
|
||||
the binding.
|
||||
|
||||
Viewport raycast selection, Shift/Ctrl multi-select, hidden-object filtering and deletion cleanup
|
||||
are implemented. Selected IDs remain a UI-session concern while the active ID stays in SceneIR.
|
||||
34
docs/status/W-060.md
Normal file
34
docs/status/W-060.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# W-060 Status
|
||||
|
||||
status: done_current_scope
|
||||
task: 对象模式命令
|
||||
|
||||
The first native command registry slice is implemented end to end. The Worker
|
||||
serializes validated `WebEngineEditCommand` payloads into the local Blender
|
||||
WASM ABI, and the native engine currently supports:
|
||||
|
||||
- `setFrame`: updates the current timeline frame and emits a frame SceneDelta.
|
||||
- `setObjectVisibility`: updates an existing object node and emits a node update
|
||||
SceneDelta.
|
||||
- `setModifierEnabled`: updates the persistent modifier mode in Blender Main.
|
||||
- `decimateMesh`: commits ordinary mesh topology/UV/color/material output to Blender Main;
|
||||
skin/shape-key replacement remains structurally blocked from save.
|
||||
- `undo`/`redo`: restore both SceneIR and a reopenable Blender Main history entry.
|
||||
- `createPrimitive`, `duplicateObject`, `deleteObject`: mutate Main IDs and Collections, then rebuild SceneIR from the writer buffer; linked duplicate preserves the shared Mesh datablock for instancing.
|
||||
- `setObjectTransform`, `translateMeshVertices`: persist Object Mode TRS and the first Edit Mode vertex workflow.
|
||||
- `meshEdit`: Main-authoritative Merge, Dissolve, Extrude, Inset, Bevel and Loop Cut transactions.
|
||||
- UV/material/image commands: UV map lifecycle/projection, material slots/face assignment, bounded Principled graph and packed PNG/JPEG images.
|
||||
- animation/hierarchy commands: keyframes/interpolation/actions, constraints, parent/collection moves, rename, Join/Separate, Apply Transform and Origin.
|
||||
|
||||
The commands have native smoke coverage and browser E2E tests that check
|
||||
revision base/next values and the resulting snapshot. Unknown commands and
|
||||
malformed payloads return typed native errors.
|
||||
|
||||
The Blender-style UI now routes Timeline frame changes and Outliner eye-button
|
||||
visibility changes through the same command path. React SceneIR, transferable
|
||||
geometry state, Three visibility and the dirty marker are updated from the
|
||||
command response; the browser E2E suite covers the Outliner interaction.
|
||||
|
||||
Every declared command writes back to `.blend`, survives undo/redo and passes save/reopen
|
||||
regression. Unsupported modifier families, mutations of read-only linked-library IDs and topology
|
||||
changes that would invalidate shape keys remain structured native blocks.
|
||||
35
docs/status/W-073.md
Normal file
35
docs/status/W-073.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# W-073 Status
|
||||
|
||||
status: in_progress
|
||||
task: 定义 Blender 三角面简化和 LOD 协议
|
||||
|
||||
`web/protocol/simplify.ts` now defines versioned `SimplifyProfile`,
|
||||
`SimplifyResult` and `LODManifest` contracts. The profile validator keeps the
|
||||
Blender modifier modes separate:
|
||||
|
||||
- `COLLAPSE` requires `ratio` in `(0, 1]` and supports triangle budget,
|
||||
vertex-group weighting/inversion, triangulate, symmetry axis and tolerance.
|
||||
- `UNSUBDIV` requires a positive integer `iterations` and rejects collapse or
|
||||
dissolve-only parameters.
|
||||
- `DISSOLVE_PLANAR` requires `angleLimit` in `[0, PI]`, with explicit
|
||||
boundary delimit flags and dissolve-boundary handling.
|
||||
|
||||
The parser also enforces non-negative source revisions and error codes for
|
||||
missing vertex groups, unsupported cross-mode fields, invalid budgets and LOD
|
||||
manifests whose triangle budgets do not decrease. A browser E2E test covers a
|
||||
valid collapse profile, a two-level manifest and the missing-vertex-group
|
||||
failure.
|
||||
|
||||
The common profile now carries an explicit `attributePolicy`
|
||||
(`PRESERVE`/`RECOMPUTE_NORMALS`/`DROP`) and a validated `SkinSimplifyPolicy`
|
||||
with maximum influences, minimum weight, maximum position error and shape-key
|
||||
handling. Vertex-group and symmetry-only fields are conditionally optional, so
|
||||
the TypeScript contract and runtime validator no longer disagree when those
|
||||
features are disabled.
|
||||
|
||||
The protocol is now exercised end-to-end by the native/WASM command path:
|
||||
`decimateMesh` validates `sourceMeshRevision`, returns a new SceneIR revision,
|
||||
and the browser-facing smoke checks topology counts, index bounds and attribute
|
||||
buffer lengths. Native Blender/WASM golden parity for all parameter
|
||||
combinations remains part of W-079; implementation of the declared skin policy
|
||||
remains W-076.
|
||||
37
docs/status/W-074.md
Normal file
37
docs/status/W-074.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# W-074 Status
|
||||
|
||||
status: in_progress
|
||||
task: 编译并复用 Blender Decimate 实现
|
||||
|
||||
`web_engine_decimate.cpp` now wraps Blender's native BMesh decimate entry points
|
||||
(`BM_mesh_decimate_collapse`, `BM_mesh_decimate_unsubdivide` and
|
||||
`BM_mesh_decimate_dissolve`) behind the local `web_engine_decimate_apply`
|
||||
two-pass C ABI. The wrapper accepts triangle buffers, returns required output
|
||||
capacities on the first call, and leaves the input mesh untouched.
|
||||
|
||||
`web_engine_apply_command` now accepts `decimateMesh` with a versioned
|
||||
`SimplifyProfile`, validates the source revision, calls the native wrapper, and
|
||||
replaces the evaluated SceneIR mesh topology. The command allocates output from
|
||||
the input upper bounds and evaluates Decimate once; it does not run the
|
||||
modifier twice merely to query exact capacities. Normals are recomputed from
|
||||
the result, BMFace material indices are retained, and UV/float-color corners
|
||||
are transferred by the W-076 policy layer. Collapse now accepts boundary and
|
||||
non-manifold triangle meshes through the same BMesh bridge. The blend reader
|
||||
reconstructs corner vertices from `.corner_edge` and `.edge_verts` only after
|
||||
validating every face cycle, so it never treats edge indices as vertex indices.
|
||||
`npm run test:topology-collapse` independently opens and collapses an open quad,
|
||||
an open n-gon and a three-face shared-edge mesh; malformed cycles remain
|
||||
`summary-only`.
|
||||
|
||||
The WebEngine CMake target exports the ABI symbol and links a small archive-file
|
||||
group containing Blender BMesh, CustomData-capable BKernel objects, DNA/BLO,
|
||||
local zlib/zstd and allocator support; this avoids pulling the desktop
|
||||
editor/image dependency graph into the WASM module.
|
||||
|
||||
The local artifact is installed in both `web/app/public/vendor/blender/` and
|
||||
`web/app/src/vendor/blender/`, with the manifest SHA-256 updated. The native
|
||||
smoke covers all three modes, Collapse topology reduction, revision sequencing,
|
||||
SceneDelta and normal/UV/material attribute lengths. The browser regression
|
||||
suite covers the same local WASM command path, including native command,
|
||||
preview and isolated LOD workers. Modifier-stack transactions and full
|
||||
skin/seam/sharp preservation remain W-075/W-076.
|
||||
86
docs/status/W-075.md
Normal file
86
docs/status/W-075.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# W-075 Status
|
||||
|
||||
status: in_progress
|
||||
task: 实现三种模式和修改器堆栈求值
|
||||
|
||||
The React Properties editor now exposes a Blender-style Decimate inspector for
|
||||
all three native modes. Collapse has ratio, triangulate and optional symmetry
|
||||
axis controls; Un-Subdivide has bounded iterations; Dissolve Planar has angle,
|
||||
boundary handling and Normal/Material/Seam/Sharp/UV delimit toggles. A shared
|
||||
attribute-policy selector makes preservation or dropping explicit. Browser E2E
|
||||
switches through the mode-specific controls, while native probes confirm all
|
||||
three BMesh entry points execute against the local WASM artifact.
|
||||
|
||||
Applying the inspector commits a revisioned `decimateMesh` command. A
|
||||
`previewDecimateMesh` command now evaluates the profile in a separate WASM
|
||||
module instance, returns temporary geometry to the Three.js viewport, keeps
|
||||
the authoritative handle/revision unchanged and supports explicit cancellation
|
||||
from the inspector.
|
||||
|
||||
The SceneIR contract now carries modifier UUID/type/name/enabled state and a
|
||||
deterministic modifier-stack hash. The native `.blend` reader traverses each
|
||||
`Object.modifiers` list, uses Blender's persistent modifier UID for a stable
|
||||
UUID when available, and exports viewport/render modes plus common Subsurf,
|
||||
Mirror, Decimate and Bevel parameters. The generated
|
||||
`rigged_shape_scene.blend` fixture verifies the real Decimate modifier payload
|
||||
instead of a mock stack. The native command
|
||||
`setModifierEnabled` toggles a declared modifier, and the native history ring
|
||||
implements bounded undo/redo with revisioned snapshots. React exposes the
|
||||
modifier checkbox and top-bar undo/redo commands; browser E2E verifies that
|
||||
undo/redo changes the authoritative native snapshot rather than a Three.js
|
||||
shadow copy. Native smoke now covers the same modifier toggle and its
|
||||
undo/redo cycle against a local WASM engine.
|
||||
|
||||
`protocol/modifier-graph.ts` now builds a stable per-mesh topological order from
|
||||
stack order and explicit `dependsOn` edges. Cycles and unresolved external
|
||||
inputs produce `BLOCKED` with the offending IDs; declared but unexecuted
|
||||
modifiers remain `METADATA_ONLY`. The WebEngine Worker requires `EVALUATED`
|
||||
before Decimate preview, commit or LOD generation. Browser E2E checks the
|
||||
topological order, metadata-only handling and cycle blocking.
|
||||
|
||||
The WebEngine exposes `evaluateDepsgraph` and the native module executes
|
||||
Blender 5.2's `BLO_read_from_memory` loader, headless runtime bootstrap,
|
||||
view-layer sync, graph build, tagged update and frame evaluation. A wasm32 DNA
|
||||
alignment bridge and the Web ID registry for NodeTree/Camera/Light preserve the
|
||||
current C++ layout. The report contains evaluated mesh positions/triangles,
|
||||
source Mesh IDs, object world matrices and modifier counts. The report also
|
||||
contains ordered modifier entries with persistent UID, mode flags, stack
|
||||
dependencies and explicit `EVALUATED`, `DISABLED` or `BLOCKED` status with
|
||||
stable error codes and suggestions. Empty,
|
||||
basic and rigged/shape-key fixtures now pass without a WASM trap; the rigged
|
||||
positions match the Blender deformation golden. Broader modifier and constraint
|
||||
parity is tracked separately and unsupported cases remain structured errors.
|
||||
The lightweight reader's name table now covers all Blender 5.2 DNA modifier
|
||||
slots 0 through 86, including the Grease Pencil range, with a compile-time size
|
||||
check. Recognition remains separate from evaluated parity in
|
||||
`docs/web/modifier-support-matrix.md`.
|
||||
SceneIR now extracts target IDs and core parameters for Lattice, Curve,
|
||||
Armature, Hook, Mesh Deform, Shrinkwrap and Surface Deform, and appends their
|
||||
external objects to `dependsOn`; they deliberately remain `METADATA_ONLY`.
|
||||
|
||||
Six reproducible Blender 5.2 category goldens now cover Generate, Deform,
|
||||
legacy Curve, Physics/time, Geometry Nodes and Grease Pencil. The native report
|
||||
now includes non-Mesh objects, including all 26 Grease Pencil modifier types
|
||||
exposed by Blender 5.2 Python. Twenty-four category types now have evaluated Web
|
||||
goldens. Subdivision uses the local OpenSubdiv 3.7.0 CPU evaluator and matches
|
||||
the 26-vertex/48-triangle desktop result. Exact Boolean uses local GMP 6.3.0
|
||||
and matches the 12-vertex/20-triangle surface result; coplanar triangulation is
|
||||
compared by oriented surface area because wasm32 and desktop can select
|
||||
different valid diagonals. Curve now runs its native modifier and matches the
|
||||
desktop golden after the Web ID registry was extended for Curves data.
|
||||
|
||||
Geometry Nodes has bounded native implementations for a single constant
|
||||
Transform Geometry or Set Position node. Both topology/position results match
|
||||
Blender 5.2. Unknown graphs retain `BLENDER_MODIFIER_ERROR`; simulation zones
|
||||
and bake data preserve input geometry and return
|
||||
`GEOMETRY_NODES_SIMULATION_UNAVAILABLE`. The full node registration/lazy-function
|
||||
runtime is not claimed. Displace adds a bounded constant local-space closure;
|
||||
resource-dependent configurations return `MODIFIER_CONFIGURATION_UNSUPPORTED`.
|
||||
Grease Pencil modifiers remain disabled.
|
||||
Mesh and Surface Deform fixtures continue to serialize real bind caches and
|
||||
deform their cage/target after binding.
|
||||
|
||||
This is not yet complete native Blender dependency-graph parity. Unsupported
|
||||
external runtime resources and unsupported modifier/constraint types return
|
||||
structured errors; the lightweight SceneIR history remains separate and is not
|
||||
silently serialized as a full Blender undo stack.
|
||||
46
docs/status/W-076.md
Normal file
46
docs/status/W-076.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# W-076 Status
|
||||
|
||||
status: in_progress
|
||||
task: 属性、UV 和蒙皮安全简化
|
||||
|
||||
`SimplifyProfile` now requires an explicit attribute policy after parsing and
|
||||
defines `SkinSimplifyPolicy` limits for influences, weights, position error and
|
||||
shape keys. The native command currently implements this partial protection
|
||||
matrix:
|
||||
|
||||
- normals are recomputed from the evaluated triangle topology;
|
||||
- BMFace material indices and material slot IDs are retained;
|
||||
- existing UV and float-color corner values are transferred to output corners
|
||||
using a deterministic closest-source-triangle barycentric projection;
|
||||
- `DROP` is the only policy that removes these arrays intentionally;
|
||||
- Collapse validates and accepts open/non-manifold Mesh-to-BMesh topology;
|
||||
- the native reader exports Mesh `MDeformVert` CustomData as fixed four-slot
|
||||
`SkinWeightsIR` arrays, carries Mesh vertex-group names, and exports
|
||||
non-Basis `KeyBlock` positions as `ShapeKeyIR`; the local
|
||||
`rigged_shape_scene.blend` fixture validates both on a real `.blend` file;
|
||||
- a skinned or shape-key mesh requires explicit `skinPolicy`; omitting it is a
|
||||
structured `NOT_IMPLEMENTED` failure rather than silent attribute loss.
|
||||
|
||||
Native smoke and browser Worker E2E verify normal, UV, corner and material
|
||||
buffer sizes on the closed cube fixture. The WebEngine protocol validates
|
||||
`SkinWeightsIR` and `ShapeKeyIR`. After BMesh produces the authoritative
|
||||
topology, native code projects each output vertex onto the closest source
|
||||
triangle, merges and normalizes its joint influences, and reconstructs every
|
||||
shape-key position with the same barycentric weights. `maxInfluences`,
|
||||
`minWeight` and `maxPositionError` are enforced before committing the new
|
||||
SceneIR. Native smoke and Worker E2E verify output vertex counts, normalized
|
||||
weights, stable joint IDs, bind matrices and shape-key array lengths.
|
||||
`shapeKeys: REJECT` still returns `SHAPE_KEYS_REJECTED` before native work.
|
||||
|
||||
The reader now exports `ArmatureIR` bones with parent IDs, Blender `Bone.arm_mat`
|
||||
rest matrices and matching `PoseChannel.pose_mat` matrices. A mesh Armature
|
||||
modifier resolves its armature object, remaps vertex-group bone names to stable
|
||||
joint IDs, and records the mesh object TRS as its non-identity bind matrix. The
|
||||
generated rig fixture verifies all fields against local Blender data. This is
|
||||
sufficient for GLB inverse-bind generation and the current triangle-bridge
|
||||
remapping path.
|
||||
|
||||
UV seam and sharp-edge error metrics, tangent regeneration, native
|
||||
vertex-group name selection in profiles, Armature deformation comparison,
|
||||
seam/sharp constraints and Blender-evaluated shape-key error comparison remain
|
||||
required before this task can be marked done.
|
||||
46
docs/status/W-077.md
Normal file
46
docs/status/W-077.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# W-077 Status
|
||||
|
||||
status: in_progress
|
||||
task: 多级 LOD 生成、缓存和视口选择
|
||||
|
||||
The cache boundary is now implemented without changing the native WASM ABI:
|
||||
|
||||
- `buildLODCacheKey` creates a deterministic, path-safe key from object ID,
|
||||
source mesh revision, modifier-stack hash, profile hash and REST/POSE state.
|
||||
- IndexedDB schema v3 adds `lod_manifest`; the StorageWorker can put/get a
|
||||
validated manifest and writes transferable `.mesh` bytes to OPFS
|
||||
`projects/<id>/cache/lod/<cacheKey>.mesh`. Read, delete and byte-budget
|
||||
pruning update `lastAccessAt` and remove the least-recently-used entries.
|
||||
- `ThreeLODAdapter` selects pre-generated levels from projected pixel height,
|
||||
with a configurable hysteresis band, and is updated by the viewport render
|
||||
loop without rebuilding the imported scene.
|
||||
- `generateLOD` evaluates every requested profile independently from the source
|
||||
`.blend` in a fresh WASM module instance, returns a validated manifest and
|
||||
transferable geometry, and is exposed by the React inspector. A binary
|
||||
length-table container round-trips the level buffers before OPFS persistence;
|
||||
the React path reads that persisted container back before installing levels
|
||||
into the Three.js viewport, while preserving source transforms and materials.
|
||||
- Browser E2E covers the OPFS bytes, manifest round trip, stable key and
|
||||
hysteresis behavior, multi-level generation and binary geometry round trips.
|
||||
|
||||
The React open path now lists all `lod_manifest` rows for the project after a
|
||||
fresh application load, filters them by the authoritative SceneIR revision and
|
||||
object IDs, reads the OPFS `.mesh` container, validates the level mesh IDs and
|
||||
installs the cached levels into the Three.js LOD adapter. Applying any native
|
||||
scene command also removes manifests from older source revisions, so a stale
|
||||
cache cannot be selected after a mesh or modifier edit. Browser E2E covers
|
||||
generation, reload, discovery and reuse.
|
||||
|
||||
Pose-aware skin joints are still not exported into the LOD manifest. The native
|
||||
Collapse bridge now performs one Blender BMesh collapse pass at a time, creating
|
||||
a fresh heap for each pass and recalculating the quadric choice from the current
|
||||
mesh state. This removes the previous WASM memory failure at intermediate cube
|
||||
targets; the LOD Worker keeps per-level isolation as a general fault boundary.
|
||||
An active modifier stack must now have an `EVALUATED` dependency-graph report
|
||||
before LOD generation. Metadata-only and unresolved stacks return a structured
|
||||
capability error rather than caching output from an implicit base mesh.
|
||||
Each isolated LOD profile applies the same skin/shape-key preflight as direct
|
||||
Decimate, so a valid `skinPolicy` receives native remapping while a missing or
|
||||
rejecting policy cannot create a partial cache entry.
|
||||
Full Blender parity still requires pose-aware skin joints and broader Blender
|
||||
golden coverage, so the task stays `in_progress`.
|
||||
43
docs/status/W-078.md
Normal file
43
docs/status/W-078.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# W-078 Status
|
||||
|
||||
status: in_progress
|
||||
task: 轻量化预算和导出策略
|
||||
|
||||
`protocol/budget.ts` now validates explicit integer budgets for triangles,
|
||||
vertices, index bytes, material slots, texture bytes and estimated GPU bytes.
|
||||
`evaluateLightweightBudget` returns every violation with limit, actual value and
|
||||
excess while leaving the measured usage unchanged. Browser E2E covers a mixed
|
||||
triangle/GPU over-budget report.
|
||||
|
||||
`aggregateLightweightUsage` and `evaluateLightweightBudgets` now produce
|
||||
deterministic project, collection, object and LOD scopes. Project usage sums
|
||||
each source object once; collection membership is reported per collection and
|
||||
LOD usage is kept separate so generated levels are not double-counted. Browser
|
||||
E2E covers all four scope reports.
|
||||
|
||||
`analyzeGLBExport` now runs before the UI export action and returns structured
|
||||
warnings/errors for summary-only or missing geometry, unevaluated modifiers,
|
||||
external/packed images, linked material inputs and unavailable skin remapping.
|
||||
When no blocking condition is present, the local exporter writes a standards-
|
||||
shaped GLB 2.0 binary containing hierarchy, mesh positions/normals/UVs/colors,
|
||||
material groups, PBR material factors and shape-key morph targets. Blender
|
||||
shape-key positions are converted to glTF deltas in the Z-up to Three.js/glTF
|
||||
basis conversion. The top-bar action downloads this local binary; browser E2E
|
||||
checks the GLB header and a non-zero morph delta.
|
||||
|
||||
`exportGLB` now accepts caller-provided local asset buffers, embeds each image
|
||||
as a GLB buffer view, and connects it to exported PBR materials. It exports
|
||||
`JOINTS_0`/`WEIGHTS_0`, bone nodes, inverse bind matrices and supported object
|
||||
or bone animation channels for a resolved armature binding. The local test
|
||||
worker parses the emitted GLB JSON again; browser E2E embeds a real local PNG
|
||||
and verifies its byte length/signature, skin joints, MAT4 inverse-bind accessor,
|
||||
animation channels and skin attributes without a network fetch.
|
||||
|
||||
The native reader now extracts the exact bytes of both legacy and list-based
|
||||
Blender packed images through the local asset request ABI; the packed fixture
|
||||
checks PNG signature, MIME and byte length without a network request. The GLB
|
||||
worker strictly parses the emitted JSON/BIN chunks and compares mesh
|
||||
attributes, embedded image byte counts/MIME, skin joints/inverse-bind MAT4s,
|
||||
morph targets and grouped animation paths against the source SceneIR. The
|
||||
browser round-trip test has no semantic mismatches. Blender-side unsupported
|
||||
features remain explicit export warnings.
|
||||
57
docs/status/W-079.md
Normal file
57
docs/status/W-079.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# W-079 Status
|
||||
|
||||
status: in_progress
|
||||
task: 三角面简化和轻量化里程碑
|
||||
|
||||
The Blender golden fixture is checked by
|
||||
`tools/web/run-blender-golden.mjs`. It opens the local
|
||||
`tests/files/web/basic_scene.blend`, evaluates native Collapse in fresh WASM
|
||||
instances at ratios `1.0`, `0.9`, `0.5` and `0.25`, and compares source object
|
||||
identity, vertex counts and evaluated loop-triangle counts with
|
||||
`tests/golden/W-079/basic-scene-decimate.json`. The test is runnable offline as
|
||||
`npm run test:golden` and currently passes. The focused native memory regression
|
||||
gate `npm run test:collapse-ratios` starts an isolated WASM instance for each
|
||||
target and asserts a successful non-empty result. The matrix now also includes the
|
||||
previously unstable intermediate ratios `0.80`, `0.75`, `0.70` and `0.65`.
|
||||
|
||||
LOD generation evaluates each requested profile in an isolated Worker/WASM
|
||||
instance. A failure at one target records `requestedLevel`, `triangleBudget`
|
||||
and the diagnostic message in `WebEngineLODResult.errors`; the remaining levels
|
||||
are reindexed and cached. The native bridge now avoids the former multi-collapse
|
||||
heap lifetime failure by running one native Collapse pass per fresh heap, so the
|
||||
intermediate golden ratios no longer fault.
|
||||
|
||||
The reader retains 64-bit on-disk BHead pointer identities in WASM and resolves
|
||||
duplicate `BLEND_DATA` attribute arrays in the owning Mesh block range. This
|
||||
prevents a second mesh from inheriting the first mesh's attributes. The offline
|
||||
`npm run test:topology-collapse` regression confirms successful native Collapse
|
||||
for an open quad, an open n-gon and a non-manifold shared edge.
|
||||
|
||||
The rigged fixture also now runs Collapse with a preserving `skinPolicy`.
|
||||
Native output projects to the source triangles, remaps fixed four-slot weights
|
||||
and rebuilds shape-key positions, while a missing policy remains blocked. The
|
||||
same path is covered through the browser WebEngine Worker.
|
||||
|
||||
The deformation fixture now records an actual Blender 5.2 evaluated-depsgraph
|
||||
golden with shape-key value and armature pose applied. The Web deformation
|
||||
worker compares linear bind/rest/pose evaluation against the declared max and
|
||||
RMS error budget. Packed-image extraction, GLB semantic re-import and the Web
|
||||
deformation golden are covered by focused browser tests.
|
||||
|
||||
The native Blender Depsgraph path now completes full loader, view-layer sync,
|
||||
graph build, tagged update and frame evaluation in the headless WASM build for
|
||||
the empty, basic and rigged/shape-key fixtures. A wasm32-specific DNA layout
|
||||
adapter recursively restores 8-byte alignment for 64-bit members; this fixes
|
||||
the `Scene.master_collection` offset and prevents the former memory trap. The
|
||||
Web ID registry includes embedded NodeTree, Camera and Light data, and the
|
||||
rigged output matches the Blender 5.2 deformation golden within its max/RMS
|
||||
budgets. The report now exposes ordered native modifier entries, persistent UIDs,
|
||||
mode flags, target object IDs, stack dependencies and explicit Blender evaluation errors; the
|
||||
rigged fixture verifies Armature followed by a structured Decimate block on its
|
||||
two-triangle input. N-001 is complete for the declared fixtures and N-002 has
|
||||
started with this report contract; broader modifier, constraint and stress
|
||||
coverage remains tracked by N-002/N-003/N-008.
|
||||
|
||||
The broad Decimate mode/performance matrix and Blender round-trip warnings are
|
||||
still tracked as follow-up coverage; unsupported cases must remain structured
|
||||
errors and cannot be treated as parity.
|
||||
32
docs/status/W-080.md
Normal file
32
docs/status/W-080.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# W-080 Principled 材质映射
|
||||
|
||||
状态:`done_current_scope`
|
||||
|
||||
路线图中的 W-080 专指 Principled 材质映射。当前已完成默认输入、emission、alpha、IOR、
|
||||
Image Texture 元数据和 warning 证据;材质槽、选中面分配、UV Map 选择、限定
|
||||
Principled/Image Texture/Normal Map 节点创作及 packed PNG/JPEG 写回归属于 W-080 的
|
||||
bounded authoring slice。packed pixels、sRGB、基础 PBR/纹理 sampler 的 Blender GLB
|
||||
round-trip 由 N-004/N-005 覆盖。N-013 现可把 Principled、Image Texture、Normal Map、
|
||||
Material Output 四节点整图原子写回 Main 并保存重开;RGB/Value/Mix/Math/Mapping/TexCoord/
|
||||
Bump、任意节点求值和更多 Principled 扩展仍保持结构化边界。
|
||||
|
||||
2026-08-09 增加 `physical-v1` 渲染切片:Specular IOR Level、Transmission Weight、
|
||||
Coat Weight、Coat Roughness、Emission Strength 已贯通 Inspector、Blender Main、reader、
|
||||
SceneIR、save/reopen 和主线程/Offscreen `MeshPhysicalMaterial`。两条视口现在统一使用线性
|
||||
输入、sRGB 输出、ACES、World exposure、真实 SUN/SPOT 方向和有界 PCF shadow。
|
||||
详细映射、风险和 PBR-001 至 PBR-012 后续任务见
|
||||
`docs/PBR_RENDERING_IMPLEMENTATION_PLAN.md`。纹理像素 GPU 上传、UDIM、HDRI/IBL、任意
|
||||
Shader Node、AREA 阴影等仍是 planned,不包含在 `done_current_scope` 声明中。
|
||||
|
||||
`tests/golden/W-080/animation-depsgraph.json` 与 `pose-constraint-depsgraph.json` 是
|
||||
历史 fixture 目录,语义上属于 N-003 的 frame/pose 回归,不改变 W-080 的任务定义。迁移
|
||||
这些 fixture 前,验收脚本和 golden manifest 必须同步更新,禁止复用任务编号。
|
||||
|
||||
默认验收:
|
||||
|
||||
```bash
|
||||
npm --prefix web run test:golden
|
||||
npm --prefix web run test:frame-evaluation
|
||||
npm --prefix web run test:pose-constraint-goldens
|
||||
npm --prefix web run test:authoring-roundtrip
|
||||
```
|
||||
128
docs/status/parity-ledger.json
Normal file
128
docs/status/parity-ledger.json
Normal file
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"updatedAt": "2026-08-12",
|
||||
"source": "docs/BLENDER_5_2_WEB_FEATURE_PARITY.md",
|
||||
"statusEnum": ["LOCAL_EXACT", "LOCAL_BOUNDED", "SERVER", "BLOCKED"],
|
||||
"families": [
|
||||
{
|
||||
"id": "N-015",
|
||||
"name": "Non-mesh geometry",
|
||||
"status": "LOCAL_BOUNDED",
|
||||
"roadmapStatus": "in_progress",
|
||||
"completedSlices": ["A1", "A2-malformed-binary-partial", "A2-integer-overflow-fixtures", "A2-multichunk-attribute-completeness", "B2", "B3-metadata", "C1-topology-partial", "C1-handle-points-partial", "C1-handle-preview-raycast-partial", "C1-handle-identity-gizmo-main-roundtrip", "C1-rename-partial", "C1-create-delete-poly-partial", "C1-poly-bezier-nurbs-1d-conversion", "C1-multispline-create-delete-bulk-handle-cyclic-transaction", "C1-surface-2d-topology-transaction", "C2-font-geometry-partial", "C2-font-layout-partial", "C2-font-character-style-textbox-roundtrip", "C2-existing-packed-vfont-style-links", "C2-builtin-font-evaluation-exact", "C3-roundtrip", "D1-raycast-partial", "D1-offscreen-vert-edge-partial", "D1-selection-history-partial", "D1-handle-identity-axis-gizmo", "D2-partial", "E1-partial", "E1-desktop-geometry-golden", "E1-true-2d-surface-desktop-golden", "E1-glb-evaluated-nonmesh-roundtrip-partial", "E1-glb-curve-line-surface-mesh-evaluated", "E1-usda-four-object-desktop-roundtrip", "E1-pointcloud-curves-hair-glb-usd-loss-fixture", "E2-1M-chromium", "E2-chromium-worker-recovery", "E2-opfs-quota-chromium"],
|
||||
"blockedSlices": ["B3-vdb-renderer", "C1-multi-handle-selection-drag-gizmo", "C2-new-external-font-import", "D1-cross-object-history-range-patch", "E1-volume-loss-fixture"],
|
||||
"acceptance": ["web:test:nonmesh-roundtrip", "web:test:nonmesh-desktop-golden", "web:test:nonmesh-glb-blender-roundtrip", "web:test:nonmesh-usd-serialization", "web:test:nonmesh-usd-blender-roundtrip", "web:test:nonmesh-binary", "web:test:vdb", "web:test:selection-history", "web:e2e:N-015|non-mesh", "web:e2e:real OPFS quota"],
|
||||
"dependencies": []
|
||||
},
|
||||
{
|
||||
"id": "N-016",
|
||||
"name": "Grease Pencil",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-schema-budget", "A-main-reader", "B-layer-frame-stroke-transaction-partial", "C-point-radius-opacity-color-cyclic-material-partial", "D-current-frame-stroke-preview-main-offscreen-chromium"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:test:grease-pencil", "web:e2e:N-016 Grease Pencil"],
|
||||
"dependencies": ["N-015"]
|
||||
},
|
||||
{
|
||||
"id": "N-017",
|
||||
"name": "Paint and weights",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-stroke-hit-weight-schema-budget-partial", "B-main-vertex-color-partial", "B-main-vertex-weight-normalize-partial"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:test:paint-roundtrip", "web:e2e:N-017 paint"],
|
||||
"dependencies": ["N-016"]
|
||||
},
|
||||
{
|
||||
"id": "N-018",
|
||||
"name": "Physics and simulation",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-family-capability-inventory", "B-settings-dependency-cache-manifest-partial", "C-exact-frame-selection-gate"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-018 physics", "web:test:simulation-cache"],
|
||||
"dependencies": ["N-017"]
|
||||
},
|
||||
{
|
||||
"id": "N-019",
|
||||
"name": "Lighting and render",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-camera-light-world-scene-reader-partial", "A-main-light-world-properties-partial", "B-three-exposure-shadow-mapping-partial", "A-white-balance-integrity-gate"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:test:lighting-roundtrip", "web:e2e:N-019 Scene exposure"],
|
||||
"dependencies": ["N-018"]
|
||||
},
|
||||
{
|
||||
"id": "N-020",
|
||||
"name": "Compositor",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-graph-resource-cycle-schema", "B-bounded-cpu-executor-partial", "C-image-operation-budget-cancel-partial", "D-unsupported-node-preservation-gate"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-020 CPU compositor"],
|
||||
"dependencies": ["N-019"]
|
||||
},
|
||||
{
|
||||
"id": "N-021",
|
||||
"name": "Sequencer and audio",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-strip-resource-schema", "B-deterministic-move-trim-split-partial", "B-source-frame-seek", "C-runtime-codec-probe-gate"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-021 sequencer"],
|
||||
"dependencies": ["N-020"]
|
||||
},
|
||||
{
|
||||
"id": "N-022",
|
||||
"name": "Tracking and masks",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-clip-track-plane-mask-schema", "B-revision-marker-mask-edit-partial", "B-source-hash-binding-validation", "C-browser-probe-solve-gate"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-022 tracking"],
|
||||
"dependencies": ["N-021"]
|
||||
},
|
||||
{
|
||||
"id": "N-023",
|
||||
"name": "Assets, libraries and IO",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-catalog-asset-license-source-schema", "A-content-addressed-opfs-capability", "B-library-dependency-order-partial", "C-glb-export-usd-analysis-gates", "E-archive-path-ratio-budget"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-023 asset"],
|
||||
"dependencies": ["N-022"]
|
||||
},
|
||||
{
|
||||
"id": "N-024",
|
||||
"name": "Editors and workflow",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-unified-area-region-context", "B-read-only-editor-manifest-partial", "C-selection-sync-revision-partial", "D-keymap-layout-budget-gates"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-024 editor"],
|
||||
"dependencies": ["N-023"]
|
||||
},
|
||||
{
|
||||
"id": "N-025",
|
||||
"name": "Scripting and platform",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-default-deny-script-policy", "B-signed-manifest-permission-budget", "C-server-source-hash-job-gate", "D-platform-capability-report"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-025 script"],
|
||||
"dependencies": ["N-024"]
|
||||
},
|
||||
{
|
||||
"id": "N-026",
|
||||
"name": "Release gate",
|
||||
"status": "BLOCKED",
|
||||
"roadmapStatus": "planned",
|
||||
"completedSlices": ["A-machine-readable-parity-manifest", "A-dependency-status-validation", "B-chromium-runtime-evidence-gate", "B-chromium-smoke-partial", "C-performance-fault-provenance-gate", "C-performance-1M-malicious-input-partial", "C-release-package-notices-partial", "D-deterministic-manifest-serialization", "D-offline-reproducible-source-archive-partial"],
|
||||
"blockedSlices": ["A", "B", "C", "D", "E"],
|
||||
"acceptance": ["web:e2e:N-026 release", "web:test:browser-smoke", "web:test:release-package", "web:release:offline", "web:test:release-performance", "web:test:malicious-blends"],
|
||||
"dependencies": ["N-015", "N-016", "N-017", "N-018", "N-019", "N-020", "N-021", "N-022", "N-023", "N-024", "N-025"]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user