Fantasy-Map-Generator/_bmad-output/implementation-artifacts/1-2-add-scene-module-for-shared-camera-state.md
Azgaar 125403b82f feat: Implement Story 1.6 - Move Shared Defs Resources to the Dedicated Host
- Added documentation for Story 1.6 outlining the requirements and acceptance criteria for migrating shared defs-backed resources to a dedicated host.
- Updated sprint status to reflect the readiness of Story 1.6 for development.
- Created epics document detailing the breakdown of the Fantasy-Map-Generator project, including functional and non-functional requirements.
- Added implementation readiness report assessing the current state of documentation and readiness for the project.
- Introduced end-to-end tests for scene bootstrap to ensure runtime hosts are created and reused correctly.
2026-03-13 00:22:23 +01:00

5.1 KiB

Story 1.2: Add Scene Module for Shared Camera State

Status: ready-for-dev

Story

As a map maintainer, I want a Scene module to own shared camera and viewport state, so that all layer surfaces consume one authoritative transform contract.

Acceptance Criteria

  1. Given shared globals such as scale, viewX, viewY, graphWidth, and graphHeight already exist, when the Scene module is introduced, then it exposes a single runtime contract for camera and viewport state, and existing global values remain authoritative and usable during migration.
  2. Given multiple surfaces will render the same map, when camera state changes, then the Scene module provides one consistent state source for all registered surfaces, and no feature code needs to read transforms from DOM structure directly.

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.
  • Perform manual smoke verification.
    • Zoom and pan keep SVG and WebGL content aligned.
    • Startup and resize continue to use the correct viewport bounds.

Dev Notes

Context Summary

  • public/main.js owns the current zoom flow: onZoom updates scale, viewX, and viewY, then handleZoom applies viewbox.attr("transform", ...) and triggers WebGLLayer.rerender().
  • src/modules/webgl-layer.ts already has syncTransform() logic that computes camera bounds from those globals. That logic is the best initial candidate to move behind a shared Scene contract instead of duplicating it elsewhere.
  • The architecture requires Scene to own shared transform meaning while keeping the global values authoritative. This story should centralize interpretation, not rename the underlying globals.

Technical Requirements

  • Implement the Scene module in src/ as a TypeScript global module and register it through src/modules/index.ts.
  • 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.

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.

Previous Story Intelligence

  • Story 1.1 should leave the runtime with stable scene-host and defs-host references. Reuse those references here instead of letting Scene rediscover DOM nodes on every call.
  • Do not fold bootstrap ownership and camera ownership into one large module. Story 1.1 is about host setup; this story is about transform semantics.

Project Structure Notes

  • Expected touch points:
    • src/modules/scene.ts
    • src/modules/index.ts
    • src/modules/webgl-layer.ts
    • public/main.js
    • src/types/global.ts
  • Keep any math helpers inside the Scene module unless there are multiple concrete callers that justify extraction.
  • Keep the scene contract in src/; legacy public/main.js should consume it, not own a second parallel source of truth.

Testing Notes

  • 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.

Dependencies

  • Build on the runtime references introduced in Story 1.1.

References

  • [Source: _bmad-output/planning-artifacts/epics.md, Epic 1, Story 1.2]
  • [Source: _bmad-output/planning-artifacts/architecture-layered-map-dom-split.md, Decision 3, Runtime Structure, Migration Plan]
  • [Source: docs/architecture-globals.md, scale, viewX, viewY, graphWidth, graphHeight globals]
  • [Source: public/main.js, zoom pipeline and handleZoom]
  • [Source: src/modules/webgl-layer.ts, syncTransform() and current camera ownership]

Dev Agent Record

Agent Model Used

TBD

Debug Log References

Completion Notes List

  • Story context prepared on 2026-03-13.

File List