- 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>
7.1 KiB
7.1 KiB
二级减速器互动教学(REDUCER_TUTORIAL)
用户入口
/?tutorial=reducer:React 图文落地页(结构、零件卡、课堂实录、课程树、开始/继续/重置)。/?tutorial=reducer&start=1:真实 Web Blender(本地 WASM Main)+ 引导侧栏。- 帮助 → 二级减速器教学:在新标签页打开落地页。
已实现
- 35 步课程(引导 + 33 个必需步骤 + 完成总结),覆盖:
- 箱体/箱盖:立方体、应用缩放、删面 + Solidify、Mirror + Boolean UNION 箱脚、 圆柱孔刀 + Join + Boolean DIFFERENCE 轴承孔、Inset/挤出止口、Mirror 螺栓孔、Bevel。
- 传动件:三根轴(圆柱 + 轴颈 + Join + 键槽布尔)、四个齿轮 (圆柱轮坯 + 齿槽刀 + Empty 对象偏移 Array + Boolean 切齿 + 轴孔/键槽布尔 + Bevel)、 Torus 套圈 + 滚球轴承。
- 标准件与附件:端盖、平键、六角法兰螺栓、通气帽、油标、放油塞、文字转网格铭牌(Subsurf 底板)。
- 装配与交付:集合层级、轴组件 Empty + 父子、根 Empty 总装、四种材质与槽位、Linked Duplicate、
保存
.blend(OPFS + 下载)与 GLB 导出。
- 课程工程身份:reducer 首次进入时通过
ensureCourseProject("tutorial-reducer", "二级减速器.blend")把默认场景写入 OPFS 课程工程(复用persistProject,不触发下载), 检查点写projects/tutorial-reducer/snapshots,与 parts 课程的快照链隔离。 - React TreeView:新增
tutorial/TutorialTreeView.tsx(role=tree/treeitem、方向键/Home/End、 展开/折叠、状态标记),用于:- 落地页课程结构(章节 → 步骤);
- 装配章节的“实时装配树”(按 SceneIR 的集合/父子关系生成)。
- 课程化改造:新增
tutorial/course.ts,把课程 id、步骤、进度文件名、资源目录、 保存/总结步骤、文案与零件卡参数化;parts 组件改为薄包装,parts 行为不变。 - 进度与恢复:OPFS
tutorial/reducer-progress.json为权威记录,localStorage 镜像; 恢复前先读 OPFS 进度,恢复失败显示提示;首次推进前串行完成“恢复或确保课程工程”。
本批修复的真实缺口
- 课程工程身份与就绪竞态:引导页的“下一步”可能在
ensureCourseProject启动前被点击, 从而把错误的默认工程 id 写进进度并排队检查点。现在侧栏把projectState(idle/preparing/ready/failed) 纳入ready门控,串行完成“恢复或确保课程工程”后才允许演示与推进;失败时显示提示并允许继续练习,但不写错误 id。 - 箱体轴承孔校验:箱体在箱脚步骤已有一个 Boolean(Union),按类型取第一个 Boolean 会命中箱脚而不是轴承孔。 校验现在按操作数“箱体孔刀”匹配 Boolean 修改器。
- 轴与轴承的局部坐标:输入轴与轴承的旋转未应用时,SceneIR 网格包围盒沿局部 Z 轴, 长度/外径校验误判。演示现在在 Join 前应用旋转(与桌面建模习惯一致)。
- 编号对象计数:
findNodes的名称后缀规则只接受.001形式,无法匹配“轴承1…6/端盖1…6/键1…4/法兰螺栓1…9”。 计数校验改为按^轴承\d+$等编号名称匹配。 - 齿轮齿槽阵列与布尔:Boolean 操作数上的活动 Array 修改器在 Web Main 的实时视口中只切出一条齿槽
(17 份阵列未被布尔求值)。已做对照:即使齿槽刀保持可见,活动 Array 仍只切一条,可见性不是原因;
在布尔前
bpy.context.view_layer.update()后应用齿槽阵列则得到正确齿形。 课程因此改为“阵列 → 应用 → Boolean”;齿轮1 的-view截图显示 17 条齿槽,齿轮2 显示 34 齿结果。 这仍是引擎的实时操作数求值缺口(已记录在“已知限制”),应用阵列是桌面同样可用的工作流。 - 重场景的保存竞争:减速器场景较大,通用 autosave 与教程检查点同时序列化会长时间占用项目锁, 导致“下一步”在完成检查后仍被禁用。现在课程激活时停用通用 autosave,教程检查点串行化(只允许一个在跑), 重课程每 3 次推进写一次检查点(零件课程保持每步);“下一步”不再等待后台保存。 代价是最多可能丢失 2 步的场景快照,进度步骤仍每步写入。
- 材质创建校验:未分配到任何对象的材质不会出现在 SceneIR,四种新材质的颜色校验全部失败。 课程在创建步先给箱体/输入轴/轴承1/箱盖各分配一个代表材质,下一步再分配其余零件。
- 实时装配树可读性:SceneIR 中的隐藏辅助对象(Mirror/Array 控制 Empty、隐藏切刀)会淹没装配层级。
React 树现在过滤
visible=false的对象与空集合,仅显示可见装配层级。
验证状态
- 有头 Chromium 全流程(2026-11-11,
capture-parts-tutorial-screenshots.mjs --course reducer --dev --port 5218): 35 步全部通过,status: PASS,errors: [];保存与 GLB 导出检查均为绿色 (GLB 2,674,332 字节,31 条相机/灯光等警告);齿轮1 视口参考图确认 17 条齿槽。 截图:web/app/public/tutorial/reducer/landing.jpg、steps/<id>.jpg、steps/<id>-view.jpg、00-assembly.jpg(35 步共 70 张步骤图 + 总览;落地页已在全部步骤截图生成后重新截取)。 npm run typecheck:exit 0;npm run build:exit 0(含PartsTutorialLanding-*.js课程 chunk)。- 生产构建上的 4 个 spec 全部通过(2026-11-11,
playwright.deployment-local.config.ts,workers=1,48.1s):wbv2-reducer-tutorial-production.spec.ts(19.9s):落地页/课程树 → 开始 →tutorial-reducerOPFS 工程 → 箱体演示 → 齿轮毛坯/阵列/布尔 → 刷新继续 → OPFS 恢复(Active 齿轮1)→ 保存.blend+ GLB 下载与 magic →projects/<savedProjectId>/scene.blend。reducer-tutorial-accessibility.spec.ts(4.5s):落地页与课程树 axe、装配步骤的实时 React 树 axe。wbv2-parts-tutorial-production.spec.ts(18.6s)与parts-tutorial-accessibility.spec.ts(4.4s):零件课程回归。
- 无障碍修复:课程目录序号颜色 #7d8287→#a6abb0(对比度 4.45→通过 4.5),装配树元信息同样改为 #a6abb0。
已知限制
- Boolean 的活动 Array 操作数在 Web Main 实时视口中只求值一份;课程在布尔前应用阵列。
待补:按桌面源码检查 Boolean 操作数的求值依赖(
MOD_boolean.cc的DEG_OB_COMP_GEOMETRY与 Array 的offset_ob关系),并加回归用例。 - 齿轮为教学简化齿形(直齿、无渐开线修形),用于讲解阵列+布尔流程,不用于强度/噪声分析。
- 轴承为简化模型(内外套圈 + 8 个滚球),未建模保持架与游隙。
- 端盖为简化圆盘+凸台,未做密封槽与标准螺栓孔阵列。
- 油标/放油塞/通气帽为示意模型;法兰螺栓数量与位置为教学布置。