114 lines
7.4 KiB
Markdown
114 lines
7.4 KiB
Markdown
# Guide Model State And View Baseline Contract
|
|
|
|
Use this contract for every change or audit involving the indoor guide model, POI focus, floor switching, detail-page return, camera reset, or model async work.
|
|
|
|
## Contents
|
|
|
|
- State ownership and initial state
|
|
- Overview and floor baselines
|
|
- Reset action contract
|
|
- POI detail return contract
|
|
- Async invalidation
|
|
- Prohibited reset mechanisms
|
|
- Required tests and audit checks
|
|
|
|
## State Ownership And Initial State
|
|
|
|
- Keep one shared business-state owner, preferably the existing `useGuideModelState` boundary. Do not introduce per-page reset flags or duplicate state managers.
|
|
- Keep `GUIDE_MODEL_INITIAL_STATE` immutable. Define it as the stable overview state captured only after the exterior/full-building model becomes ready for the first time.
|
|
- Derive the default floor and initial camera from model configuration, floor data, or the first stable ready state. Never hardcode `1F`, a floor ID, camera coordinates, target, or distance.
|
|
- Route state changes through explicit actions such as `initializeModel`, `enterOverview`, `switchFloor`, `focusPoi`, `clearPoiSelection`, `enterRoutePreview`, and `resetToViewBaseline`.
|
|
- Include at least these business fields in the shared contract:
|
|
- 3D/indoor mode, `indoorView`, and `layerMode`.
|
|
- Default active floor, requested floor, loading floor, and committed/rendered floor.
|
|
- Camera position, up, fov, zoom, controls target, and camera distance.
|
|
- Selected POI, active/highlighted POI, target focus request, and pending target focus.
|
|
- Visible POI IDs, temporary focus markers, focus labels, pulses, and hall highlights.
|
|
- Route preview, navigation simulation, and automatic floor-switch state.
|
|
- Model ready/loading/error state, model-load version, focus request ID, and reset generation.
|
|
|
|
## Overview And Floor Baselines
|
|
|
|
- Preserve the first stable exterior/full-building ready snapshot as the overview baseline.
|
|
- Maintain deterministic `FloorViewBaseline` values keyed by stable floor ID and a baseline cache key.
|
|
- Inherit observation direction, camera up, fov, zoom, composition, and screen-offset rules from the overview baseline.
|
|
- Compute each floor's controls target and camera distance from that floor's visible model bounding box. Do not copy the overview's absolute position and target to every floor.
|
|
- Never capture a floor baseline from a user-dragged camera, an animated camera, or a POI-focus camera.
|
|
- Return identical position, target, distance, direction, tilt, occupied-screen ratio, and visual center for repeated resets of the same floor within a reasonable epsilon.
|
|
- Invalidate a cached floor baseline when model/package version, visible model bounds, composition rules, or canvas aspect ratio changes.
|
|
|
|
## Reset Action Contract
|
|
|
|
Expose one renderer operation:
|
|
|
|
```ts
|
|
resetToViewBaseline({
|
|
view: 'overview' | 'floor',
|
|
floorId?: string,
|
|
reason: 'poi-detail-close' | 'manual-reset' | 'floor-reset'
|
|
})
|
|
```
|
|
|
|
Perform a floor reset in this order:
|
|
|
|
1. Increment the shared generation/request ID so old floor loads and focus requests become stale.
|
|
2. Cancel camera animation, target-focus work, and queued focus callbacks.
|
|
3. Clear selected POI, active/highlighted POI, target focus request, and pending target focus.
|
|
4. Dispose temporary markers, focus labels/pulses/bases, hall highlights, route previews, and navigation simulation.
|
|
5. Restore `visiblePoiIds` to `null`, reset search state, and collapse the search dock.
|
|
6. Switch to or confirm the target floor without remounting the renderer.
|
|
7. Apply the deterministic floor baseline only after that floor's model commit succeeds.
|
|
8. Reset automatic floor switching using the final restored camera distance.
|
|
9. Keep `ThreeMap`, WebGL, scene resources, and valid loaded-model caches alive.
|
|
|
|
- Make reset idempotent. Repeated calls with the same target view and floor must converge on the same business and camera state.
|
|
- If the renderer is not ready, retain only the newest reset request and apply it after ready. A failed model state must fail safely without reviving old POI state.
|
|
|
|
## POI Detail Return Contract
|
|
|
|
- Use a one-shot context instead of a boolean:
|
|
|
|
```ts
|
|
type PoiDetailReturnContext = Readonly<{
|
|
floorId: string
|
|
resetMode: 'floor-baseline'
|
|
requestId: number
|
|
}>
|
|
```
|
|
|
|
- Set the context before every guide-originated POI detail navigation, including search results, direct model/map POI selection, hall detail, exhibit detail, facility detail, and related-explanation actions.
|
|
- Cancel the context when `navigateTo` fails or the target cannot be resolved/opened.
|
|
- Consume it once in the guide homepage `onShow`, clear it immediately, and then reset to that POI's floor baseline.
|
|
- Do not set it for explain-home, deep-link, or other non-guide entry paths to the same detail pages.
|
|
- Keep top close, custom back, browser/system back, and other successful detail exits on the normal page-stack return path. Do not make detail pages mutate `ThreeMap` internals.
|
|
- Preserve the first normal homepage entry as overview. Never treat initial `onShow` as a detail return.
|
|
- Audit all navigation call sites, not only `facility/detail`. Search for `navigateTo`, hall/exhibit/facility detail URLs, map `poiClick`, and related-explanation actions.
|
|
|
|
## Async Invalidation
|
|
|
|
- Give floor loads, model commits, POI loads, focus requests, camera animations, and queued resets a comparable request ID, generation, epoch, or abort signal.
|
|
- Increment generation before reset cleanup. Check it before every async commit that mutates floor, selection, focus, marker, or camera state.
|
|
- Allow only the newest POI/floor request to commit. A completed old cross-floor request must not overwrite a later selection or reset.
|
|
- Invalidate preloads separately when necessary, but never let a preload commit become active business state after reset.
|
|
- Treat stale-request completion as a no-op, not as a user-visible load failure.
|
|
|
|
## Prohibited Reset Mechanisms
|
|
|
|
- Do not use `window.location.reload()`, `location.href`, or equivalent page reloads.
|
|
- Do not use `uni.reLaunch()` to reopen the current guide homepage.
|
|
- Do not change a component key to remount `GuideMapShell` or `ThreeMap`.
|
|
- Do not destroy and recreate `ThreeMap`, `WebGLRenderer`, controls, or scene solely to reset business state.
|
|
- Do not redownload or reparse an already valid cached GLB/model package.
|
|
- Do not add floor-, category-, type-, or POI-ID-specific reset branches.
|
|
|
|
## Required Tests And Audit Checks
|
|
|
|
- Cover search-result and direct map/model POI entry paths for facilities, halls, exhibits, and temporary focus markers.
|
|
- Cover same-floor and cross-floor targets, focus animation in progress, floor load in progress, repeated close/onShow, detail-open failure, model-not-ready, and model-error states.
|
|
- Assert after return that shared business state matches the target baseline contract, selection/highlight/focus are empty, `visiblePoiIds` is `null`, and search is collapsed.
|
|
- Assert camera position, controls target, direction, and distance match the appropriate overview/floor baseline within epsilon.
|
|
- Assert an old cross-floor focus/load request cannot commit after reset.
|
|
- Assert `ThreeMap` mount count, WebGL initialization count, model-package fetch count, and cached GLB parse count do not increase on detail return.
|
|
- Assert non-guide detail entry does not reset the guide model.
|
|
- Browser-test at least three POI types on different floors and verify identical same-floor reset composition, no white flash, no URL/load-time reset, and no duplicate GLB network request.
|