Context
Surfaced while adding the shared prefab tooltip in #217.
Observation
Both viewers now feed the same shared PrefabTooltipController, but they sit at different architectural levels:
- The 2D map is decomposed into many top-level handlers instantiated at the composition root (
src/index.ts): MapCanvasHandler, CursorHandler, MarkerHandler, PrefabHighlightHandler, PrefabTooltipHandler, and so on.
- The terrain viewer is a single self-contained component (
TerrainViewer) that builds its own sub-parts internally: TerrainViewerCameraController, buildMarkerSprites, buildPrefabBoxes, and the hover/tooltip sub-controller.
Because of this, the terrain viewer's tooltip feeder cannot be a peer of the 2D PrefabTooltipHandler. It needs TerrainViewer's live camera and boxes, so it is created inside TerrainViewer, not at the root. In this codebase "Handler" conventionally means a composition-root-wired, page-lifetime unit, so a "Handler" created inside TerrainViewer is a naming/level mismatch. The near-term fix in #217 just names each feeder per its level (a root PrefabTooltipHandler vs a TerrainViewerHoverController owned by TerrainViewer), which reflects the asymmetry rather than resolving it.
Why it matters
Any concern shared between the two viewers (the tooltip today; possibly hover highlight, selection, or markers tomorrow) hits the same seam: one side is a root handler, the other is buried inside a component. That makes truly symmetric wiring impossible and forces shared state (the tooltip DOM/controller) to be injected across two different levels.
Possible directions (large, deferred)
- Decompose
TerrainViewer into root-level handlers wired in index.ts (camera, markers, boxes, hover), the way the 2D map already is, so both viewers are "a bag of handlers".
- Or the opposite: wrap the 2D map into a single self-contained component (like
TerrainViewer) that owns its handlers internally, so both viewers are "one component".
Either is a broad restructuring of the composition root and was intentionally left out of #217.
Scope
Tracking only. #217 ships the near-term naming fix; this issue records the underlying asymmetry for a future decision.
Context
Surfaced while adding the shared prefab tooltip in #217.
Observation
Both viewers now feed the same shared
PrefabTooltipController, but they sit at different architectural levels:src/index.ts):MapCanvasHandler,CursorHandler,MarkerHandler,PrefabHighlightHandler,PrefabTooltipHandler, and so on.TerrainViewer) that builds its own sub-parts internally:TerrainViewerCameraController,buildMarkerSprites,buildPrefabBoxes, and the hover/tooltip sub-controller.Because of this, the terrain viewer's tooltip feeder cannot be a peer of the 2D
PrefabTooltipHandler. It needsTerrainViewer's live camera and boxes, so it is created insideTerrainViewer, not at the root. In this codebase "Handler" conventionally means a composition-root-wired, page-lifetime unit, so a "Handler" created insideTerrainVieweris a naming/level mismatch. The near-term fix in #217 just names each feeder per its level (a rootPrefabTooltipHandlervs aTerrainViewerHoverControllerowned byTerrainViewer), which reflects the asymmetry rather than resolving it.Why it matters
Any concern shared between the two viewers (the tooltip today; possibly hover highlight, selection, or markers tomorrow) hits the same seam: one side is a root handler, the other is buried inside a component. That makes truly symmetric wiring impossible and forces shared state (the tooltip DOM/controller) to be injected across two different levels.
Possible directions (large, deferred)
TerrainViewerinto root-level handlers wired inindex.ts(camera, markers, boxes, hover), the way the 2D map already is, so both viewers are "a bag of handlers".TerrainViewer) that owns its handlers internally, so both viewers are "one component".Either is a broad restructuring of the composition root and was intentionally left out of #217.
Scope
Tracking only. #217 ships the near-term naming fix; this issue records the underlying asymmetry for a future decision.