Skip to main content

Map Markers

This page owns the marker presentation taxonomy for Valenar's strategic map. Markers are presentation-layer visualizations over existing server data. They are not a new gameplay entity type, not a new SECS channel, not a new SECS template, and not a new server-side row. The architectural decision behind this rule is recorded in ad-0003-map-marker-presentation-layer.md.

Role

A marker is a 2D UI icon anchored to a position inside a Location polygon on the strategic map. Markers exist to surface the underlying gameplay rows the player has already earned — a Feature, a Site, a Threat, a clue or lead, an available activity hint — at a glance, without the player having to open a panel.

Markers are not entities. They have no template, no channel, no scope edge, no contract, and no SECS source. They are derived presentation; their lifecycle is bound to the lifecycle of the row that produced them. A marker exists because a Feature exists, not because the marker layer says it does.

Source Data

Marker rows are derived from existing server-provided data:

  • MapFeature — terrain feature, notable sign, generated content visible at this Location.
  • Site rows — discovered or enterable Sites at the Location.
  • Threat rows — pressure or hostile presence attached to the Location or to Features and Sites inside it.
  • Clue, lead, and objective rows — narrative or planning rows that have a spatial anchor at this Location.
  • Activity availability — when an activity is available at the Location and the activity is significant enough to deserve a glanceable marker (e.g. a camp candidate hint, a water-source hint, a known-good shelter hint).

The marker layer does not invent server content. If the row is unknown to the player (no clue, no scouted Feature, no surveyed Site), no marker is drawn. Discovery state gates marker visibility per the same knowledge-state rules that gate every other Location surface.

Local Positioning

Locations are polygon containers, not point objects. A marker has a position inside the Location's polygon, not a position equal to the Location's centroid.

Authored offsets per Feature, Site, or Threat row are the long-term answer. Until that data ships, the client derives a deterministic offset from the row identity:

  1. Hash (featureId, locationId) with FNV-1a-32.
  2. Map the hash to an angle (0..2π) and a radius (0..1) inside the unit disk.
  3. Project the offset to the Location polygon's local frame as centroid + R * r * (cos θ, sin θ) where R is the Location's effective radius.
  4. Verify the candidate point lies inside the polygon via pointInPolygon.
  5. If the candidate falls outside the polygon, fall back to the centroid.

The hash is deterministic, so the same row always sits at the same offset across reloads and across clients. The fallback is a hard fallback to the centroid, not silent point clamping that pretends the polygon is rectangular. Bbox-quad approximations of polygon outlines are forbidden.

Zoom Aggregation

The marker layer renders three zoom passes:

  • far — clustered summary. Multiple markers at a Location collapse into a single cluster glyph with a count badge. The cluster expresses "this Location has interesting content" without claiming any specific row.
  • mid — stacked group with a count badge. Distinct source kinds (Feature, Site, Threat, clue) stack visually so the player can tell at a glance that the Location has, for example, two known Sites plus a Threat.
  • close — individual markers drawn at their local offsets inside the polygon. Each marker is independently hover-targetable and click-targetable.

The zoom thresholds belong to the client renderer. The taxonomy guarantees that every marker resolves to the same underlying row in every zoom level — clusters are visual aggregates, not separate rows.

Priority Ordering

When zoom or screen space forces a marker selection, the priority order is:

  1. critical danger
  2. objective
  3. camp or shelter
  4. water
  5. major Feature or Site
  6. clue or lead
  7. resources
  8. minor traces

Higher-priority markers occlude lower-priority ones at the same offset. The order is a presentation rule; it does not change the underlying row data.

Hover and Click Behavior

Marker pointer behavior is part of the canonical gd-shell-screen-model.md § Map Interaction Contract:

  • Hover on a marker — opens a marker-scoped tooltip via the existing data-tip-id tooltip engine. The tooltip identifies the marker's underlying Feature, Site, Threat, clue, or activity hint. The tooltip is read-only.
  • Click on a cluster marker — selects the owning Location. Clusters render at the Location centroid (mid zoom) or as cluster summaries (far zoom); clicking either resolves through the same point-in-polygon path as a direct Location click and inherits the Location's selection behavior. The cluster's underlying Feature, Site, Threat, clue, and activity-hint rows are surfaced through the LocationContextPanel on right-click and through the Location's Wide and Full panels. A dedicated cluster tray is not shipped in this slice; a future wave may add one if marker density grows large enough that the LocationContextPanel becomes cluttered.
  • Click on an individual marker — surfaces marker-scoped quick activities: Inspect, Open Feature or Site dossier, Add to queue, Pin.

The marker layer never bypasses the canonical activity surface. Marker-scoped quick activities route through the same enqueue path (enqueueScheduledActivity, enqueueTravel, or useOverlayStore.open) as any other activity entry point.

Design Rules

  • Markers are derived presentation. The marker layer must not introduce a new server-side entity type, channel, scope edge, contract, or .secs source row to back a marker.
  • Discovery state gates marker visibility. Unknown content does not get a marker; partial knowledge gets a partial-knowledge marker.
  • Marker positioning is deterministic per (rowId, locationId). Random per-session offsets are forbidden because they break player spatial memory.
  • The hash-derived fallback offset is a fallback for the period before authored offsets ship, not a substitute for them.
  • Markers stay generic to source kind. No per-marker bespoke art commitments; the renderer picks an icon family per source row type, not per individual row.
  • Marker examples used in this document (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, not committed lore, and not committed gd-canon.md or gd-glossary.md entries.

Implementation Reference

The Wave C client implementation lives in examples/valenar/Client/src/components/map/markerPresentation.ts. That module exposes the LocationMarker shape, the FNV-1a-32 deterministic offset derivation, the pointInPolygon verification step, the markerZoomLevel helper for the three zoom passes, and the eight-tier priority taxonomy. The canvas draw passes in MapCanvas.tsx consume that data for the far / mid / close zoom passes.