Skip to main content

AD-0003: Map Markers as Presentation Layer

Status

Accepted (2026-05-13).

Context

Wave-brief language for the Valenar strategic map referred to "markers" — 2D icons drawn on the map to indicate Features, Sites, Threats, clues, camp candidates, water sources, and similar player-relevant rows. Read in isolation, the term "marker" could imply a new gameplay entity type, parallel to the committed map content taxonomy of Location / Feature / Site / Threat documented in examples/valenar/docs/systems/gd-locations-features-sites.md.

Two interpretations were possible:

  • Marker as gameplay entity — a new SECS template or scope row backing each marker, with its own generation contract, ownership rules, and lifecycle.
  • Marker as presentation layer — a client-side visual derived from the existing Location / Feature / Site / Threat / clue / activity data, with no new server-side row.

The first option would have required a marker template family, a marker generation contract, a marker scope edge, and a place in the SECS engine's template registration flow. The second option requires only a client-side derivation module.

Decision

Markers are a presentation layer over the existing committed map content taxonomy. They are not a new gameplay entity type.

Specifically:

  • No new SECS template, channel, modifier, system, event, contract, scope, activity, on_action, or policy is introduced to back markers.
  • No new server-side row, snapshot field, or generation contract is introduced for markers.
  • The committed map content taxonomy — Location, Feature, Site, Threat plus the clue / lead / objective rows — remains the source of truth for "what exists on the map".
  • Marker visibility, positioning, zoom aggregation, and priority ordering are client-side derivations from those rows, implemented in examples/valenar/Client/src/components/map/markerPresentation.ts.

The marker taxonomy and presentation rules are documented in examples/valenar/docs/systems/gd-map-markers.md.

Consequences

  • Marker positioning uses client-side deterministic offsets from (featureId, locationId) via FNV-1a-32, mapped to an angle and radius inside the Location polygon, with pointInPolygon verification and a centroid fallback. Authored offsets per row are the long-term answer; the hash derivation is the bridge until that data ships.
  • Discovery state gates marker visibility per the same knowledge-state rules that gate every other Location surface. Unknown content does not get a marker.
  • The Wave C implementation is the canonical reference: markerPresentation.ts for derivation, MapCanvas.tsx for the far / mid / close zoom draw passes, useMapPointerInteraction.ts for hover and click routing.
  • Introducing a new server data type to back markers — for example, a MapMarker template or a server-pushed marker snapshot — requires a new ADR that supersedes this one. The presentation-layer rule is the default and is not loosened silently.
  • The marker examples used in gd-map-markers.md (water sound, animal tracks, ruin entrance, danger den, camp candidate, smoke trace, clue or lead marker, Old Stones marker) are presentation examples only. They are not committed game canon and must not be added to gd-canon.md or gd-glossary.md as a side effect of this ADR.

Alternatives Considered

  • Introduce a Marker entity in SECS. Rejected. A marker would duplicate the semantics of the row it represents — a Feature marker is just the Feature, a Site marker is just the Site. Promoting the marker to its own entity would require duplicate generation rules, duplicate ownership rules, duplicate discovery-state rules, and a new modding contract. None of that buys gameplay leverage the existing rows do not already provide.
  • Generate marker rows from server systems. Rejected for the same reasons. The server already knows about every Feature, Site, Threat, and clue at a Location; an additional marker-generation pass would be redundant and would force the engine to express "what an icon looks like" as authoritative gameplay state.
  • Render markers via SVG over the canvas instead of canvas draw passes. Out of scope for this ADR. Implementation choice; the presentation-layer rule applies regardless of renderer.

References

  • examples/valenar/docs/systems/gd-map-markers.md — marker taxonomy, positioning, zoom aggregation, priority order, and design rules.
  • examples/valenar/docs/systems/gd-locations-features-sites.md — committed Location / Feature / Site / Threat content taxonomy.
  • examples/valenar/docs/ux/gd-shell-screen-model.md — map interaction contract and overlay layering.
  • examples/valenar/Client/src/components/map/markerPresentation.ts — client-side derivation.
  • examples/valenar/Client/src/components/map/useMapPointerInteraction.ts — pointer routing.
  • examples/valenar/Client/src/components/MapCanvas.tsx — far / mid / close zoom draw passes.