Initialize Trellis project guidelines
This commit is contained in:
219
.trellis/spec/preview/index.md
Normal file
219
.trellis/spec/preview/index.md
Normal file
@@ -0,0 +1,219 @@
|
||||
# Preview:Cesium 预览层
|
||||
|
||||
> 覆盖 `scripts/lib/cesium-preview.js`(672 行)与 `cesium-preview.css`(230 行)。
|
||||
> 运行时:浏览器。全仓唯一的 DOM 环境。
|
||||
|
||||
---
|
||||
|
||||
## 定位
|
||||
|
||||
预览层是**验证性的,不是产物本身**。它加载 `cesium` 阶段导出的 `.glb` + `.json`,
|
||||
用来确认资产在真实 Cesium 里的样子。改这一层**不会**改变 Blender/GLB 主资产。
|
||||
|
||||
车辆巡航同理——README 里写明它是"用于验证高精度巡航可用性的预览层功能"。
|
||||
|
||||
---
|
||||
|
||||
## 没有构建步骤
|
||||
|
||||
```
|
||||
scripts/lib/cesium-preview.js ─── 原样 copyFileSync ──▶ outputs/<area>/cesium-preview.js
|
||||
scripts/lib/cesium-preview.css ─── 原样 copyFileSync ──▶ outputs/<area>/cesium-preview.css
|
||||
(build-area.js:328-335)
|
||||
<area>-cesium-preview.html ─── 模板字符串生成 ────▶ 同目录
|
||||
(build-area.js:697)
|
||||
```
|
||||
|
||||
所以:**没有打包、没有转译、没有 npm 依赖、没有模块系统**。浏览器直接吃。
|
||||
写代码时只能用目标浏览器原生支持的语法,`Cesium` 从 CDN 全局引入。
|
||||
|
||||
整个文件是一个 IIFE + `"use strict"`(`cesium-preview.js:1-2`)。
|
||||
|
||||
---
|
||||
|
||||
## 参数注入
|
||||
|
||||
JS 不硬编码任何文件名,全部从 HTML 注入的全局对象读:
|
||||
|
||||
```js
|
||||
const config = window.OSM_ASSET_PREVIEW_CONFIG || {}; // :4
|
||||
// config.areaId / .glbName / .metadataName / .routeName / .vehicleModelName
|
||||
```
|
||||
|
||||
生成侧在 `build-area.js:697 cesiumPreviewHtml()`,注入时**必须转义**:
|
||||
|
||||
| 场景 | 用 |
|
||||
|---|---|
|
||||
| HTML 文本/属性 | `escapeHtml()`(`build-area.js:759`) |
|
||||
| `<script>` 里的 JSON | `escapeScriptJson()`(`:767`) |
|
||||
|
||||
`|| {}` 的兜底不能删——它让 JS 在没有配置块时也不至于在第一行就崩。
|
||||
|
||||
**加一个新的可配置项**:`cesiumPreviewHtml()` 里加进注入的 JSON,JS 侧从 `config` 读,
|
||||
两边都要动。
|
||||
|
||||
---
|
||||
|
||||
## 加载流程
|
||||
|
||||
`main()`(`:30-52`)的顺序是刻意的:
|
||||
|
||||
```
|
||||
setLoadingMessage("Loading scene")
|
||||
→ fetchJson(metadata) 必需,失败即终止
|
||||
→ fetchOptionalJson(route) 可选,失败降级
|
||||
→ scenePlacement(metadata)
|
||||
→ createViewer()
|
||||
setLoadingMessage("Loading model")
|
||||
→ loadSceneAssets() 逐个资产加载,失败收集不中断
|
||||
→ addVehicleCruises() / createCameraPresets()
|
||||
→ buildAssetToggles() / bindRuntimeControls() / startDiagnostics()
|
||||
→ cameras.overview()
|
||||
→ baseStatus = summaryText(...)
|
||||
setLoadingMessage("Preparing view")
|
||||
→ await waitForStableFrames() 等画面稳定
|
||||
→ document.body.classList.add("scene-ready") ← CSS 靠这个类收起遮罩
|
||||
→ window.osmPreview = {...}
|
||||
```
|
||||
|
||||
### 三档失败语义
|
||||
|
||||
这一层的错误处理分得很清楚,**新增加载逻辑时要先想清楚落在哪一档**:
|
||||
|
||||
| 档 | 做法 | 出处 |
|
||||
|---|---|---|
|
||||
| **必需** | `fetchJson` 直接抛,预览起不来 | `:55-62` |
|
||||
| **可选** | `fetchOptionalJson` 捕获 → `console.warn` → 返回 `null` | `:63-73` |
|
||||
| **部分** | 逐条收集失败,汇总到诊断面板,其余照常显示 | `:163-165` |
|
||||
|
||||
两段注释把理由写清楚了:
|
||||
|
||||
> The route file is an extra on top of the scene, not a precondition for it.
|
||||
> A missing or unreadable route costs the cruise controls, not the preview.
|
||||
|
||||
> One broken entry in metadata.assets should not blank the whole preview, so
|
||||
> failures are collected and surfaced in the diagnostics panel instead.
|
||||
|
||||
### `scene-ready` 是加载态的唯一开关
|
||||
|
||||
`waitForStableFrames()`(`:107`)等若干帧稳定后才加 `scene-ready` 类,CSS 据此
|
||||
收起遮罩。**不要改成定时器或 `load` 事件**——材质编译完成之前画面是花的。
|
||||
|
||||
### `window.osmPreview` 是唯一对外句柄
|
||||
|
||||
```js
|
||||
// Handle for the browser console and for headless checks: everything else
|
||||
// in here is closed over by the IIFE and unreachable from outside. :50-51
|
||||
window.osmPreview = { viewer, metadata, placement, assets, cruise, cameras };
|
||||
```
|
||||
|
||||
调试和无头检查都靠它。**加新的顶层对象就往这里挂**,不要再开新全局。
|
||||
|
||||
---
|
||||
|
||||
## Viewer 配置:一切都关掉
|
||||
|
||||
`createViewer()`(`:74-97`)把 Cesium 的默认 UI 和地球全部关闭:
|
||||
|
||||
```js
|
||||
animation, timeline, baseLayerPicker, geocoder,
|
||||
navigationHelpButton, sceneModePicker, infoBox,
|
||||
selectionIndicator, baseLayer ← 全 false
|
||||
globe.show = false ← 不显示地球
|
||||
skyAtmosphere / skyBox / sun / moon ← 全 false
|
||||
backgroundColor = globe.baseColor = "#d9e0e2" ← PREVIEW_BACKGROUND
|
||||
```
|
||||
|
||||
理由:这是**看单个园区资产**的预览,不是地图应用。留着地球和大气会干扰对
|
||||
材质与几何的判断,也让背景色不可控。
|
||||
|
||||
`depthTestAgainstTerrain = false` —— 没有地形,开着只会让模型被裁。
|
||||
|
||||
保留的只有 `homeButton` 和 `fullscreenButton`。
|
||||
|
||||
---
|
||||
|
||||
## DOM 与状态
|
||||
|
||||
### DOM 句柄集中在顶部
|
||||
|
||||
`:5-20` 一次性取完全部元素引用,**不在函数里现查**。新增控件时加在这一批里。
|
||||
|
||||
### status 的两类消息
|
||||
|
||||
```js
|
||||
// Status carries two kinds of message: the scene summary, which is what the
|
||||
// panel should read whenever nothing else is going on, and transient notes
|
||||
// from a control the user just touched. Keep the summary so the transient
|
||||
// note can be replaced instead of destroying it. :21-24
|
||||
let baseStatus = "";
|
||||
```
|
||||
|
||||
`baseStatus` 存场景摘要,瞬时提示用完要能回到它。**加新的瞬时提示时不要直接覆写
|
||||
`baseStatus`**。
|
||||
|
||||
### 诊断读数跟渲染循环,不跟定时器
|
||||
|
||||
```js
|
||||
// Camera-dependent readouts have to track the camera, so refresh off the
|
||||
// render loop rather than a fixed timer, throttled to stay off the hot path. :589-590
|
||||
```
|
||||
|
||||
相机相关的读数必须跟着渲染循环刷新并**做节流**。用 `setInterval` 会在相机快速移动时
|
||||
读到过期值,不节流会拖慢帧率。
|
||||
|
||||
### 单资产 vs 多资产的开关
|
||||
|
||||
```js
|
||||
// A single-asset scene keeps the plain "Scene" checkbox; a multi-asset one
|
||||
// gets a child checkbox per model with "Scene" acting as the master. :194-195
|
||||
```
|
||||
|
||||
`buildAssetToggles()` 按资产数量决定 UI 形态,`syncSceneMaster()` 维护主从关系。
|
||||
|
||||
---
|
||||
|
||||
## 坐标系
|
||||
|
||||
GLB 停留在**局部 ENU 坐标系**(X 东、Y 北、Z 上),靠伴生 JSON 的放置信息配合
|
||||
`Cesium.Transforms.eastNorthUpToFixedFrame` 摆到地球上
|
||||
(`blender/export_cesium.py:8-9`)。
|
||||
|
||||
`scenePlacement(metadata)`(`:131`)负责这一步。**改动导出侧的坐标约定必须同步改这里。**
|
||||
|
||||
---
|
||||
|
||||
## 本地预览必须走 HTTP
|
||||
|
||||
```bash
|
||||
cd outputs/<area-id>
|
||||
python3 -m http.server 8765
|
||||
# → http://localhost:8765/<area-id>-cesium-preview.html
|
||||
```
|
||||
|
||||
`file://` 会被浏览器的同源策略拦掉 `fetch`,页面停在加载遮罩上。
|
||||
|
||||
---
|
||||
|
||||
## 反模式
|
||||
|
||||
| 反模式 | 后果 |
|
||||
|---|---|
|
||||
| 引入需要打包/转译的语法或 npm 依赖 | 没有构建步骤,直接跑不起来 |
|
||||
| 在 JS 里硬编码 `.glb` / `.json` 文件名 | 换区域就失效,绕过 config 注入 |
|
||||
| 注入 HTML 时不转义 | 区域名带特殊字符就破页面 |
|
||||
| 把可选资源当必需资源加载 | 缺一个路线文件整个预览打不开 |
|
||||
| 单个资产加载失败就中断全部 | 一条坏 metadata 让预览全白 |
|
||||
| 用定时器代替 `waitForStableFrames` | 遮罩在材质编译完成前就收起,画面是花的 |
|
||||
| 相机读数用 `setInterval` | 快速移动时读到过期值 |
|
||||
| 诊断刷新不节流 | 拖慢帧率 |
|
||||
| 再开一个全局变量 | 已有 `window.osmPreview` |
|
||||
| 用 `file://` 打开 | fetch 被拦,卡在加载中 |
|
||||
|
||||
---
|
||||
|
||||
## 相关
|
||||
|
||||
- [CLI 与阶段](../pipeline/cli-and-stages.md):`cesium` / `preview` 阶段如何生成这些文件
|
||||
- [资产生成](../blender/asset-generation.md):GLB 里的材质为什么要单独调色
|
||||
- README「实验:车辆巡航」节:面向使用者的说明
|
||||
Reference in New Issue
Block a user