Files
workinf_Blender_Wasm/docs/status/PARTS_TUTORIAL.md
mes123456 d1e6b63d54
Some checks failed
M6 deployable RC / quick (push) Has been cancelled
M6 deployable RC / chromium (push) Has been cancelled
M6 deployable RC / release (push) Has been cancelled
chore: checkpoint web Blender feature-gap work, docs and tests
- update native web_engine sources and rebuilt wasm artifacts
- add task cards, status notes and tooling scripts
- add web e2e specs, tutorial UI sources and tutorial assets
- sync golden task manifests and audit records

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-11-11 10:46:55 +08:00

6.7 KiB
Raw Blame History

机械零件套装互动教学(PARTS_TUTORIAL)

用户入口

  • /?tutorial=parts:React 图文落地页(课程介绍、零件卡片、课堂实录截图、开始/继续/重置)。
  • /?tutorial=parts&start=1:真实 Web Blender(本地 WASM Main)+ 引导侧栏。
  • 帮助 → 零件建模教学:在新标签页打开落地页。

已实现

  • 21 步课程(0 引导、19 个必需步骤、完成总结),覆盖:
    • 创建与变换:立方体、圆柱、贝塞尔圆环、文字、Empty;缩放/位置、应用缩放。
    • 编辑模式:顶面内插、挤出、沉台、轴肩、六角头细节、支架。
    • 修改器与布尔:Bevel、Boolean(Difference,刀具对象指针)、Array、Solidify、Mirror、Subsurf。
    • 层级、材质与交付:集合、父子、三种材质并按槽位分配、复制、保存 .blend、导出 GLB。
  • “演示本步”通过同一原生 Main 执行:Python 使用 bpy;对象合并(底座开孔刀具、螺栓头+杆)改为 typed joinObjects,与产品 Object → Join 同一路径。
  • 实时校验读取 SceneIR:节点名称/类型/父子、变换、网格包围盒、修改器栈与参数、布尔操作数、集合成员、材质槽。
  • 保存/导出校验绑定 App 的 userAction 状态(SAVE/SAVE_AS/EXPORT),不以 dirty=false 单独判定。
  • 进度持久化:
    • OPFS tutorial/parts-progress.json 为权威记录,localStorage 仅为同步镜像/降级;OPFS 写入串行化避免旧写覆盖新写。
    • 每步推进后写入 OPFS 恢复快照(saveSnapshot),重新进入教程时从 OPFS 恢复工程并回到记录的步骤。
  • 有头 Chromium 截图:tools/web/capture-parts-tutorial-screenshots.mjs 执行全部步骤并输出 web/app/public/tutorial/parts/steps/<stepId>.jpg(含引导侧栏的整页图)与 <stepId>-view.jpg(视口参考图)。
  • 教程端到端测试:web/tests/e2e/wbv2-parts-tutorial-production.spec.ts。

本批修复的真实缺口

  1. 引导入口就绪竞态:侧栏在默认工程尚未打开时就能点击“演示本步”,Python 请求被引擎拒绝 (Invalid embedded Python request)。现在侧栏暴露 ready/busy,场景就绪前禁用演示与下一步。
  2. 修改器 SceneIR 元数据缺失(桌面源码对齐): web_engine_blend_main_merge_modifier_snapshot 中有修改器的对象被错误地 continue 跳过, 导致 editableParameters 从未合并,布尔修改器的 operation/object 无法读取(教程布尔校验失败)。 已删除该反向早退,保留“有修改器时不做原始法线回填”的原有条件。 增量编译 cmake --build build_web_blender6 --target web_engine -j8 并 node tools/web/sync-web-engine-runtime.mjs;同步后的 web_engine.wasm 哈希 4cb478454c8cbc2936e346224820c2f56fc70645cb3b8d3237f05b96bd27c6ac。
  3. 保存校验:教程把 SAVE/SAVE_AS 的 userAction 状态与 dirty 结合,避免“新工程未保存”误判。
  4. 合并/父子路径:演示中的 Join 改为 typed joinObjects(与 Object → Join 一致);assemblies 的父子改为 typed setParents(与 Object → Parent 一致),避免 bpy.ops.object.join / parent_set 在无头上下文中的行为差异。
  5. OPFS 进度串行写 + 恢复前置:OPFS 记录先于本地镜像落盘,加载完成后再决定是否恢复工程,避免空进度先占位。
  6. Web 业务工具模式下的 GLB 导出失败:SceneIR 会列出 object.convert 后遗留的孤立曲线数据块; 导出前对任意 nonMeshData 都调用 evaluateDepsgraph,在没有原生 GPU 画布的 Web 业务工具模式下该评估不返回; 即使跳过评估,导出器也会因为这些未求值数据报 NON_MESH_EVALUATION_REQUIRED 而不生成 GLB。 现在导出前只保留被场景节点引用的非网格数据(孤立数据块丢弃),仅对实际使用的数据评估; 渲染能力查询也改为最长等待 3 秒的保守探测,避免无 GPU 画布时永久挂起。
  7. GLB 导出被未使用材质阻塞:导出器会校验 SceneIR 里的全部材质,而启动模板带有未使用的 Dots Stroke 材质(没有 Principled/Output 节点图),导致整个导出报 SHADER_GRAPH_UNMAPPABLE。 桌面 glTF 导出器只收集被导出对象引用的材质;现在导出前同样只保留被场景网格材质槽引用的材质。 默认场景复测导出 3996 字节 GLB;教程完整场景导出 31264 字节。
  8. “继续学习”未恢复工程:启动模板在新会话中复用同一个 projectId,侧栏用 progress.projectId === context.projectId 判断“已是学习工程”,于是跳过 OPFS 恢复,停留在默认立方体场景。 教程编辑器的挂载恢复只应比较“是否存在学习进度”,现已移除该 id 相等早退; 生产 spec 验证恢复后 [data-testid="scene-stats"] 显示 Active 底座,状态栏显示 Recovery: baseline r2。 (Outliner 集合折叠时行不在 DOM,恢复断言因此改用场景统计而不是 treeitem。)

验证状态

  • 有头 Chromium 全流程(2026-11-11 05:14,capture-parts-tutorial-screenshots.mjs --dev --port 5191): 21 步全部通过,status: PASS,errors: [];保存与 GLB 导出检查均为绿色, 截图写入 web/app/public/tutorial/parts/(21 张步骤图 + 21 张视口图 + 落地页/总览图)。
  • npm run typecheck:exit 0(缓存指纹在 App.tsx 修改后重新生成)。
  • npm run build:exit 0,教程 chunk PartsTutorialLanding-*.js、usePartsTutorialProgress-*.js 正常产出。
  • 生产无障碍 spec:通过(落地页 + 首个练习步骤的引导侧栏 axe 检查无 critical/serious 问题); 测试从引导页进入 base-rename 后检查 .tutorial-checks[aria-live=polite]。
  • 生产端到端 spec:覆盖“演示 → 下一步 → OPFS 进度 → 刷新后继续学习 → OPFS 恢复工程 → 保存 .blend 与导出 GLB”,并直接断言 OPFS tutorial/parts-progress.json、 projects/<id>/snapshots/*.blend 与 projects/<id>/scene.blend。
  • 2026-11-11 最终生产构建 4 个 spec(parts/reducer 生产与无障碍)全部通过; parts 恢复断言改用 scene-stats,下载用事件队列按扩展名匹配。

已知限制

  • 编辑模式演示走 bpy.ops 的 EXEC 路径;循环切割滑动、切割刀、模态倒角/内插等模态工具未纳入课程。
  • 完成总结不含“应用全部修改器”步骤;GLB 导出前不强制烘焙修改器。
  • 材质按对象槽位分配,未覆盖共享材质 data-block 的分配 UI。
  • 环境阻塞的既有缺口(OpenVDB voxel remesh、Ocean FFTW3、light-probe bake)不在本教学案例范围内。