# 场景与回放约定

## 分离三件事

1. **工艺数据**：输入输出、阶段、文案、参数、来源、表示方式、默认镜头。
2. **主题场景**：设备与材料、几何变化、特写和机理符号。
3. **播放底座**：统一时钟、拖动、暂停、倍速、镜头控制、UI 与渲染。

重复逻辑才提取。不要把整段上一主题脚本复制到新主题后只替换标题；也不要为了抽象而
给一个场景增加一套插件注册系统。已有技术栈中的组件、hooks、类或普通函数均可承载。

## 可采样的时间模型

约定 `sample(progress, seconds, delta)` 描述该时刻状态，其中 progress ∈ [0,1]。
几何位置、可见性、颜色、粒子、图表和读数都由同一时刻推导。尤其注意：

- 0 是有效初态，1 是已完成末态。暂停拖到 1 时保留末态，按播放继续才进入下一章。
- 拖动不自动增加物理时间；不要依赖不断 `rotation += delta` 来还原关键动作。
- `update` 同一时刻调用多次应得到同一状态，不能每帧新建纹理、几何或改变随机种子。
- 如果确需积分或历史求解，提供确定性 reset/replay 或缓存路径；不要假装它能直接任意 seek。
- 连续播放时正确处理上一章遗留时间。用真实时差推进工序，不能把所有帧截到 50 ms
  后把低帧率机器上的十秒动作变成三十秒。对物理求解使用固定子步并另行限制恢复策略。
- 后台标签页可以停止时间推进，但回到前台时应重设时钟基准，避免突然跳过多章。
- 暂停后仍可旋转相机；不要把相机交互和工艺时间混为一谈。

减少动态效果偏好应至少初始暂停、关闭自动环绕并缩短镜头过渡。若只是降低闪烁，
不能声称支持了减少动态效果。根据现有架构采用请求式渲染或暂停时的低成本刷新。

## 确定性粒子

可视化物质转移往往不需要粒子物理求解。为每个粒子固定种子，根据时间相位计算路径：

```javascript
const phase = (seconds * speed + seed) % 1;
particle.position.lerpVectors(source, target, phase);
particle.visible = processIsActive;
```

起点与终点应跟随当前几何。例如喷嘴移走后，粒子不能继续从旧位置穿越样品。
弧线、扩散和大小也可由种子推导。显示纯示意粒子时在场景语义中说明；不要用随机良率
制造看似真实的计量输出。晶粒形貌也不能由漂亮多边形声称得到实际显微分辨率。

## 数据一致性

曲线与指标应共享同一个模型或数据集。例如先计算 J(V)，再从它求最大功率点、FF、
效率，而不是在面板上硬编码一个与曲线无关的数字。写清单位、有效面积与归一化基准。
动画的“当前阶段”使用同一阶段边界，不让读数已经显示完成而画面仍在加工。
真实时间是带来源的工艺信息；演示时间只用于节奏。

## 模板的实际接口

`assets/starter/` 是自包含的页面源代码模板；依赖由 scaffold 从显式 vendor 目录复制。
`process-data.js` 是标准 JSON 右侧的单次全局赋值。`theme.js` 以 ID 为键绑定几何构建器，
从 manifest 转成共享播放器需要的 `group/dur/cam/update/readout`，不会复制元数据。
播放器尚不是场景编辑器或完整工业仿真引擎；新项目可以替换具体底座而保持上述语义。
复用已有播放器时检查其 DOM 依赖（例如图表 canvas、计数与状态节点），不要因为某章
没有图表就删除播放器仍要求的节点。可选能力应在底座中判空，或给出明确的缺失节点错误。

复制模板后的第一件事是明确真实主题和素材，而非修改模板来掩盖尚未实现的动画。
复杂资产优先用已有 CAD/glTF 或项目模型；若用简化几何，检查轮廓、机械接触和比例。
程序化三维模型适合代码工具；需要位图纹理/插图时再用对应图像工具，不把截图当模型。
