# 三维 / 组态 / 地图场景配方与联动模板

> 返回 [SKILL.md](../../SKILL.md)。**硬门禁：piece 选项名一个都不许猜**——一律查本技能 `references/widgets/` 下的 [scene-3d.md](../widgets/scene-3d.md) / [scada-2d.md](../widgets/scada-2d.md) / [map-2d.md](../widgets/map-2d.md)（终极权威 [widget-schema.generated.json](../widget-schema.generated.json)）。本文只给"组合套路"，不是选项字典。

## 0. 通用：builder 组件经 addWidget 一次建成

`ctx.addWidget` / `screen.addWidget` 入参支持顶层 `pieces`（SDK `BuildPieceNodeInput`，自动补 uid）：

```ts
await screen.addWidget({
  type: 'scene-3d', uid: TWIN_UID, position: [24, 152], size: [1520, 904],
  options: {
    'geometry-unit': 'percent',
    'scene3d-initialized': true,            // scada 是 'scada-initialized'（防播种演示内容）
    'point-key-field': [f('conn_pts', 'tbl_pts', '键')],
    'point-value-field': [f('conn_pts', 'tbl_pts', '值')],
    interactions: twinInteractions(),
  },
  pieces: twinPieces(),
})
```

场景定义放 `scenes/*.ts`：导出 `XXX_UID` 常量 + `xxxPieces()` + `xxxInteractions()`，联动目标（设备→piece uid）集中成映射表。

## 1. scene-3d 配方（数字孪生）

- **固定开头**：单例 `{ uid:'scene3d-scene', type:'scene3d-scene' }` + `{ uid:'scene3d-camera', type:'scene3d-camera' }`（uid 逐字固定）；灯光 ambient + directional(cast-shadow)；地面 plane（`pickable:false`）。
- **零素材离线纪律**：背景用 `bg-mode:'sky'` 程序化天空；不用外链模型/瓦片/在线粒子预设；粒子只用内置 `fx-kind: fire/smoke/rain/snow/firework/text`。
- **常用组合**：楼宇/装置=`scene3d-extrude`(edges 科技棱线，flow-gradient 光效档)；罐=`scene3d-tank`(液位测点)；管道=`scene3d-pipe`(flow + `flow-rules` 按值启停)；周界=`scene3d-wall`(state-rules 变红 + blink)；区域=`scene3d-zone`；巡检=`scene3d-trail` + 形状 `path-points` 路径动画；点位批量=`scene3d-sprites`/`scene3d-points`；人员定位=`scene3d-persons`（**sprite 档离线安全**，`data-key` 测点值 JSON `[[id,x,y,z,名],…]` 差分平滑移动）；标注=`scene3d-label`/`scene3d-board`/`scene3d-fxmarker`/`scene3d-beam`；书签=`scene3d-view`；后期=`scene3d-effects`（bloom + `outline-hover` + `hover-tip`，每场景一份）。
- **测点驱动**：画板绑长表键/值两列；元素 `data-key` + `state-rules`（`值=颜色` 每行一条）/`blink-values`/`flow-rules`；热力/人员/点云的 `data-key` 值为 JSON 串整批刷新。
- **运行时增删 piece**：`scene.addPiece({ type:'scene3d-tank', uid, options })` / `scene.removePiece(uid)`（builder 通用句柄；禁止删 `scene3d-scene` / `scene3d-camera`）。不要只改 `raw.node.pieces`。
- **演练显隐**：火焰/烟雾粒子平时 `enabled:false` 或藏于状态，演练时用交互动作 `scene3dSetVisible`（经 receiveBehaviorEvent 触发）或直接改测点驱动的元素状态。

## 2. scada-2d 配方（工艺组态）

- 画板 options：`scene-width/height` 与摆放尺寸 1:1、`theme:'tech-blue'`、`appearance-3d:true`、`'scada-initialized': true`、绑长表键/值。
- **图元 node**：`shape` 从 159 种里选（泵 pump/阀 valve·motor-valve/罐 tank·sphere-tank/水箱 water-tank/立式换热器 shell-tube-exchanger/深井泵 deep-well-pump/污泥泵 sludge-pump/絮凝池 floc-tank/配水井 distribution-well/冷却塔/传感器 sensor·pressure-sensor/声光 beacon/数码屏 digital-display/仪表 gauge/温度计/流量计/火炬 flare-stack/标题栏 title-bar/状态牌 status-pill…）；几何用 `geo-x/y/w/h` 场景坐标；`fill/stroke` 留空跟随主题。
- **按值驱动**（全在 `data-enabled:true` 下）：`state-by-value`+`state-rules` 状态色；`anim-by-value`+`anim-rules`（`1=spin:1.6 / 0=none / 2=shake`——泵按值起转、故障抖动）；液面/仪表类形状配 `value-min/max` 量程自动画液位/指针，`show-value-text` 出读数；`fill-by-value` 阈值三段色（气体检测器标配）。
- **连线 link**：`from-node`+`from-port` / `to-node`+`to-port`（通用四边 n/e/s/w）+ `waypoints` 途径点；主工艺管用 `line-style:'pipe'`（线宽即管径 10~16）+ `flow:true`；按值流动 `data-enabled + data-key + flow-by-value + flow-rules`（`1=on:1.6\n0=off`）——泵停管路停流（含路径动画符号）的联动就靠它。
- **布局纪律**：先在注释里排版面坐标（回路走向、途径点避让图元），连线端点引用写完必跑一致性单测。
- 图元点击：代码侧 `ctx.getScada(uid).onNodeClick(payload => ...)`（开趋势窗等）。

## 3. map-2d 配方（GIS 一张图）

- **pieces 三段式**：`map-body`（单例、`uid:'map-body'`、放第一个）→ `map-source-*`（可选）→ 图层 `map-*`（数组顺序=叠放）。
- 地理模式（**map-body 的 options**，不是 map-2d 本体的）：`coordinate-system:'geographic'` + `basemap:'gaode-vec'`（需联网；离线降级为暗底不炸）+ `map-center`/`map-zoom`。
- **企业/设施点位**：`map-symbol` 或 `map-circle`，`data-input:'bind-fields'` 直接绑台账表 `marker-lng/lat/name/value`；**按属性变色**用 `map-circle`/`map-geojson` 的数据驱动样式：`point-color-mode:'field'` + `point-color-field` + `point-color-stops`（每行 `输入 => 颜色`，风险四色标配——`map-symbol` 是 `symbol-label-color-mode/field/stops` 组，具体键名查 map-2d.md §6.3-C/widget-schema）。
- **风险四色区域**：`map-source-geojson`（内联 FeatureCollection，属性带 name/level）+ `map-polygon`/`map-geojson` 引用源（`data-input:'source'` + `data-source-uid: [{ refType:'element', targetPath:['源uid'] }]`），填充色按属性 stops。
- **告警特效**：`map-fx-pulse-ring`（告警企业脉冲）/`map-fx-fire`（事故火点）绑一张"告警点位表"（sim 推行，空行=无特效）——特效层同享 §6.3 数据来源。
- **悬停/点击**：图层 `tooltip-enable`+`tooltip-fields`；交互写在 map-2d 自身 `options.interactions`（`marker-click` payload=要素属性行）；代码侧句柄 `ctx.getMap(uid)` → `flyTo/fitData/setZoom`（列表点行定位标配）。
- 控件：map-body 内置 `control-zoom`/`control-scale`/`control-compass` 等四角控件选项，或独立 `map-control-legend`/`map-control-view` 组件（`target-map` 留空=本页第一张图）。

## 4. 交互持久化模板（version 2）

```ts
function ix(trigger: { name: string; options?: Record<string, unknown> }, action: { name: string; options: Record<string, unknown> }, alias: string) {
  const trig = { name: trigger.name, options: trigger.options ?? {} }
  return { trigger: trig, interactions: [{ alias, enable: true, trigger: trig, action: { name: action.name, options: { start: 'meanwhile', delay: 0, duration: 1, ...action.options } } }] }
}
// options.interactions = { version: 2, groups: [ ix(...), ... ] }
```

常用分组（scene-3d）：

| 触发 | 动作 | 效果 |
|---|---|---|
| `scene3d-piece-click` | `scene3dPopup { mode:'open', 'piece-uid':'' }` | 点谁弹谁 |
| `scene3d-piece-dblclick` | `scene3dFocus { 'piece-uid':'', padding, 'fly-transition':true }` | 双击聚焦 |
| `receiveBehaviorEvent { eventName:'twin-focus' }` | `scene3dFocus { 'piece-uid':'' }`（留空取 payload.pieceUid） | 跨页告警定位 |
| `receiveBehaviorEvent { eventName:'twin-overview' }` | `scene3dFlyTo { 'view-uid':'v_overview' }` | 回总览书签 |

## 5. 跨页联动配方（代码侧）

- 告警 → 三维定位：`ctx.setActiveScreen('pg_twin')` + `setTimeout(() => ctx.emit('twin-focus', { pieceUid }, TWIN_UID), 400)`（切页动画留时）。
- 告警/列表 → 地图定位：`ctx.setActiveScreen('pg_map')` + `ctx.getMap(MAP_UID)?.flyTo(...)`。
- 表格点行 → 详情窗：`table.onSelect(sel => { 刷写窗内 uid 组件 setOption; ctx.openWindow('win_x', { keepPosition: true }) })`（`sel` 是选中维度 `{别名:值}` 非整行，整行用 `table.getValue().row`，见 [scaffold.md](scaffold.md) §4）。
- 演练副作用（自动开应急窗/切页）由 sim runtime 的事件回调执行，不进纯函数。
