架构边界详细说明
August 11, 2026 · View on GitHub
最后更新:2026-07-11 | 覆盖源码:
src/全局 交叉引用:viewer.md、file-io.md、robot-canvas-lib.md
1. 依赖方向(补充)
依赖图与基本约束见 CLAUDE.md §架构红线与执行准则。此处补充逐层细化:
app:编排 features/store/shared/core/types,不把业务细节反向塞回下层features:依赖 store/shared/core/types,禁止依赖 appstore/shared:不应新增对 features 的运行时依赖core:纯解析、robot 拓扑、格式检测、runtime patch diff 等,不引入 React / store / feature / shared UItypes:只提供类型与常量,不回指上层
2. lib / packages 约束
src/lib/视为对外复用封装层,只收稳定、通用、与应用壳无关的能力- 应用内部不要把
src/lib/当业务逻辑 source of truth - 若能力强依赖
workspaceStore、app overlays 或特定业务流程,不要抽进src/lib/ packages/react-robot-canvas/是对外发布包工作区;dist/由构建脚本维护,禁止手改
Host App 可以通过 AppExtensionConfig.contextFileMenu 为替代工作区 surface 注入一组
文件动作。Core Header 只拥有菜单的呈现、焦点和关闭行为;文件句柄、保存策略、预检、
导入提交和业务文案仍由 host 拥有,避免把 Pro 场景工作流反向写入开源 Core。
AppExtensionConfig.surfaceModeSelector 只暴露中性的 primary / alternate 状态。
Core 据此切换默认工作区与宿主工作区的壳层呈现,但不知道宿主的业务模式名称、数据模型或
工作流;“模型 / 场景”等产品语义必须由 Pro 在注入配置时映射和提供文案。
3. 当前存量例外(禁止扩散)
运行时代码:
src/features/editor/index.ts->src/features/urdf-viewer/index.ts(Editor facade)src/features/editor/{ik_selection,panels,usd_bindings,usd_documents,usd_export,usd_hydration,usd_offscreen_runtime,usd_prewarm,usd_runtime}.ts->src/features/urdf-viewer/...(Editor 窄 facade;精确 importer / specifier / target 以dependency_boundaries.mjsallowlist 为准)src/lib/components/RobotCanvas.tsx->src/features/urdf-viewer/components/JointInteraction.tsxsrc/lib/components/RobotCanvas.tsx->src/features/urdf-viewer/components/RobotModel.tsx
上述例外由 scripts/tools/dependency_boundaries.mjs 按 importer + specifier + resolved target 精确匹配,禁止扩大为整层或整 feature 例外。
测试期例外(不作为运行时先例):
src/features/file-io/utils/usdFloatingRoundtrip.test.ts->urdf-viewerruntime/utilssrc/features/file-io/utils/usdGo2Roundtrip.test.ts->urdf-viewerruntime/utils
4. Feature Public APIs
editor:统一 Editor 公开入口通过src/features/editor/index.ts暴露;高成本 / 延迟加载 / app 编排专用能力可通过src/features/<feature>/*.ts窄 facade 暴露,允许清单由dependency_boundaries.mjs精确维护code-editor:组件与 Monaco 运行时从src/features/code-editor/index.ts静态进入应用依赖图;这是为了保证开发期旧页面点击源码时不再请求可能失效的 Vite 模块,禁止恢复组件入口或 Monaco 的点击时动态import()urdf-viewer:Editor 实现子目录,通过src/features/urdf-viewer/index.ts暴露file-io:导入导出入口,通过src/features/file-io/index.ts暴露app层新增对src/features/<feature>/...子路径的 deep import 必须先收敛到 feature 公开入口;存量 deep import 只保留在dependency_boundaries_baseline.json的knownFeatureDeepImportsratchet 中,按importer -> specifier精确计数,修掉后删除对应 baseline 项。
5. Canonical Data Sources
DEFAULT_MOTOR_LIBRARYcanonical source:src/shared/data/defaultMotorLibrary.json- 宿主注入状态 canonical source:
src/shared/hostIntegrationState.ts;src/hostIntegrations.ts只做稳定 facade,feature 不得反向依赖 app facade src/shared/data/motorLibrary.ts:仅负责验证、标准化与导入路径检测src/features/hardware-config/index.ts:兼容层 re-export- 应用机器人领域状态 canonical source:
src/store/workspaceStore.ts中非空workspace: AssemblyState - workspace 构造与严格不变量:
src/core/robot/canonicalWorkspace.ts - component 内
RobotData始终使用 source-local ID;跨 component ID 只由assemblySceneProjection.ts显式映射 - selection canonical source:
src/store/selectionStore.ts的WorkspaceSelection;禁止恢复 robot/assembly 两套 selection - project archive canonical source:
.usp 3.0的workspace/state.json与history/workspace.json;旧版本直接拒绝
6. Shared Three.js 工具
vite.config.ts从 Node 当前可解析的依赖图定位 Three:Core 独立安装时使用自身node_modules,被宿主仓直接编译或运行配置测试时可使用上层锁定安装,不要求伪造core/node_modules- 通用 THREE 释放:
src/shared/utils/three/dispose.ts src/features/urdf-viewer/utils/dispose.ts:兼容层 re-export- viewer backend lifecycle:
src/features/urdf-viewer/renderers/,包括ThreeJsBackend、createRendererBackend、loadedRobotSceneSync、source format / metadata / fallback policy - shared mesh renderer:
src/shared/components/3d/renderers/只放纯 mesh renderer 组件(STL/OBJ/DAE/GLTF)与 Collada scene helpers,不承载 viewer backend 状态 - collision overlay material:
src/shared/utils/three/collisionOverlayMaterial.ts - MJCF parser material:
src/core/utils/materialFactory.ts
7. Core Canonical Helpers
- 源文件格式检测 canonical source:
src/core/parsers/format_detection.ts app/utils/import-preparation/formatDetection.ts与features/file-io/utils/formatDetection.ts只做 workflow wrapper 或资产/电机文件补充判断- 组装 auto seed:
src/core/robot/auto_seed_assembly.ts;避免 app 与 file-io 测试各自复制 seed 逻辑 - runtime patch diff:
src/core/robot/runtime_patch_diff.ts;viewer 可通过features/urdf-viewer/utils/robotLoaderDiff.ts兼容 re-export
8. Canonical Workspace / Source Documents
src/app/hooks/workspace-source-sync/robot_source_snapshot.ts:source snapshot 的稳定序列化;该目录不持有 robot 镜像src/core/robot/componentSourceDraft.ts:component-owned draft 与 semantic hash;library source 只是不可变模板src/app/utils/sourceCodeDocuments.ts:按 active component 构造可编辑 document;multi/bridge workspace 只提供只读 projectionsrc/app/hooks/workspace-mutations/*:所有业务 mutation 显式携带 component/entity target- structured mutation 后只允许 patch 对应 component draft 或使其失效;禁止回写共享 library template
- source full apply 在 store 外 parse/validate,再以 revision CAS 原子替换目标 component robot + matching draft
- 不得恢复
useWorkspaceSourceSync、single-component reuse/reseed、source-scene mirror 或 renderer-strategy mutation 分支
8.1 Scene Projection Boundary
src/core/robot/assemblySceneProjection.ts:输出 direct/assembledRobotData与EntityRef双向 global ID mappingsrc/core/robot/assemblyScenePlacement.ts:统一 Assembly/component root transform,renderer 与 export 共用direct-component仅是性能策略;selection、mutation、history、source apply 和 export target 不得以此分流- projection 只读且不得写回 store;owner 解析只能查 mapping,禁止按字符串前缀猜测
8.2 Workflow / Runtime Lifecycle Owners
src/app/hooks/robotLoadWorkflow.ts是 document load/import 的线性 use case;pre-resolved cache 与 worker completion 必须汇入同一 finish/commit 路径,React/store 绑定只放useRobotLoadWorkflow.tssrc/features/urdf-viewer/hooks/viewer-controller/useClosedLoopPreviewScheduler.ts独占闭环预览 worker session、RAF、pending request、generation/in-flight serial 和 unmount cleanup;controller facade 不得复制这些 refs 或另开求解入口src/app/utils/importPreparation.ts只保留顶层 workflow/facade;共享 DTO/集合、sidecar reference、archive collector、loose-file collector 分别位于import-preparation/对应模块,archive/loose 路径复用同一 sidecar 解析能力src/features/urdf-viewer/utils/usdOffscreenInteractionState.ts独占 offscreen selection/hover、mesh/pick/helper index、raycaster/pointer 与 highlight snapshot;stage reset 恢复 highlight 并清索引但保留 selection,full reset 才清空交互选择src/app/hooks/useWorkspaceViewerDerivations.ts负责 workspace→semantic scene/projection/placement/viewer document/source document/joint read model;高频 live joint motion 不得使 semantic projection/placement 失去 identitysrc/app/hooks/useAppLayoutSnapshotWorkflow.ts独占 snapshot action refs、preview session、capture cancellation/progress 与 debug API cleanup;AppLayout只组合其稳定输出src/app/components/unified-viewer/useUnifiedViewerSceneLifecycle.ts独占 retained Three.js graph、document scope、inactive scene timer、release timer 和 unmount cleanupsrc/features/urdf-viewer/utils/usdDeferredSceneSnapshotLifecycle.ts独占 deferred scene snapshot 的 pending payload、单 timer、generation/revision、stage clear 与 terminal disposesrc/app/components/snapshot-dialog/snapshotCaptureForm.ts独占 capture form 默认值、JPEG/透明背景不变量、压缩档位和翻译后的 choice model;SnapshotDialog保留窗口/preview render 生命周期
9. Debuggability First
默认原则:兜底不是默认美德,silent fallback 会掩盖真实问题、污染状态、拉高排障成本。
必须遵循:
- 默认优先暴露真实错误,不吞错、不改写异常、不偷偷切备用路径
- 禁止新增
catch -> 返回空值/默认值/旧缓存/伪成功状态的 silent fallback - 导入、导出、hydration、roundtrip、解析、viewer 初始化等 source-of-truth 链路禁止不透明兜底
- Worker bridge / off-main-thread 链路默认 fail fast,不要因 worker 不可用就在主线程悄悄补实现
- 禁止用"自动重试 + 自动降级 + 自动切换备用实现"掩盖根因
若必须保留窄兜底,同时满足:
- 保留原始错误信息、栈与触发条件
- 能被用户或开发者明确观察到
- 不得悄悄改写 source of truth
- 注释说明为何必须兜底及降级到什么
10. Linux 哲学与 Linus taste
这是一级工程约束,不是风格建议。
默认取向:
- 优先简单直接的数据流与控制流,不为"理论优雅"引入额外抽象层
- 优先解决真实问题,不为未来场景预埋复杂框架
- 优先把复杂度消灭在设计里,不包进 manager/factory/coordinator 名字里
必须遵循:
- 小而清晰的接口优先
- 优先组合现有稳定模块,不新增"万能层""统一抽象层""Base*"或过度泛化封装
- 优先通过更好的数据结构消灭特殊情况,不继续堆
if/else - 命名必须直白,描述真实语义、所有权、生命周期和失败路径
- 不把坏状态悄悄修平;异常时暴露不变量被破坏的位置
- 新抽象必须证明降低了整体复杂度;只搬运复杂度则不抽
明确不鼓励:
- 为"模式统一"引入不需要的架构层
- 过度 OO / 继承 / 配置化 / 泛型化
- 把复杂交互拆成大量弱关联小文件
- 用 silent fallback、隐式同步、魔法默认值维持表面整洁
- 为避免修改旧代码而额外包适配器
11. 内存 / 生命周期约束
- 新增
ResizeObserver、全局事件监听、RAF、timer、worker listener、ImageBitmap、object URL、THREE 材质/几何体/纹理、OffscreenCanvas 时必须同时实现对称 cleanup - shared worker / singleton runtime 必须明确所有者和释放边界
- 新增 shared worker / singleton runtime 时,评审必须能指出对应
dispose*/reset*调用点 - 临时缓存必须有上限、淘汰策略或显式 dispose/reset 路径
12. 依赖检查命令
分层红线、app feature deep import surface 与 import 循环由 scripts/tools/dependency_boundaries.mjs 机器化把关(零依赖,复用 @/* -> src/* alias):
npm run deps:audit # 报告越层 import、app feature deep import 与循环依赖
npm run deps:check # CI 阻断门(当前 cycles/deep-import baseline 均为空)
该脚本编码 §1 的方向(core 禁 React/越层、features 禁互相 import、shared/store/lib 禁向上、types 为 leaf),也会拦截非 .cjs 产品源中可绕过 ESM 图的 require()。§3 的存量例外只按精确 importer/specifier/target allowlist。app 对 feature 子路径的 deep import 和 import cycle 新增或 baseline stale 都会让 --check 失败;当前两个 baseline 清单均为空。npm run lint 已串联 deps:check。下列 rg 命令仅作快速人工排查备用:
# 检查潜在反向依赖(core/shared/store 对 features 的引用)
rg -n "from ['\"]@/features/" src/core src/shared src/store
# 检查 feature 间直接耦合
rg -n "from ['\"]@/features/" src/features
# 检查 shared 对 store 的依赖
rg -n "from ['\"]@/store/" src/shared
# 检查硬编码色值
rg -n "#[0-9A-Fa-f]{3,8}" src
# 检查 #0088FF 使用范围
rg -n "#0088FF|#0088ff" src | rg -v "Slider.tsx|styles/index.css"
13. 规模门禁与豁免(Size Budgets & Exemptions)
单文件/函数长度、圈复杂度、参数数、嵌套深度由 scripts/tools/google_style_audit.mjs 的 count-based 规则把关,走 google_style_baseline.json ratchet(存量 grandfather、仅净新增违规 fail;file-name-snake-case 已 retired,只报告不阻断)。当前阈值:file hard 800、function hard 200、complexity hard 20、params 4、depth 4(均 skipBlank+skipComments,仅作用 src/**,对 **/*.test.* / **/*.spec.* / scripts/** 关闭)。css-declaration-order 当前 baseline 为 0,新增乱序会阻断。原则:多数超长解析器/数值求解器是真实领域内聚,禁止为凑行数硬拆;只对存在"可干净抽离附带膨胀"的文件做定向重构。
以下文件/目录有意豁免所有 JS/TS 行长与复杂度门禁,不计入上述预算:
- 手写 C-ABI emscripten 源:
src/core/loaders/wasm/collada_mesh_parser.cpp、src/core/loaders/wasm/obj_parser.cpp。它们是单翻译单元(single TU)设计——单.cpp+-flto+ 匿名namespace内部链接,所有 helper 文件本地。拆成多 TU/头文件运行时零收益、只增 header 边界摩擦,故有意保留单文件;要可读性用 section banner 注释而非物理拆分。注意:构建是 C-ABIEXPORTED_FUNCTIONS模式(手动HEAPU8marshalling via*_get_result_ptr/*_get_result_size),不是 embind(无emscripten/bind.h/EMSCRIPTEN_BINDINGS/--bind)。.cpp 风格由.clang-format固定。 - 生成产物:
public/wasm/**(emscripten JS glue +.wasm二进制,由scripts/build/rebuild-*-wasm.sh生成,勿手改,改.cpp重跑脚本)、**/*.generated.*(ESLint 与 audit 一致跳过)。 - vendored 源:
third_party/**(魔改版 OpenUSD)、src/features/urdf-viewer/runtime/**(USD WASM runtime)。