@realsee/vr-cli 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/NOTICE.md +7 -0
  2. package/README.md +216 -0
  3. package/TERMS.txt +54 -0
  4. package/agent-assets/AGENTS.md +113 -0
  5. package/agent-assets/adapters/.cursor/rules/realsee-vr.mdc +7 -0
  6. package/agent-assets/adapters/.github/copilot-instructions.md +1 -0
  7. package/agent-assets/adapters/.kiro/steering/realsee-vr.md +6 -0
  8. package/agent-assets/adapters/CLAUDE.md +3 -0
  9. package/bin/vr-cli.mjs +3 -0
  10. package/dist/cli.mjs +24 -0
  11. package/package.json +38 -0
  12. package/skills/realsee-image-resources/SKILL.md +82 -0
  13. package/skills/realsee-image-resources/references/cors-and-three-textures.md +50 -0
  14. package/skills/realsee-image-resources/references/data-wanxiang.md +57 -0
  15. package/skills/realsee-image-resources/references/five-image-url-transform.md +81 -0
  16. package/skills/realsee-image-resources/references/source-and-domain-policy.md +63 -0
  17. package/skills/realsee-vr-app/SKILL.md +157 -0
  18. package/skills/realsee-vr-app/references/continuous-improvement.md +24 -0
  19. package/skills/realsee-vr-app/references/dnalogel-api-capabilities.md +241 -0
  20. package/skills/realsee-vr-app/references/dnalogel-openapi-recipes.md +818 -0
  21. package/skills/realsee-vr-app/references/five-api-capabilities.md +119 -0
  22. package/skills/realsee-vr-app/references/five-runtime.md +83 -0
  23. package/skills/realsee-vr-app/references/official-docs.md +61 -0
  24. package/skills/realsee-vr-app/references/plugin-lifecycle.md +65 -0
  25. package/skills/realsee-vr-app/references/ui-and-validation.md +57 -0
  26. package/skills/realsee-vr-app/references/vapor-dom-layer.md +186 -0
  27. package/skills/realsee-vr-app/scripts/verify-project.mjs +1566 -0
  28. package/skills/threejs-r117-five/SKILL.md +71 -0
  29. package/skills/threejs-r117-five/references/five-ownership.md +70 -0
  30. package/skills/threejs-r117-five/references/r117-capabilities.md +82 -0
  31. package/skills/threejs-r117-five/references/r117-version-guards.md +60 -0
  32. package/templates/base/.editorconfig +12 -0
  33. package/templates/base/.env.example +12 -0
  34. package/templates/base/.gitignore.template +6 -0
  35. package/templates/base/.node-version +1 -0
  36. package/templates/base/.npmrc.template +3 -0
  37. package/templates/base/.nvmrc +1 -0
  38. package/templates/base/.prettierignore +12 -0
  39. package/templates/base/README.md +160 -0
  40. package/templates/base/eslint.config.mjs +75 -0
  41. package/templates/base/index.html +13 -0
  42. package/templates/base/package-lock.json +6444 -0
  43. package/templates/base/package.json +55 -0
  44. package/templates/base/prettier.config.mjs +5 -0
  45. package/templates/base/server/app.ts +54 -0
  46. package/templates/base/server/check-config.ts +4 -0
  47. package/templates/base/server/config.ts +54 -0
  48. package/templates/base/server/index.ts +31 -0
  49. package/templates/base/server/realsee-open-api.ts +316 -0
  50. package/templates/base/server/types.ts +64 -0
  51. package/templates/base/server/work-route.ts +80 -0
  52. package/templates/base/server/work-service.ts +54 -0
  53. package/templates/base/shared/model-floorplan.ts +242 -0
  54. package/templates/base/src/main.tsx +11 -0
  55. package/templates/base/src/shared/useElementSize.ts +28 -0
  56. package/templates/base/src/styles.css +91 -0
  57. package/templates/base/src/vr/five/SpatialRuntimeProvider.tsx +234 -0
  58. package/templates/base/src/vr/five/api.ts +10 -0
  59. package/templates/base/src/vr/five/fiveConfig.ts +42 -0
  60. package/templates/base/src/vr/five/initialState.ts +48 -0
  61. package/templates/base/src/vr/plugins/SpatialPluginRegistry.ts +104 -0
  62. package/templates/base/src/vr/plugins/dnalogel.ts +2 -0
  63. package/templates/base/src/vr/plugins/examples/FeatureOwnedMeshPlugin.ts +73 -0
  64. package/templates/base/src/vr/work/WorkSource.ts +247 -0
  65. package/templates/base/tsconfig.json +27 -0
  66. package/templates/base/tsconfig.server.json +25 -0
  67. package/templates/base/vite.config.ts +21 -0
  68. package/templates/viewer/src/app/App.tsx +182 -0
  69. package/templates/viewer/src/features/floorplan/ModelFloorplanFeature.ts +141 -0
  70. package/templates/viewer/src/features/navigation/ModeSwitcher.tsx +111 -0
  71. package/templates/viewer/src/features/tags/PanoTagFeature.ts +110 -0
  72. package/templates/viewer/src/ui/ViewerOverlay.tsx +141 -0
@@ -0,0 +1,119 @@
1
+ # Five 6.8.9 native capability map
2
+
3
+ This map describes the complete public native Five spatial surface available to the generated React application. Exact signatures come from installed declarations; never infer a method from this summary.
4
+
5
+ ## Source-of-truth order
6
+
7
+ 1. `node_modules/@realsee/five/package.json` for public export paths.
8
+ 2. `node_modules/@realsee/five/AI_CONTEXT.md` and `llms.txt` for the version-bundled documentation index.
9
+ 3. `node_modules/@realsee/five/ai_guides/api.md` and the matching feature guide.
10
+ 4. The relevant installed `index.d.ts` and referenced declaration for exact signatures.
11
+
12
+ ## Use the shipped Five documentation set
13
+
14
+ Five ships about 400K of AI-oriented documentation with the package, so route a task into it instead of guessing or searching the web. Do **not** read `node_modules/@realsee/five/docs/`: it is auto-generated HTML and the package explicitly excludes it.
15
+
16
+ | Need | Installed file |
17
+ | -------------------------------------------------------------------------- | ------------------------------ |
18
+ | entry point and reading order | `AI_CONTEXT.md` |
19
+ | scenario table (`场景 → 文档速查`) plus per-doc keyword `tags` | `llms.txt` |
20
+ | core vocabulary before writing code: Observer, Pose, Mode, Work, PanoIndex | `ai_guides/glossary.md` |
21
+ | API signature index | `ai_guides/api.md` |
22
+ | one capability in depth (32 guides) | `ai_guides/features/<name>.md` |
23
+ | categorized map and architecture guidance | `ai_guides/README.md` |
24
+ | behavior changes across 6.6/6.7/6.8 | `ai_guides/release_notes/` |
25
+
26
+ Read `glossary.md` first when the request involves pano identity, pose or mode vocabulary; most State and observer mistakes are vocabulary mistakes. When the scenario table does not match, keyword-match the `tags` block at the bottom of each feature guide. `ai_guides/ai-doc-guidelines.md` is for maintaining Five's own docs, not for application work.
27
+
28
+ Because `five/index.d.ts` re-exports `./model`, `./work` and `./renderer` with `export *`, grepping the barrel for a symbol name is not proof that it is missing. Compile an import against the installed declarations before concluding that an API does not exist.
29
+
30
+ Frequently requested capabilities that map to a guide and a declared API:
31
+
32
+ | Product ask | Declared API | Guide |
33
+ | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
34
+ | DOM label/HUD following a 3D point | `five.project2d(vector, testModel?)` returning `Vector2 \| null`, updated on the `render.prepare` event | `features/screen-project.md` |
35
+ | click picking, floor detection | `five.model.intersectRaycaster`, gesture events | `features/raycast.md`, `features/gesture.md` |
36
+ | screenshot, magnifier, colour picker | `five.getPixels(...)`, `five.getSize(target)`, `five.getDrawingBufferSize(target)` | `features/get-screen-pixels.md` |
37
+ | authenticated or privately deployed resources, CDN rewriting | `FiveInitArgs.requestProxy?(url) => string \| Promise<string>` | `features/request-proxy.md` |
38
+ | panorama colour grading | `panoFilter` material parameter via `five.modelScene.parameter.set('panoFilter', filter)` | `features/pano-filter.md` |
39
+ | model section view, roof removal | clipper parameters on the PBM material | `features/clipper.md` |
40
+ | camera fly-through, pano transitions | `five.updateCamera`, `five.moveToPano`, `five.changeMode` | `features/camera-animation.md`, `features/move-pano-effect.md` |
41
+ | first-screen and refinement progress | model `loaded` versus refined signals | `features/load-progress.md` |
42
+ | sandbox or comparison of several Works | `five.works`, `five.load`, scoped State | `features/multi-work.md` |
43
+
44
+ ## Runtime-only feature flow
45
+
46
+ A feature with no upstream data source does not use the BFF. Use this sequence instead of the OpenAPI recipe flow, keeping the same ownership discipline:
47
+
48
+ 1. **Confirm the capability exists:** find the scenario row above, read the guide, and confirm the exact signature in the installed declarations. Compile an import rather than trusting a barrel grep.
49
+ 2. **Pick the readiness gate:** panorama-only work for pano-scoped APIs, `five.model` readiness for model-dependent ones, positive host dimensions before anything that reads size. Do not start a model-dependent effect on a panorama-only Work.
50
+ 3. **Own it from one focused adapter under `src/features/`:** validate user input (finite numbers, bounded sizes, allowed enums), keep the native Five instance visible, and expose typed actions to the DOM layer.
51
+ 4. **Retain every disposer:** event subscriptions from `five.on`, animation loops, media, and any Three object you added to `five.scene`. Register dynamic plugins through `SpatialPluginRegistry` and release them with identity-safe `unregister`.
52
+ 5. **Trigger a frame when you mutate the scene:** set `five.needsRender = true` after changing owned objects or material parameters; use `render.prepare` for per-frame DOM synchronization rather than a private `requestAnimationFrame` loop.
53
+ 6. **Isolate failure:** an unsupported browser capability or a failed effect disables only that feature and leaves the base Viewer usable.
54
+ 7. **Validate:** typecheck, lint, build, verifier, then confirm in a real browser that the effect appears, that teardown leaves no listener or Three resource, and that a remount does not stack duplicates.
55
+
56
+ `requestProxy` is a constructor option, not a runtime method. Five installs a default proxy that rewrites legacy `vrlab-*.ljcdn.com` hosts to their `realsee-cdn.cn` equivalents, so replacing it wholesale can silently drop that mapping; compose with the default behaviour and keep the approved-host policy from the sibling [realsee-image-resources Skill](../../realsee-image-resources/SKILL.md). Credentials belong in the BFF, never in a browser proxy.
57
+
58
+ The local `src/vr/five/api.ts` exposes supported native public entries without wrapping or narrowing them. Direct imports from the package remain valid and are preferred for tree shaking.
59
+
60
+ ## Supported public entry points
61
+
62
+ | Import | Capability |
63
+ | ------------------------------- | ------------------------------------------------------------------------------------------------- |
64
+ | `@realsee/five` | Five runtime, Work, State, modes, camera, model, renderer, network, events, coordinates and WebXR |
65
+ | `@realsee/five/plugins` | Built-in spatial, CSS2D/CSS3D, trajectory, animation, object helper and Gaussian entrance plugins |
66
+ | `@realsee/five/line` | Wide line geometry, material and line objects |
67
+ | `@realsee/five/sticker` | Spatial sticker and intersection support |
68
+ | `@realsee/five/vfx` | Flame, light, airflow and particle effects |
69
+ | `@realsee/five/gltf-loader` | GLTF/DRACO/DDS loaders and parser types |
70
+ | `@realsee/five/shader-lib` | Clipping, alignment, sweep, shine and custom shader utilities |
71
+ | `@realsee/five/work-downloader` | Work resource download and image processing helpers |
72
+
73
+ The package also publishes framework adapters. This project intentionally excludes `@realsee/five/react` because that wrapper can lag behind the native runtime. React remains available for local composition, Context and DOM UI only.
74
+
75
+ ## Core spatial capability domains
76
+
77
+ ### Runtime and initialization
78
+
79
+ Use `Five`, `FiveInitArgs`, controller init arguments, `FiveLoadOptions`, viewport configuration and constructor plugins. `src/vr/five/fiveConfig.ts` supplies reviewed `FiveInitArgs`; `SpatialRuntimeProvider` calls `new Five(...)` directly and exposes the instance through `useSpatialRuntime()`.
80
+
81
+ For the default single viewport, Five owns its internal renderer. After the host has positive dimensions, call `five.appendTo(host, size)`, then `five.refresh(size, pixelRatio)` on later positive resizes. Use an external renderer and `setViewport` only when a feature truly needs shared-canvas viewports and can own renderer sizing and disposal explicitly.
82
+
83
+ ### Work and multi-Work
84
+
85
+ Use `parseWork`, `Work`, `Works`, `createWorks`, loose Work types and `workToJson`. Keep raw payload, `workCode`, optional `baseURL` and initial State together. Sandbox or comparison features may load multiple Works; do not force the default single-Work example into a global limitation.
86
+
87
+ `five.load` returns `Promise<void>` but has no declared AbortSignal or cancel method in 6.8.9. Abort network acquisition, ignore stale continuations and design explicit ordering for dynamic Work replacement.
88
+
89
+ ### State, modes, camera and controllers
90
+
91
+ Use `State`, `Pose`, `Mode`, camera/controller init types, `five.getCurrentState`, `setState`, `changeMode` and camera/controller APIs declared by the installed version. Preserve Work identity with snapshots. Read the bundled State, Mode and camera guides before changing transitions.
92
+
93
+ ### Events, gestures and animation
94
+
95
+ Use typed Five event maps, base/gesture/intersection/mode/model/network/pano/render/state/Works/XR events, `Motion` and `AnimationFrameLoop`. Prefer the disposer returned by `five.on`/`once`; pair every subscription, hook, loop and gesture interception with cleanup.
96
+
97
+ ### Coordinates, projection and picking
98
+
99
+ Use vector/coordinate utilities, pano heading/longitude utilities, `five.project2d`, `five.camera`, model intersections, raycasters and bounding volumes. Keep DOM screen coordinates, NDC, Five world coordinates and Work coordinates explicit.
100
+
101
+ ### Model, PBM, point cloud and 3D Tiles
102
+
103
+ The main entry exposes model scenes/layers/material parameters, PBM mesh/point cloud/splat types, loaders for PBM/AT3D/Dome/B3DM/PNTS/GLTF/PLY/FBX/X3P/Splat/SPZ, Tileset/Tile/Trajectory scheduling and intersection types. Gate model-only features on model readiness, not only `five.load` completion.
104
+
105
+ ### Renderer, resources and visual effects
106
+
107
+ Use scene/camera/renderer objects, textures, image URL transforms, image/texture options, post-processing composer and passes, pano meshes, clipping/bounding helpers, shaders, line/sticker/VFX and external model loaders. Image-source authorization, approved CDN selection, Five `defaultImageURLTransform`, 数据万象 and browser CORS belong to the sibling [realsee-image-resources Skill](../../realsee-image-resources/SKILL.md); this capability map retains Five API and ownership responsibilities. Dispose owned Three objects, materials, textures, passes and animation loops explicitly.
108
+
109
+ ### Network and resource policy
110
+
111
+ Use `Fetcher`, network subscribe/error types and image URL policy for authenticated CDN or private deployment adapters. Credentials remain server-only; browser resource transforms may receive only browser-safe URLs or tokens explicitly approved for exposure.
112
+
113
+ ### Native lifecycle
114
+
115
+ There is no public `start()` or `destroy()` contract in 6.8.9. Automatic playback is controlled by `FiveInitArgs.play`; runtime control uses `play()` and `pause()`. Teardown uses `dispose()`. Save `getElement()` before disposal and remove the unmanaged canvas afterward because public declarations do not guarantee DOM detachment or dispose idempotence.
116
+
117
+ ## Extension rule
118
+
119
+ A feature may import any supported native capability above. Add a feature adapter only to own business data, lifecycle or UI composition; never create a wrapper that hides the native Five instance or blocks an SDK capability.
@@ -0,0 +1,83 @@
1
+ # Five runtime invariants
2
+
3
+ ## Work loading
4
+
5
+ - Accept Work through a `WorkSource` boundary, not from a hardcoded business endpoint or local `work.json`.
6
+ - The browser route is `/{resourceCode}` and the Viewer calls only the same-origin `/api/work/{resourceCode}` contract. Do not add `VITE_WORK_URL` or embed a business endpoint.
7
+ - The generated Fastify BFF is a replaceable TypeScript example. Keep the shared contracts in `server/types.ts`, Realsee token exchange/cache and upstream calls in `server/realsee-open-api.ts`, the framework-neutral browser envelope in `server/work-service.ts`, and HTTP adaptation in `server/work-route.ts`. Node runs these files directly through type stripping, so `server/` must stay erasable-only and keep explicit `.ts` import extensions.
8
+ - A Go or other backend may replace `server/`, but must preserve `GET /api/work/{resourceCode}` and return `{ work, workCode, baseURL?, capabilities?: { modelFloorplan } }` without exposing credentials or tokens.
9
+ - Use the single `.env.example` as the server/deployment schema. Only the BFF reads `REALSEE_GATEWAY_ENDPOINT`, `REALSEE_GATEWAY_APP_KEY` and `REALSEE_GATEWAY_APP_SECRET`; browser code reads none of them.
10
+ - Keep the real `REALSEE_GATEWAY_APP_SECRET`, access token and OpenAPI authorization logic in the BFF environment or secret manager. Never expose them through `VITE_*`, Vite `define/envPrefix`, client source, query strings, browser request headers, logs or returned Work envelopes.
11
+ - Carry `workCode`, optional `baseURL`, raw Work and optional initial State together. Preset feature input must be explicit; only `presetData.panoTagList` or a validated named feature-data contract may feed a plugin.
12
+ - Never infer PanoTag from generic `tags`, `tagList` or `tag_list` fields. `/open/v3/hot/list` is authoritative only after its envelope and typed tag records are validated by a named BFF adapter.
13
+ - Call `parseWork(raw, { workCode, baseURL })` before `five.load`.
14
+ - Abort network requests on unmount and ignore late continuations.
15
+ - Five 6.8.9 declares no AbortSignal or load-cancel API. Do not claim that aborting fetch cancels an in-flight `five.load`; serialize dynamic replacements or replace the owned instance when strict ordering is required.
16
+
17
+ ## OpenAPI-backed feature data
18
+
19
+ Spatial capability resolution order: installed @realsee/dnalogel preset -> native Five -> Three.js.
20
+
21
+ - Tags, hotspots, and anchors default to PanoTagPlugin with GET /open/v3/hot/list.
22
+ - Tours use Five State snapshots with GET /open/v3/observerpicture/search.
23
+ - Model annotations default to ModelMakerPlugin with GET /open/v3/annotation/search.
24
+ - Floorplans default to ModelFloorplanPlugin with GET /open/v3/floorplan/plugins.
25
+ - Routes use GuideLinePlugin for rendering and shape-selected CruisePlugin or MovePlugin playback with GET /open/v3/route/search.
26
+ - SDK-shaped custom data requires an explicit developer opt-out from Open Platform data.
27
+
28
+ All five authenticated GET requests use `resource_code` and an access token in the `Authorization` header. Keep those calls in the BFF, expose only application-specific same-origin contracts, validate response envelopes as untrusted data, and adapt them to installed SDK types. The `format_floorplan_url` second hop is an uncredentialed redirect-free HTTPS fetch, not a sixth authenticated gateway request. OpenAPI shapes are not permission to cast arbitrary JSON to `Tags`, ModelMaker `ServerData`, GuideLine data, `ModelFloorplanServerData` or Five `State`.
29
+
30
+ An explicit Open Platform opt-out allows locally supplied data only when it follows the installed SDK declaration. It does not relax browser credential isolation, Work immutability, persistence authorization, media provenance or lifecycle cleanup.
31
+
32
+ ### Feature readiness and failure isolation
33
+
34
+ Treat transport success, validated data, runtime readiness and visible/playing state as separate gates. Every feature request carries the active `workCode` plus a monotonically increasing generation token; abort its fetch on replacement and ignore every continuation whose token or Work no longer matches.
35
+
36
+ | Feature | Required gate | Do not wait for / assume |
37
+ | ----------------------------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
38
+ | Tour | Work loaded; referenced pano resolves in `five.observers` | Model readiness; `five.setState` is not awaitable |
39
+ | PanoTag point/plane | Work loaded and validated tag anchor | Model readiness unless content/anchor is model-dependent |
40
+ | ModelMaker | Work declares a usable model and the active model becomes loaded | A panorama-only Work will eventually emit model readiness |
41
+ | GuideLine rendering | Validated single geometry branch and, for the installed `load` path, active model readiness | `load` makes lines visible or starts playback |
42
+ | Cruise pano/keyframe playback | Work/observers loaded plus validated pano indexes or keyframes | GuideLine data is a Cruise action; model readiness |
43
+ | Move custom-curve playback | Model-capable Work plus one validated model-space curve | GuideLine `PathItem[]` is directly accepted; multiple `CurvePath.curves` are all played |
44
+
45
+ `GuideLinePlugin.load` waits for model readiness; `CruisePlugin` waits only for Work and observers; `MovePlugin` enters Model and awaits Five readiness when playback starts.
46
+
47
+ Reject empty routes, unknown pano indexes, unsupported curves, non-finite coordinates, timing or speed, and ambiguous multi-segment Move paths before plugin load.
48
+
49
+ On a panorama-only Work, do not call the installed GuideLine `load` and wait forever. Keep validated Cruise pano playback available and expose line rendering as unavailable; never start model-only Move custom-curve playback. Distinguish ready-empty from malformed/error. API, schema, ModelMaker, GuideLine, Cruise or Move failure disables only that feature; it must not fail the base Work Viewer, reinterpret raw data, or trigger an automatic custom Three fallback. Keep GuideLine rendering and Cruise/Move playback errors independent.
50
+
51
+ ## State and modes
52
+
53
+ - `State` is the authoritative spatial snapshot. Capture tour points with `five.getCurrentState()` and restore them with `five.setState()` while preserving `workCode`, `mode`, `panoIndex` and supported pose fields.
54
+ - `/open/v3/observerpicture/search` records may provide `pano_index`, longitude, latitude and fov; validate and map these to a `Partial<State>` rather than creating an independent camera model. If persisted as JSON, serialize vector fields to plain numbers and reconstruct them explicitly.
55
+ - `Panorama`: first-person panoramic navigation.
56
+ - `Mapview`: product three-dimensional overview.
57
+ - `Topview`: top-down map/floor structure.
58
+ - `Model` and `Floorplan` have different semantics; do not alias labels by guesswork.
59
+ - Listen to `mode.change` and call the returned disposer during cleanup.
60
+
61
+ ## Native construction and rendering
62
+
63
+ - Import `Five` and `FiveInitArgs` from `@realsee/five`; never use `@realsee/five/react`, `createFiveProvider`, `FiveCanvas` or framework hooks.
64
+ - Keep constructor options in `fiveConfig.ts`, but create the instance inside the mounted host lifecycle rather than as a module singleton.
65
+ - Wait for positive host width and height before `new Five(...)` and `five.appendTo(host, size)`.
66
+ - Observe the native surface and call `five.refresh(size, window.devicePixelRatio)` only for positive sizes.
67
+ - The default single viewport lets Five own its internal renderer. If an external renderer is introduced, the application must mount its canvas, size it and define renderer ownership explicitly.
68
+ - Use the same pinned Three package as Five integrations.
69
+ - Feature readiness may require model refinement after `five.load`; gate model-only controls separately.
70
+
71
+ ## Ownership and teardown
72
+
73
+ - A mounted native surface owns exactly one Five instance, one `SpatialPluginRegistry` and one unmanaged canvas.
74
+ - React StrictMode/HMR must be safe: keep ownership effect-local, guard stale async work and never reuse a disposed module-level instance.
75
+ - Dispose feature subscriptions/media/plugins first, drain the dynamic registry, save `five.getElement()`, call `five.dispose()` once, then remove the canvas.
76
+ - Public 6.8.9 declarations do not guarantee dispose idempotence, automatic canvas detachment or ownership of an externally supplied renderer.
77
+ - Use WebGL2 fallback for unsupported old iOS environments.
78
+ - Make resource URL transformation an injected policy for private/offline deployments.
79
+ - Route image provenance, approved CDN hosts, Five `defaultImageURLTransform`, 数据万象 operations and browser CORS through the sibling [realsee-image-resources Skill](../../realsee-image-resources/SKILL.md); this runtime reference continues to own Five construction, State and teardown invariants.
80
+
81
+ ## Model floorplan contract
82
+
83
+ The complete model floorplan contract lives in [dnalogel-api-capabilities.md](dnalogel-api-capabilities.md); follow it there rather than a copy that can drift.
@@ -0,0 +1,61 @@
1
+ # Official and installed documentation map
2
+
3
+ Installed declarations and package-bundled guides are authoritative for the versions actually resolved by `package-lock.json`; generated minimums and versioned baseline references are routing aids, not substitutes for the target installation.
4
+
5
+ ## Five 6.8.9
6
+
7
+ Read locally in this order:
8
+
9
+ 1. `node_modules/@realsee/five/AI_CONTEXT.md`
10
+ 2. `node_modules/@realsee/five/llms.txt`
11
+ 3. the selected guide under `node_modules/@realsee/five/ai_guides/`
12
+ 4. the matching public `index.d.ts` and referenced declaration
13
+
14
+ Public native package entry points are listed in [five-api-capabilities.md](five-api-capabilities.md). Although the package publishes framework adapters, this project intentionally forbids `@realsee/five/react`; verify behavior against the native `Five` declarations instead of copying adapter examples.
15
+
16
+ ## Realsee image resources
17
+
18
+ Read the sibling portable Skill at [realsee-image-resources/SKILL.md](../../realsee-image-resources/SKILL.md) for image provenance, approved CDN domains, Five `defaultImageURLTransform`, 数据万象 processing and browser CORS. Its installed-Five checks complement this runtime map without changing Five or Three ownership boundaries.
19
+
20
+ ## Three.js 0.117.1
21
+
22
+ Read `node_modules/three/package.json`, then `node_modules/three/src/Three.d.ts` and the selected declaration. Extension modules must be confirmed under `node_modules/three/examples/jsm`; this version has no `three/addons` export. Use the sibling portable Skill at `../../threejs-r117-five/SKILL.md` for the ten capability domains, Five ownership and modern-to-r117 migration guards.
23
+
24
+ The knowledge-domain taxonomy was inspired by [CloudAI-X/threejs-skills](https://github.com/CloudAI-X/threejs-skills), whose README targets r160+. The local Skill is independently rewritten and pinned to r117; upstream snippets are not a signature source.
25
+
26
+ ## dnalogel 3.81.2
27
+
28
+ Read `node_modules/@realsee/dnalogel/libs/index.d.ts`, then the selected plugin's declarations and installed docs. Plugin return types and lifecycle methods are not uniform. For any spatial, VR or 3D request, inspect the installed preset catalog before writing native Five/Three code. Requests classified as tags, hotspots or anchors default to `PanoTagPlugin`; model annotations default to `ModelMakerPlugin`; route geometry uses `GuideLinePlugin`, point/keyframe playback uses `CruisePlugin`, and custom model-space curve playback uses `MovePlugin`. PanoTag content/anchors are declared under `libs/PanoTagPlugin/typings/tag/{TagData,Tag,Utils}.d.ts`; virtual-screen candidates include `ModelTVVideoPlugin`, `CSS3DRenderPlugin`, `PanoVideoPlugin` and, only after a preset gap is established, custom Five/Three plugins. The root catalog and decision workflow are in [dnalogel-api-capabilities.md](dnalogel-api-capabilities.md).
29
+
30
+ ## Vapor 0.2.12
31
+
32
+ Use the installed package types for exact component props and the authorized Vapor component site for behavior. Vapor remains a DOM library; read [vapor-dom-layer.md](vapor-dom-layer.md).
33
+
34
+ ## External indexes
35
+
36
+ - [Realsee OpenAPI reference](https://open-platform.realsee.com/developer/openapi/?id=1001) (authoritative 中文版 id=1001); its backing [OpenAPI specification](https://open-platform.realsee.com/api/open/1001/) is the machine-readable contract.
37
+ - [`POST /auth/access_token`](https://open-platform.realsee.com/developer/openapi/?id=1001#post-/auth/access_token): form-encoded `app_key`/`app_secret`; returns `{ code, status, data: { access_token, expire_at } }`; token TTL is 5 minutes, so cache it server-side.
38
+ - [`GET /open/v3/vr/info?resource_code=...`](https://open-platform.realsee.com/developer/openapi/?id=1001#get-/open/v3/vr/info): send the raw access token in the `Authorization` header; `data` carries the Work payload (`base_url`, `initial`, `model`, `observers`, `panorama`, `_signature`, `allow_hosts`, `certificate`, `expire_at`, `resource_code`).
39
+ - [`GET /open/v3/hot/list?resource_code=...`](https://open-platform.realsee.com/developer/openapi/?id=1001#get-/open/v3/hot/list): authoritative tag/hotspot/anchor data; response `data` contains `globalConfig`, `contentTypeConfig` and `tagList`, which must be validated against installed PanoTag declarations. Optional fields may be `null` even when the schema presents object types, so normalize `null` to absence before SDK validation.
40
+ - [`GET /open/v3/observerpicture/search?resource_code=...`](https://open-platform.realsee.com/developer/openapi/?id=1001#get-/open/v3/observerpicture/search): authoritative tour-point list under `data.list`. Each item has display metadata and nested pose `data` (`pano_index`, longitude, latitude, fov, heading and floor index); live responses may also contain nullable optional pose fields. Map only validated pose fields to Five `Partial<State>` with the active Work identity.
41
+ - [`GET /open/v3/annotation/search?resource_code=...`](https://open-platform.realsee.com/developer/openapi/?id=1001#get-/open/v3/annotation/search): authoritative model-annotation list under `data.list`. Records provide ids, `type`, object-valued `object_data`, labels and space identifiers; validate the geometry discriminator and finite coordinates before adapting to ModelMaker `{ list }`.
42
+ - `GET /open/v3/floorplan/plugins?resource_code=...`: returns a descriptor whose `data.format_floorplan_url` points to the preferred `{ version, data: FloorplanServerData }` plugin input. Do not read `format_model_url`; fetch the second-hop URL only as uncredentialed redirect-free HTTPS and validate the complete nested shape before exposing `capabilities.modelFloorplan`.
43
+ - [`GET /open/v3/route/search?resource_code=...`](https://open-platform.realsee.com/developer/openapi/?id=1001#get-/open/v3/route/search): authoritative route list under `data.list`, with optional `is_asc`. Records may provide ids, `pano_group`, `path`, `panorama_style_config`, `model_style_config` and `visible_floor_indexes`; the OpenAPI transport schema is not a dnalogel plugin input. Validate a selected product branch, adapt only its geometry to GuideLine, then independently build Cruise `{ panoIndexList }` or Move `{ path }` playback data. Do not use the annotation endpoint as a route source.
44
+ - OpenAPI route records are never passed raw: rename validated style config only for GuideLine `lines`, and never pass GuideLine `PathItem` arrays or style objects to `CruisePlugin` or `MovePlugin`.
45
+ - If a source record contains both `pano_group` and `path`, the route adapter must choose product semantics explicitly and pass only the selected geometry branch to GuideLine.
46
+ - For all three list APIs, HTTP success plus `code === 0` and an array `data.list` is the transport boundary. An empty array is ready-empty; malformed records or a nonzero business code are not empty success. The machine-readable source is the [OpenAPI V3 Chinese specification](https://open-platform.realsee.com/api/open/1001/).
47
+ - These authenticated OpenAPI calls are server-only. Use a typed BFF/data adapter, validate the envelope, and expose only the minimum same-origin browser contract. SDK-shaped custom data is allowed only after an explicit developer opt-out from Open Platform data.
48
+ - Gateway servers: `https://app-gateway.realsee.cn` (中文版) and `https://app-gateway.realsee.jp` (overseas ids 1002/1003).
49
+ - `/open/v1/entity/vr`, `/open/v1/work/download` and `/open/v1/work/sign` are archived in the reference; do not treat them as the current Work data contract.
50
+ - Realsee Open Platform and Five: https://open-platform.realsee.com/developer/docs/five/intro/
51
+ - Five package documentation: https://unpkg.com/@realsee/five/docs/index.html
52
+ - dnalogel package documentation: https://unpkg.com/@realsee/dnalogel/docs/index.html
53
+ - Vapor components: https://vapor.realsee.cn/?path=/docs/introduction--docs
54
+ - Agent Skills specification: https://agentskills.io/specification
55
+ - AGENTS.md format: https://agents.md/
56
+
57
+ Do not copy SDK source or documentation bodies into generated projects. Record version-specific integration decisions and link to installed or authoritative material.
58
+
59
+ ## Model floorplan contract
60
+
61
+ The complete model floorplan contract lives in [dnalogel-api-capabilities.md](dnalogel-api-capabilities.md); follow it there rather than a copy that can drift.
@@ -0,0 +1,65 @@
1
+ # Spatial plugin lifecycle and registration
2
+
3
+ ## Two native plugin mechanisms
4
+
5
+ Do not conflate these APIs:
6
+
7
+ 1. `FiveInitArgs.plugins`: constructor-time Five plugins owned by the Five instance.
8
+ 2. `five.plugins`: a string-keyed runtime lookup dictionary with no register/unregister methods.
9
+
10
+ Do not use the separate caches/hooks exposed by `@realsee/five/react`; the generated application uses only the native Five instance and its plugin dictionary.
11
+
12
+ The generated `SpatialPluginRegistry` is vendor-neutral and manages only dynamically created entries in `five.plugins`, whether they come from dnalogel presets or application-defined Five plugins. It rejects a name already owned outside the registry, unregisters by object identity so stale cleanup cannot remove a newer instance, and drains remaining plugins even if one disposer fails.
13
+
14
+ For custom plugins whose factory immediately adds objects or subscriptions, construct the candidate first and wrap `plugins.register(name, candidate)` in `try/catch`; call the candidate's idempotent `dispose()` before rethrowing a registration error. Enable it from a focused feature and pair the successful registration with `SpatialRuntimeLifetime.own(() => plugins.unregister(name, candidate))`. The opt-in `src/vr/plugins/examples/FeatureOwnedMeshPlugin.ts` demonstrates this pattern and should be the starting point for Agent-generated Three features.
15
+
16
+ ## Capability-based lifecycle
17
+
18
+ Neither dnalogel nor the local registry defines a universal plugin lifecycle interface. For each dnalogel preset, inspect its installed factory return type; for each custom Five plugin, define and review its local return type. Handle only declared capabilities:
19
+
20
+ 1. Create it for the current Five instance.
21
+ 2. Register it only if cross-feature lookup is needed.
22
+ 3. Call `load` only if declared, after the plugin's Work/model readiness gate.
23
+ 4. Call `enable`/`disable` only if declared and required by that plugin.
24
+ 5. Subscribe to declared hooks once and retain unsubscribe callbacks.
25
+ 6. Stop declared media, cruise, animation or loops before disposal.
26
+ 7. Clear loaded data where the plugin supports it.
27
+ 8. For a registered instance, call identity-safe `plugins.unregister(name, expected)` only after pending work settles; unregister invokes its declared `dispose` when present.
28
+ 9. Call `dispose` directly only for a candidate that failed before registration or for an explicitly unregistered owner.
29
+
30
+ Cleanup must be idempotent under React StrictMode, HMR, Work changes and aborted requests. During full surface teardown, feature cleanup and registry drain happen before `five.dispose()`.
31
+
32
+ ## Spatial annotation lifecycle
33
+
34
+ A VR spatial tag is a domain annotation, not a plugin type. Classify content, renderer, anchor and lifecycle/data ownership, then follow the project capability order: installed dnalogel preset, native Five, then Three through Five's ownership boundaries. Requests classified as tags, hotspots or anchors default to `PanoTagPlugin`; requests classified as model-space geometric annotations default to `ModelMakerPlugin`. A text popover, model annotation, four-point video screen and custom Three object may have unrelated readiness gates and cleanup contracts even when product language calls all of them “tags”.
35
+
36
+ OpenAPI-backed feature data is fetched and authorized by the BFF, validated as untrusted input and adapted to the exact installed plugin type. Use `/open/v3/hot/list` for PanoTag data, `/open/v3/annotation/search` for ModelMaker data, `/open/v3/floorplan/plugins` then `data.format_floorplan_url` for complete ModelFloorplan data, `/open/v3/route/search` for separate GuideLine rendering and shape-selected Cruise/Move playback inputs, and `/open/v3/observerpicture/search` for Five State tour snapshots. Only an explicit developer opt-out from Open Platform data allows SDK-shaped local data.
37
+
38
+ Do not infer PanoTag from a generic `tags`, `tagList` or `tag_list` field, Panorama mode or a screenshot. Never directly edit `work.json`, downloaded Work or customer Work. Persistence requires an explicit authoritative editor/API/BFF/source contract and user confirmation; otherwise keep the feature runtime-only or emit a typed patch proposal. All media/model URLs must come from Work, an approved API/CDN or user-authorized assets.
39
+
40
+ ## Feature-specific ownership
41
+
42
+ - **Tour:** it is Five State application, not a plugin. Abort the feature request, invalidate its work/generation token, remove `state.synced` or UI subscriptions, and never apply a late State to a different Work. Do not restore a captured State after the owning Work changes.
43
+ - **ModelMaker:** create it only for a model-capable Work. On replacement or failure, abort/ignore pending data, remove hooks, call declared `disable()` and `clear()` when initialized, wait for pending load, then call identity-safe unregister once; unregister performs disposal. A non-empty upstream list with no valid geometry is an error, while an empty list is ready-empty.
44
+ - **Route controllers:** point-route playback owns one `CruisePlugin`; custom model-space playback owns one `MovePlugin`; GuideLine remains a separate renderer. Do not call `GuideLineItem.walk()` as a managed production controller because its temporary playback ownership and completion semantics are not sufficient for cancellation. Stop new playback, call declared `pause()`, remove hooks, clear GuideLine data, wait for pending loads, then unregister each registered owner exactly once. GuideLine failure must not destroy independently valid point playback, and playback failure must not remove an already rendered line.
45
+ - Route cleanup pauses the owned playback controller before hook removal and disposal; `clear` belongs to GuideLine, is not a public Cruise operation, and GuideLine disposal does not own an external or embedded Cruise controller automatically.
46
+ - Do not invent `RoutePlugin`, `PanoRove`, `stop()`, or a universal route controller; use only the exports and methods declared by the installed package.
47
+ - **Panorama-only routes:** the installed GuideLine `load` waits for a model, so do not start that load on a Work that cannot satisfy the gate. Mark line rendering unavailable while retaining validated pano-index Cruise playback; custom-curve Move playback is model-only.
48
+
49
+ Every async feature must capture both the active `workCode` and a generation token before fetch/load. A cleanup invalidates the token first, then aborts requests and ignores late continuations before touching plugin state. Runtime API/schema/plugin failure is feature-local; never silently feed raw data to the SDK or create an unreviewed Three fallback.
50
+
51
+ ## Explicit PanoTag preset example
52
+
53
+ The generated `PanoTagFeature` demonstrates the preferred plugin for tags, hotspots and anchors, but it does not perform a browser-side OpenAPI call. `WorkSource` accepts only the explicit `presetData.panoTagList` source contract, validates its required `contentType`, `position` and `data` shape, and exposes the installed `Tags['tagList']` type. A product integration may instead supply a named BFF contract backed by validated `/open/v3/hot/list` data. Generic `tags`, `tagList` and `tag_list` fields never activate the preset. The feature owns PanoTag creation, click hook, exact typed load and disposal. Selection may locate and blink a tag without unexpectedly changing the user's current mode.
54
+
55
+ `model_file` is not a PanoTag 3.81.2 canonical content type. For models or virtual screens, classify behavior and choose canonical `Model`, `MediaModel` or `MediaPlane`, `ModelTVVideoPlugin`, `CSS3DRenderPlugin`, `PanoVideoPlugin`, or—only when no preset satisfies the behavior—a focused custom Five/Three plugin.
56
+
57
+ ## Multi-instance applications
58
+
59
+ A plugin belongs to a Five viewport and usually an active Work. Sandboxes, comparison views and multi-Work applications require identity scoped by viewport and Work. Never use an unscoped process-global plugin singleton.
60
+
61
+ For the complete dnalogel preset family catalog, read [dnalogel-api-capabilities.md](dnalogel-api-capabilities.md). Custom Five plugins remain responsible for their own local contracts.
62
+
63
+ ## Model floorplan contract
64
+
65
+ The complete model floorplan contract lives in [dnalogel-api-capabilities.md](dnalogel-api-capabilities.md); follow it there rather than a copy that can drift.
@@ -0,0 +1,57 @@
1
+ # DOM layering and browser validation
2
+
3
+ Read [vapor-dom-layer.md](vapor-dom-layer.md) first. Vapor is a DOM component library above the spatial scene, not part of Five/dnalogel rendering.
4
+
5
+ ## Layering
6
+
7
+ - Import `@realsee/vapor/vapor.css` once at the application entry.
8
+ - Keep the native `five-surface` host and the DOM overlay as siblings inside the spatial stage.
9
+ - Five alone owns the canvas inserted under `five-surface`; React must not reconcile that canvas node.
10
+ - Transparent full-stage roots use `pointer-events: none`.
11
+ - Re-enable pointer events only on visible controls, drawers, dialogs, masks and intentional interaction surfaces.
12
+ - Mount UI according to feature readiness, not as a substitute for spatial readiness.
13
+
14
+ ## Browser diagnostics
15
+
16
+ Inspect:
17
+
18
+ - native Five canvas, `five-surface` and overlay rectangles;
19
+ - `elementsFromPoint` at canvas and control positions;
20
+ - Five mode/state and the relevant plugin state;
21
+ - active requests, event disposers, animation loops, media and WebGL/Three resources;
22
+ - remount behavior under StrictMode/HMR and the absence of stale canvases;
23
+ - transition animations and `document.visibilityState` when DOM motion appears stuck.
24
+
25
+ Do not add production `!important` overrides to compensate for a hidden or frozen automation page.
26
+
27
+ ## Vapor runtime validation matrix
28
+
29
+ Static markers and screenshots do not prove that a Vapor composition matches the installed runtime. For each affected viewport and overlay state, verify:
30
+
31
+ - exactly one executable `@realsee/vapor/vapor.css` import and no `vapor.scss` or copied internal stylesheet;
32
+ - the `Vapor` provider rectangle matches the DOM overlay host and the selected theme is an installed `ThemeValue`;
33
+ - every used `useDimension().match()` rule belongs to the installed union, and the intended layout appears at each actual breakpoint in portrait and landscape;
34
+ - top, right, bottom and left safe-area behavior uses the declared source/merge rule without double-counting Provider insets and CSS `env()`;
35
+ - dialogs, modals, drawers, sheets, masks and dispatched overlays have correct portal order, focus entry/return, Escape/backdrop behavior and close reasons; in 0.2.12 `Dialog` reports exactly `escapeKeyDown`, `backdropClick` and `closeButtonClick`, and only the last is an accepted action;
36
+ - blank spatial-stage points resolve to the Five canvas while visible controls and intentional masks win `elementsFromPoint` inside their bounds;
37
+ - controls remain keyboard reachable with meaningful names, roles, state and live-region behavior;
38
+ - no application stylesheet overrides `.vapor-*` internals or redraws a component that exists in the installed package;
39
+ - typecheck validates every component prop, compound child and symbol against the target installed declarations. Static markers cannot do this: a hallucinated prop, an invalid `match()` rule or a wrong Toast payload is only caught by compiling the composition against the installed `.d.ts` files.
40
+
41
+ When an external recipe places a placeholder VR component under `Vapor`/`ZStack`, reuse only its DOM chrome composition. This generator must keep the Five canvas in the dedicated sibling `five-surface` host.
42
+
43
+ ## Acceptance checks
44
+
45
+ - For an explicit Vapor request, executable source must import and render the matching non-provider Vapor component; the provider and stylesheet alone are insufficient.
46
+ - Blank spatial-stage points resolve to `CANVAS`, not a transparent Vapor root.
47
+ - Visible DOM controls are the top hit target inside their own bounds.
48
+ - Five is not constructed at zero dimensions; later positive resizes update its drawing surface.
49
+ - Work load, model refinement and feature-ready indicators are not conflated.
50
+ - Relevant Five modes, events, projection/raycast and plugin behavior work for the changed feature.
51
+ - Remount, Work switch and aborted load leave no old canvas, plugin DOM, listeners, media or animation.
52
+ - Type check and production build pass.
53
+ - Built assets and browser requests contain no `REALSEE_GATEWAY_APP_SECRET` or real gateway credentials.
54
+
55
+ ## Model floorplan contract
56
+
57
+ The complete model floorplan contract lives in [dnalogel-api-capabilities.md](dnalogel-api-capabilities.md); follow it there rather than a copy that can drift.
@@ -0,0 +1,186 @@
1
+ # Vapor DOM layer boundary
2
+
3
+ Vapor is the generated application's React component library. It is not a spatial renderer and must not become an abstraction over Five or dnalogel.
4
+
5
+ ## Versioned documentation workflow
6
+
7
+ The current generated baseline is `@realsee/vapor@0.2.12`. Upstream or external `ai_guides` may describe a newer checkout, so use them for discovery and composition intent rather than as a copyable API contract.
8
+
9
+ Use this lookup order for every Vapor change:
10
+
11
+ 1. read the target project's installed `node_modules/@realsee/vapor/AI_CONTEXT.md` and `llms.txt`;
12
+ 2. use installed `node_modules/@realsee/vapor/ai_guides/README.md`, the relevant `components/*.md`, and `recipes/*.md` to discover candidate components and compositions;
13
+ 3. confirm every public named export in the installed root `vapor.d.ts`;
14
+ 4. confirm props, unions, refs, compound relationships and close reasons in the selected installed component declarations;
15
+ 5. when declarations do not settle a runtime default, inspect that installed implementation and validate it in a browser.
16
+
17
+ Use the installed `ai_guides` only for component discovery and composition recipes; the target project's root `vapor.d.ts` and selected component declarations are the API contract, and conflicts resolve in favor of installed declarations.
18
+
19
+ Do not copy version-sensitive examples blindly. The 0.2.12 baseline requires exactly one executable `@realsee/vapor/vapor.css` import, not `vapor.scss`; Toast methods/config, symbol exports, Provider defaults, breakpoint rules and compound component props must all be checked against the installed declarations. A symbol list from another checkout is not an allowlist.
20
+
21
+ ## Ownership
22
+
23
+ Vapor may own:
24
+
25
+ - toolbars, buttons, menus, forms, cards and status panels;
26
+ - drawers, dialogs, sheets, masks and notifications;
27
+ - responsive layout, visual tokens and DOM accessibility;
28
+ - UI state derived from spatial state.
29
+
30
+ Vapor must not own:
31
+
32
+ - Work parsing or loading;
33
+ - Five `State`, camera, mode or coordinates as an independent source of truth;
34
+ - model, panorama, raycast or WebGL rendering;
35
+ - native Five construction, renderer/canvas sizing or disposal;
36
+ - dnalogel preset or custom Five plugin construction, data loading or disposal;
37
+ - customer credentials or Open Platform requests.
38
+
39
+ ## Component fidelity
40
+
41
+ When the request explicitly names Vapor, map each applicable DOM control to a public named export from the installed root barrel before writing JSX. Version 0.2.12 includes exports such as `Button`, `Segmented`, `Switch`, `Checkbox`, `Toolbar`, `TitleBar`, `TabView`, `Dialog`, `Drawer`, `BottomSheet`, `Toast`, `Text`, `Card`, `Progress`, `HStack` and `VStack`; this list is illustrative, so declarations remain authoritative.
42
+
43
+ - When the user explicitly requests Vapor components, use matching named exports from the installed `@realsee/vapor` package for every applicable DOM control; importing `Vapor` or `vapor.css` alone does not satisfy the request.
44
+ - Do not replace an available Vapor component with raw HTML or a locally styled replica; use raw DOM only for semantics or capabilities absent from the installed Vapor declarations, and record that gap.
45
+ - Before implementing Vapor UI, read `node_modules/@realsee/vapor/AI_CONTEXT.md`, `llms.txt`, `vapor.d.ts`, and the selected component declarations; never invent component names or props.
46
+ - Use the installed `ai_guides` only for component discovery and composition recipes; the target project's root `vapor.d.ts` and selected component declarations are the API contract, and conflicts resolve in favor of installed declarations.
47
+
48
+ Import public components from `@realsee/vapor`, keep the stylesheet side-effect import at the application entry, and render all components under `Vapor`. Do not import internal component paths. Raw DOM remains valid for structural wrappers, semantic elements, canvas hosts and capabilities with no installed Vapor equivalent; it must not imitate an available Vapor control.
49
+
50
+ ### Recorded deviation: this generator's mode switcher
51
+
52
+ The rule above requires recording every raw-DOM deviation, so this one is recorded here rather than left for rediscovery.
53
+
54
+ `src/features/navigation/ModeSwitcher.tsx` intentionally does **not** use `Segmented`, even though `Segmented` is exported and semantically close. The generated verifier enforces this for that file, so an agent that "upgrades" the mode switcher to `Segmented` will fail `npm run check`. The declaration-based reason in 0.2.12:
55
+
56
+ - `SegmentedPropTypes` accepts only `options: { text: ReactNode; value: string }[]`, `value`, `onChange`, `appearance`, `size`, `prefix`, `suffix` and sizing props;
57
+ - `size` is limited to `'sm' | 'md'`, while this control needs `3rem`/`5rem` heights with `lg`/`xl` fonts;
58
+ - there is no per-option weight/opacity prop and no selected-indicator slot, so the selected-state treatment cannot be expressed;
59
+ - an earlier generated version stretched, and the fix required overriding `.vapor-segmented` internals, which is itself forbidden.
60
+
61
+ The switcher therefore composes `HStack`/`VStack`/`Button`/`Font` and keeps only the selected indicator as a small raw `div`. This is a recorded capability gap, not a licence to hand-roll other controls: `Segmented` remains the correct default for ordinary segmented pickers such as floor selection, where its installed sizing semantics do fit.
62
+
63
+ ## Component selection matrix
64
+
65
+ Choose by product semantics before styling:
66
+
67
+ - layout and decoration: `HStack`, `VStack`, `ZStack`, `Grid`, `Block`, `Box` and `Layer`;
68
+ - navigation and mode selection: `TitleBar`, `BottomBar`, `TabView`, `Toolbar` and `Segmented` when its installed sizing semantics fit the design;
69
+ - actions and form controls: `Button`, `Switch`, `Checkbox`, `SelectCircle` and the installed input components;
70
+ - feedback and overlays: `Dialog`, `Modal`, `Drawer`, `BottomSheet`, `Toast`, `Mask` and `Overlay`;
71
+ - content and status: `Text`, `Font`, `Icon`, `Image`, `Card`, `Badge`, `Progress` and installed media components;
72
+ - iconography: `Icon` with a named `*Symbol` export from the installed catalogue, never an inlined replacement SVG.
73
+
74
+ Raw DOM is appropriate for semantic wrappers, ARIA live regions, the Five host, native input capabilities explicitly required by a Vapor component, or a capability absent from the installed package. It must not recreate the appearance or interaction contract of an available Vapor control.
75
+
76
+ ## Provider, theme, layout and responsive semantics
77
+
78
+ - Keep one `Vapor` provider per overlay root unless a product requirement explicitly needs an isolated provider. Set its width and height to the overlay host contract and verify their rendered rectangles.
79
+ - `VaporConfig` defaults `width` to `100vw` and `height` to `100vh`. A provider mounted inside a sized overlay host must therefore override both, or it will size itself to the viewport instead of its host. This generator passes `width="100%"` and `height="100%"`.
80
+ - Use only the installed `ThemeValue`; 0.2.12 declares `arc_beauty`, `square_simple` and `minimalist`. Use local `Theme` boundaries only when the product intentionally changes theme inside the overlay.
81
+ - `HStack` arranges DOM horizontally, `VStack` vertically and `ZStack` overlays DOM children. `Layer` is a visual DOM gradient/vignette, not a Five scene layer.
82
+ - Use `useDimension()` for structural responsive changes. It returns `{ width, height, breakpoint, orientation, match }`; branch on `match(rule)` and `orientation`, not on raw pixel comparisons.
83
+ - The 0.2.12 match union is exact: `sm`, `>=sm`, `>sm`, `<md`, `<=md`, `md`, `>=md`, `>md`, `<lg`, `<=lg`, `lg`, `>=lg`, `>lg`, `<xl`, `<=xl` and `xl`; do not invent other matcher strings. Note there is no `<sm` and no `>xl` rule.
84
+ - A custom Provider `dimension` value must satisfy the complete installed shape: `{ sm: [number, number]; md: [number, number]; lg: [number, number]; unit: 'px' | 'rem' }`. `DimensionBreakpoint` includes `'xl'`, but the provider config has no `xl` entry: `xl` is the region above `lg`, so do not add an `xl` key. Use `useRemPx` only when JavaScript must convert design rem values to pixels; do not impose a global rem conversion toolchain.
85
+ - Preserve the public `saveAreaInsets` spelling and use `useSaveAreaInsets()` for Provider values. The Provider prop is `Partial`, while `useSaveAreaInsets()` returns all four edges as required numbers, so read insets from the hook instead of re-deriving defaults. Define whether Provider insets, browser `env(safe-area-inset-*)`, or both are authoritative; if both represent the same physical inset, de-duplicate rather than adding it twice. Validate all four edges in portrait and landscape.
86
+ - Error capture is the `Vapor` prop `errorBoundary?: boolean | ErrorBoundaryProps`, enabled by default; see `ai_guides/recipes/error-boundary.md` for `FallbackComponent` and `resetKeys`. 0.2.12 exports the `ErrorBoundaryProps` type but **no** `ErrorBoundary` component, so do not import one. A Vapor error boundary covers React DOM rendering only. It does not replace Five/plugin lifecycle cleanup or asynchronous resource error handling.
87
+
88
+ Keep the Five canvas in its dedicated sibling host outside `Vapor`; Vapor layout components own DOM chrome only, even when an external recipe nests a placeholder VR component inside a stack.
89
+
90
+ ## Composition
91
+
92
+ The native Five instance and dnalogel render the spatial scene. Five inserts its canvas into a dedicated host; the Vapor tree is a sibling DOM overlay positioned above it:
93
+
94
+ ```text
95
+ spatial-stage
96
+ ├── five-surface Five-owned native canvas
97
+ └── dom-overlay
98
+ └── Vapor DOM components only
99
+ ```
100
+
101
+ React may provide local Context and lifecycle ownership around the native instance, but must not import the Five React adapter. Spatial features expose typed state and actions to the UI. UI events call those actions; UI components do not reach into undocumented renderer internals.
102
+
103
+ ## Executable 0.2.12 patterns
104
+
105
+ These are the APIs whose shape is most often guessed wrong. Every signature below comes from the installed 0.2.12 declarations; re-confirm them after any Vapor upgrade. The installed `ai_guides/recipes/` directory carries the upstream long-form versions (`app-layout.md`, `responsive-layout.md`, `dispatch-overlay.md`, `slot-plug.md`, `error-boundary.md`).
106
+
107
+ ### Use the shipped documentation set instead of guessing
108
+
109
+ The installed package carries its own AI documentation, so do not paraphrase it here and do not search the web. `AI_CONTEXT.md` names the entry point, and `llms.txt` is a task-indexed router. Read in this order and stop as soon as the answer is authoritative:
110
+
111
+ | Need | Installed file |
112
+ | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
113
+ | entry point and reading order | `AI_CONTEXT.md` |
114
+ | "I want to do X" lookup table, component categories with keyword tags, Hooks index | `llms.txt` |
115
+ | full documentation map | `ai_guides/README.md` |
116
+ | one component's props/slots/examples | `ai_guides/components/<name>.md` (43 files) |
117
+ | composition patterns | `ai_guides/recipes/app-layout.md`, `responsive-layout.md`, `dispatch-overlay.md`, `slot-plug.md`, `error-boundary.md` |
118
+ | icon catalogue and `Icon` usage | `ai_guides/symbols/symbol-list.md`, `ai_guides/components/icon.md` |
119
+ | authoritative API contract | root `vapor.d.ts` plus the selected `components/**/*.d.ts` |
120
+
121
+ `llms.txt` already routes overlays, layout, navigation, media, forms, theming, Toast, cards, Fab and responsive work to the right component or recipe. Use it before inventing a composition, and prefer an upstream recipe over a hand-rolled one.
122
+
123
+ ### Icons arrive through a wildcard re-export
124
+
125
+ `vapor.d.ts` begins with `export * from './symbols';`, which adds about 133 named icon exports (`HomeSymbol`, `CloseSymbol`, `ArrowLeftSymbol`, …) plus the `IconSymbol` types. Scanning `vapor.d.ts` for explicit named exports therefore misses every icon, so consult `ai_guides/symbols/symbol-list.md` for the catalogue and confirm the identifier in `symbols/index.d.ts`. Usage is `<Icon symbol={HomeSymbol} type="solid" />`; never invent an icon name or inline a replacement SVG for an icon that exists.
126
+
127
+ Note that "symbol" means two unrelated things in this package: icon symbols, and the overlay identities created by `createOverlaySymbol`.
128
+
129
+ ### Verified 0.2.12 doc/declaration divergences
130
+
131
+ `ai_guides` is authored per release and can lag the declarations it ships with; that is why declarations win. These divergences are confirmed in the pinned 0.2.12 package, so follow the declaration column:
132
+
133
+ | Area | `ai_guides` says | Installed 0.2.12 declares |
134
+ | ------------- | --------------------------------- | --------------------------------------------------------------------------- |
135
+ | Toast trigger | `toast.add(Toast, { message })` | `useToast()` returns `{ show, dismiss }`; there is no `add` |
136
+ | Toast payload | `message: string`, `icon: string` | `content?: string[]`, `icon?: ReactNode`; `ToastPropTypes` has no `message` |
137
+
138
+ So a Toast reads:
139
+
140
+ ```tsx
141
+ const toast = useToast();
142
+ toast.show({ content: ["已保存当前视角"], duration: 2000 });
143
+ ```
144
+
145
+ `content` is `string[]`, not a string or a `ReactNode`, and one array entry renders one line. Treat any other `ai_guides` example the same way: if it does not compile against the installed declarations, the declarations are right and the example is stale.
146
+
147
+ ### Overlay stacking uses overlay identities, not z-index literals
148
+
149
+ `createOverlaySymbol(description, level?: 0 | 1 | 2 | 3 | 4)` creates an identity; `useOverlayRegister(description, level, visible)` (or `(description, visible)`) returns `{ isTop, zIndex }`; `useOverlayVisible(...descriptions)` reports whether any of them is open; `useOverlayManager()` exposes `isTop`, `getZIndex`, `add`, `remove`, `has` and `onChange`. Use these instead of hand-picked `z-index` values, and use `useOverlayVisible` to suppress spatial gestures while an overlay covers the canvas.
150
+
151
+ The returned `zIndex` applies to **your own** overlay element, not to a built-in one. `DialogPropTypes` declares no `className`, `style` or `zIndex`, so `Dialog` owns its portal and stacking; the same holds for the other built-in overlays. Attempting to restyle them from the application is the `.vapor-*` override that is forbidden elsewhere in this reference. For a custom layer, wrap a single element in `Overlay` (declared as `FC<PropsWithChildren<{}>>`, whose content must be one element) and apply `zIndex` there:
152
+
153
+ ```tsx
154
+ const { zIndex } = useOverlayRegister(
155
+ symbol.description,
156
+ symbol.level,
157
+ visible,
158
+ );
159
+ return (
160
+ <Overlay>
161
+ <div style={{ zIndex }} />
162
+ </Overlay>
163
+ );
164
+ ```
165
+
166
+ ### Overlays this generator must keep spatial-safe
167
+
168
+ Follow `ai_guides/recipes/dispatch-overlay.md` for imperative overlays and `slot-plug.md` for cross-component content; only the spatial constraints below are specific to this generator.
169
+
170
+ `useDispatchOverlayComponent(Component)` needs props containing `visible: boolean` and optional `onClose`, and its dispatch takes `Omit<Props, 'visible' | 'onClose'>`, so passing `visible` at the call site is a type error. An `onClose` handler returning `false` vetoes the close, so a spatial feature must not assume every close settles its state.
171
+
172
+ While an overlay covers the canvas, use `useOverlayVisible(...descriptions)` to suppress spatial gestures, and re-enable them when it closes. `DialogPropTypes.onClose` reports `'escapeKeyDown' | 'backdropClick' | 'closeButtonClick'`, and only the last is an accepted action; a cancellation must leave Five state untouched.
173
+
174
+ Slot names are plain strings with no compile-time registry, so centralize them in one constant module to keep a typo from silently rendering the fallback.
175
+
176
+ ### Reading spatial state into DOM
177
+
178
+ UI reads spatial state through a feature's typed accessors and calls its actions; it never mutates Five directly from a component body. Keep `match()`-driven layout branching in the DOM layer and Five mode changes in the feature layer, as `ModeSwitcher.tsx` does.
179
+
180
+ ## Pointer events
181
+
182
+ The full-stage `dom-overlay` and transparent Vapor roots use `pointer-events: none`. Only visible controls, dialogs, drawers, masks and intentional interaction surfaces use `pointer-events: auto`. Validate hit targets with `elementsFromPoint`; screenshots cannot prove event routing.
183
+
184
+ ## Lifecycle
185
+
186
+ DOM component unmount does not automatically dispose Five/dnalogel resources. Spatial feature adapters own requests, subscriptions, media, Three resources and plugin cleanup. The native surface owner drains those features and the registry before calling `five.dispose()` and removing the unmanaged canvas.