feat: Update SceneModule to manage camera state and viewport, refactor WebGL layer to utilize Scene methods

This commit is contained in:
Azgaar 2026-03-13 02:39:40 +01:00
parent 42557881bb
commit 52708e50c5
10 changed files with 128 additions and 26 deletions

View file

@ -50,12 +50,15 @@ so that split layer surfaces can share resources without depending on one map SV
- Keep the runtime compatible with the current global-variable model. New TypeScript code must use ambient globals directly, not `window` or `globalThis` wrappers.
- New TypeScript modules must follow the project Global Module Pattern: declare global, implement a class, then assign `window.ModuleName = new ModuleClass()`.
- Avoid grouped SVG buckets or speculative abstractions here. The goal is bootstrap ownership only.
- Keep the implementation lean. Do not expand this story into a broad runtime framework, compatibility bridge, or camera API beyond the host ownership needed for Story 1.1.
- Prefer direct code over wrappers. Do not add helpers, comments, or indirection unless at least two concrete call sites need them.
### Architecture Compliance
- This story is the Phase 1 foundation from the layered-map architecture: create one scene container, one defs host, and stable references before any layer split begins.
- `svg` and `viewbox` remain compatibility-era globals after this story. They must stop being the architectural source of truth, but they are not removed yet.
- The runtime defs host must live outside individual layer surfaces so later split SVG shells can reference shared resources by stable ID.
- Keep ownership narrow: this story covers bootstrap ownership only. Do not fold in layer registry, compatibility lookups, export behavior, or transform semantics.
### Project Structure Notes
@ -73,7 +76,8 @@ so that split layer surfaces can share resources without depending on one map SV
- The architecture document explicitly defers formal test work for this tranche.
- Do manual verification for fresh load, saved-map load, and relief visibility.
- If a pure helper is extracted while implementing bootstrap ownership, keep it testable, but do not expand scope into a new test suite in this story.
- Do not add Playwright coverage, browser harnesses, or new automated regression suites in this story.
- If a pure helper is extracted while implementing bootstrap ownership, keep it simple and locally testable later, but do not expand scope into a new test suite in this story.
### References

View file

@ -1,6 +1,6 @@
# Story 1.2: Add Scene Module for Shared Camera State
Status: ready-for-dev
Status: in-progress
<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
@ -17,18 +17,18 @@ so that all layer surfaces consume one authoritative transform contract.
## Tasks / Subtasks
- [ ] Create a narrow Scene runtime module.
- [ ] Expose shared camera and viewport getters derived from the authoritative globals.
- [ ] Expose scene-host references established in Story 1.1 through the same contract.
- [ ] Centralize transform ownership.
- [ ] Move reusable camera-bound calculations behind Scene methods instead of ad hoc DOM reads.
- [ ] Keep `scale`, `viewX`, `viewY`, `graphWidth`, and `graphHeight` as the underlying truth during migration.
- [ ] Update runtime consumers that already operate across surfaces.
- [ ] Rewire the current WebGL layer framework to consume the Scene contract instead of reading transform meaning from DOM structure.
- [ ] Ensure zoom and pan updates publish one consistent state for all registered surfaces.
- [ ] Keep compatibility intact.
- [ ] Preserve existing `viewbox` transform application while older code still depends on it.
- [ ] Do not break callers that still read the existing globals directly.
- [x] Create a narrow Scene runtime module.
- [x] Expose shared camera and viewport getters derived from the authoritative globals.
- [x] Expose scene-host references established in Story 1.1 through the same contract.
- [x] Centralize transform ownership.
- [x] Move reusable camera-bound calculations behind Scene methods instead of ad hoc DOM reads.
- [x] Keep `scale`, `viewX`, `viewY`, `graphWidth`, and `graphHeight` as the underlying truth during migration.
- [x] Update runtime consumers that already operate across surfaces.
- [x] Rewire the current WebGL layer framework to consume the Scene contract instead of reading transform meaning from DOM structure.
- [x] Ensure zoom and pan updates publish one consistent state for all registered surfaces.
- [x] Keep compatibility intact.
- [x] Preserve existing `viewbox` transform application while older code still depends on it.
- [x] Do not break callers that still read the existing globals directly.
- [ ] Perform manual smoke verification.
- [ ] Zoom and pan keep SVG and WebGL content aligned.
- [ ] Startup and resize continue to use the correct viewport bounds.
@ -47,12 +47,14 @@ so that all layer surfaces consume one authoritative transform contract.
- Use bare ambient globals declared in `src/types/global.ts`. Do not introduce `window.scale` or `globalThis.viewX` usage.
- Keep the abstraction narrow: Scene owns shared camera and viewport state, not layer ordering, defs ownership, or export assembly.
- Prefer pure helper methods for transform math so later stories can reuse them without DOM coupling.
- Keep the module terse. Do not let `Scene` accumulate bootstrap, compatibility, registry, or export responsibilities in this story.
### Architecture Compliance
- This story implements the architecture decision that transform ownership moves from `#viewbox` to scene state.
- `viewbox` remains a compatibility-era render target, not the source of truth.
- The Scene API should be sufficient for both SVG and WebGL consumers once split surfaces arrive.
- Developer productivity is architecture here: expose only the few scene methods current consumers actually need.
### Previous Story Intelligence
@ -75,6 +77,7 @@ so that all layer surfaces consume one authoritative transform contract.
- Formal automated test work is out of scope for this tranche.
- Keep transform calculation logic pure enough for later coverage.
- Manual verification should cover zoom, pan, resize, and relief alignment.
- Do not add Playwright coverage or new browser-driven tests in this story.
### Dependencies
@ -92,12 +95,21 @@ so that all layer surfaces consume one authoritative transform contract.
### Agent Model Used
TBD
GPT-5.4
### Debug Log References
### Completion Notes List
- Story context prepared on 2026-03-13.
- Scene now exposes shared camera, viewport, and compatibility transform access while reusing the stable scene-host references from Story 1.1.
- WebGL camera sync now consumes `Scene.getCameraBounds()` and legacy zoom handling routes `viewbox` transform application through `Scene.applyViewboxTransform()`.
- Automated tests were removed and no tests or Playwright checks were run per user instruction.
- Manual smoke verification remains pending before the story can move to review.
### File List
- public/main.js
- src/modules/scene.ts
- src/modules/webgl-layer.ts
- src/modules/scene.test.ts (removed)

View file

@ -48,6 +48,7 @@ so that visibility, order, and surface ownership are managed consistently instea
- Keep the public contract minimal. Do not add export metadata yet; that belongs to Epic 4.
- Store actual surface handles, not just selectors, so later stories can mount independent SVG shells and WebGL surfaces under one contract.
- Ensure reorder application is atomic from the user perspective. Avoid partial states where one surface has moved and another has not.
- Keep the registry boring. No factory layers, schema systems, or speculative metadata beyond `id`, `kind`, `order`, `visible`, and `surface`.
### Architecture Compliance
@ -77,6 +78,7 @@ so that visibility, order, and surface ownership are managed consistently instea
- Manual verification is sufficient for this tranche.
- Verify the existing sortable Layers UI still works and that no layer disappears from the visible stack after a reorder.
- Do not add Playwright coverage or new automated test infrastructure in this story.
### Dependencies

View file

@ -47,6 +47,7 @@ so that individual layers can be created, mounted, updated, and disposed without
- Avoid generic factories or strategy trees. One lifecycle owner with SVG and WebGL-capable implementations is enough for this phase.
- Do not force feature modules to pass renderer flags around. If two surface kinds need separate logic, isolate that inside the lifecycle owner.
- Preserve the current `WebGLLayer` canvas and shared context budget.
- Keep the API compact. Do not add lifecycle hooks or extension points that this migration does not use yet.
### Architecture Compliance
@ -75,6 +76,7 @@ so that individual layers can be created, mounted, updated, and disposed without
- Manual validation is sufficient.
- Focus on mount, redraw, hide/show, and cleanup behavior for relief because that is the current live mixed-render surface.
- Do not add Playwright coverage or new automated test harnesses in this story.
### Dependencies

View file

@ -48,6 +48,7 @@ so that existing workflows keep working while code migrates to the new scene and
- Return real layer surfaces or layer-local SVG roots where available. Do not fake a new canonical SVG document.
- `queryMap(selector)` should be controlled and predictable. It must not silently reintroduce global DOM coupling as a hidden permanent pattern.
- Preserve current IDs and selectors where possible so callers can migrate incrementally.
- Keep the bridge thin and temporary. Do not add convenience helpers beyond the three architecture-approved lookups.
### Architecture Compliance
@ -78,6 +79,7 @@ so that existing workflows keep working while code migrates to the new scene and
- Manual verification is sufficient.
- Validate save/export, labels/text paths, and at least one legacy selector-heavy workflow after the helpers are introduced.
- Do not add Playwright coverage or new automated regression suites in this story.
### Dependencies

View file

@ -52,6 +52,7 @@ so that split surfaces can keep using stable IDs for filters, masks, symbols, ma
- The dedicated defs host must be reachable by all layer surfaces after the map DOM is split.
- Prefer one focused defs owner module over scattered DOM writes.
- Avoid changing export behavior in this story beyond what is necessary to keep runtime resources consistent for later work.
- Keep defs ownership isolated. Do not use this story to introduce broader compatibility or export abstractions.
### Architecture Compliance
@ -83,6 +84,7 @@ so that split surfaces can keep using stable IDs for filters, masks, symbols, ma
- Manual validation is sufficient.
- Check at least one feature path mask, one text-path label case, one marker or symbol reference, and fogging/filter behavior.
- Do not add Playwright coverage or new automated browser tests in this story.
### Dependencies

View file

@ -42,7 +42,7 @@ story_location: /Users/azgaar/Fantasy-Map-Generator/_bmad-output/implementation-
development_status:
epic-1: in-progress
1-1-bootstrap-scene-container-and-defs-host: in-progress
1-2-add-scene-module-for-shared-camera-state: ready-for-dev
1-2-add-scene-module-for-shared-camera-state: in-progress
1-3-add-layers-registry-as-the-ordering-source-of-truth: ready-for-dev
1-4-add-layer-surface-lifecycle-ownership: ready-for-dev
1-5-add-compatibility-lookups-for-legacy-single-svg-callers: ready-for-dev