3.9 KiB
3.9 KiB
3D 编辑器侧边栏信息架构
目标布局
┌ 场景大纲与资产中心 ┐ ┌──────── 3D Viewport ────────┐ ┌ 右侧工作区 ──┐
│ 场景大纲(常驻) │ │ │ │ 检查器/控制/数据│
│ ├─ Robot │ │ │ │ 上下文属性 │
│ │ ├─ Body │ │ │ │ │
│ │ └─ Joint │ │ │ │ │
│ └─ Maps │ │ │ │ │
│ └─ Object │ │ │ │ │
├────────────────────┤ │ │ │ │
│ 资产库 | 工程文件 │ │ │ │ │
└────────────────────┘ └──────────────────────────────┘ └──────────────┘
- 场景大纲常驻,资产库与工程文件共享下半区,放置地图时无需在“结构/资产”之间切换。
- 右侧使用“检查器 / 控制台 / 数据录制”三个顶层视图;检查器内部根据统一选择自动路由到 Body、Joint、地图实例或地图对象。
- Python/ONNX 控制器、全局 Actuator/Joint 控制和数据录制不是对象属性,放在右侧独立视图中,不使用模态窗口,因此操作时始终能看到并交互仿真画面。
- 控制与训练等重型组件仅在首次进入对应右侧视图时懒加载。
- 控制台分区默认全部折叠,按“执行器控制 → 关节调试 → 外力交互 → Python 控制 → ONNX 推理 → 强化学习训练”排列,并在标题右侧显示“控制 / 调试 / 交互 / 推理 / 训练”功能标记。
状态与依赖边界
EditorSelection 是大纲高亮和检查器路由的唯一选择语义,只保存稳定 ID:
type EditorSelection =
| { kind: 'body'; bodyId: number }
| { kind: 'joint'; jointId: number; bodyId: number }
| { kind: 'map'; mapAssetId: string }
| { kind: 'map-object'; mapAssetId: string; objectId: string };
Viewer 的射线命中详情仍保留为临时 ViewerSelection,仅用于展示 geom 和世界位置,不再决定检查器类型。
组件职责:
ProjectSidebar:只编排常驻SceneOutliner、MapAssetLibrary和ProjectTree。SceneOutliner:把 simulation 与 map 数据投影成一棵可选择的场景树;不修改业务状态。MapAssetLibrary:只负责资产发现、点击添加和拖放,不再保存已放置实例树。ModelControlsSidebar:持有右侧栏壳层、顶层视图切换,并在检查器视图中按EditorSelection.kind路由。RobotInspector:承载模型摘要、Body 和 Joint 的领域 UI。PhysicalMapPanel:承载地图实例参数与地图对象精确属性,不再持有视口工具状态。MapViewportToolbar:在视口内统一承载 Transform、网格吸附与贴地检测,并与顶部ViewerToolDock共享交互状态。MapDraftStatusOverlay:常驻视口底部,统一显示改动计数以及场景级提交/丢弃入口。WorkspaceToolsPanel:懒加载并在右侧栏内承载控制器、全局仿真控制和数据录制。
所有选择入口遵循同一事件流:
场景树点击 / Viewer 拾取
↓
App 更新 EditorSelection(稳定 ID)
↓
SceneOutliner 高亮 + Inspector 自动路由
↓
领域面板发出 command callback
↓
App / MapEditSession / SimulationSession 执行修改
该实现只使用 React hooks、受控属性和 Tailwind class,兼容 React 18;当前工程使用 React 19 时无需兼容层。