编辑工作流
平台里所有修改都是改构建脚本。IFC 和 DXF 永远是脚本跑出来的产物,所以任何一次保存,背后一定是一次脚本变更。概念模型见Script 编辑与版本。
模型的两种形态
- script-backed:模型有构建脚本,具备完整编辑能力——定位、参数表单、脚本编辑器、暂存、版本。
- plain:模型是外部上传的,没有脚本,只能查看和审查。让 AI 把它复现成脚本之后就变成 script-backed,见文末 bootstrap。
选中构件,定位脚本
属性面板是只读的,不提供直接改值。要修改,先选中构件,点定位脚本按钮:
- 前端调
GET /api/v1/models/{id}/script/locate,IFC 按 guid 查,DXF 按 key 查。 - 命中后自动切到 Design 面板的脚本编辑器,光标落在生成这个构件的那一行并高亮。
- 查不到就保持只读。如果暂存脚本和定位信息对不上,会提示先运行一次脚本再定位。
两种改法
Design 面板有两种模式:参数表单和脚本编辑器。定位结果里的 origin 标签决定用哪种:
- origin 是 params:构件参数来自脚本头部的 PARAMS 块。在参数表单里改对应键的值,提交即可。
- origin 是 literal:参数是写死在调用行里的字面量。可以直接在脚本编辑器里改这一行。AI 侧也可以调
POST /script/edit-call,由服务端用 libcst 精确重写这个标量,保留原有格式和注释。 - origin 是 traced:参数是运行时算出来的,只能定位不能自动改写。请打开脚本编辑器手动改。
沙箱验证与暂存
表单提交或脚本保存时,先做静态契约校验,不通过直接报 422,什么都不会被修改。通过后进入暂存区。暂存区最多保留 10 步,落盘保存,重启不丢,支持撤销和重做。
暂存之后有三个去向:
- 放弃:丢弃整条暂存链,不产生任何版本。
- 试运行:沙箱里执行暂存脚本,预览产物,不产生版本。
- 保存版本:执行脚本生成 IFC 或 DXF,固化为大版本 v{n+1}。
Design 面板在 xeokit、web-ifc、DXF 三条查看分支上完全一致,共用同一份数据和接口。版本列表里对非当前版本还可以回滚:恢复那版的脚本并重新执行。
版本与 Diff
大版本就是一次显式的「保存版本」。每版完整保留脚本和定位信息,即 scripts/v{n}.py 和 v{n}.map.json,编号只增不改。产物文件只留最新一份,历史版本需要对比或下载时,从对应脚本重新构建。
工具栏的 Diff 按钮打开对比面板:
- 选 base 和 target。target 可以是某个版本,也可以是当前状态。
- 点对比。绿色是新增,黄色是修改,红色是删除。
- 点条目定位到构件;修改条目可以展开,看每个字段的旧值和新值。
- 点清除复位着色。
对比是属性级的语义对比,按确定性 GlobalId 或实体 key 对齐。不做几何对比,因为改几何就是改脚本。IFC 和 DXF 两侧逻辑相同。
中途预览
AI 或人在试运行成功后,服务端会推 viewer.staged 事件,保存版本之前就能看到中间结果:
- DXF 和 web-ifc 分支画布直接刷新,代价低。
- xeokit 分支重转 XKT 比较慢,画布左上角出现「AI 中间结果 · 点击预览」角标,点击才重载。
保存大版本后由 viewer.committed 事件驱动常规刷新。
bootstrap:把上传的 IFC 变成脚本
有 AI 参与时,上传 IFC 的意图是让它照着做一份:
- 用户上传 IFC,此时是 plain 态,只能看。
- AI 通过 MCP server 读取模型,用 aiifc skill 编写复现脚本。
- 首次暂存时平台自动把上传原件保存为
bootstrap.ifc。脚本经沙箱验证后保存为大版本 v1,模型转为 script-backed。 - 首次保存的响应里有 alignment 计数,也就是原件和生成结果之间的差异摘要,用它判断复现是否走样。