GeoGazette

Annotations

What gets drawn on the map. Four kinds, plus two optional blocks that add a callout or motion to any of them.

Annotations live in a root registry, so one can span several scenes or outlive the scene that introduced it. A scene shows them with annotation_ids, or an annotation can set its own at and until on the document timeline.

The four kinds

marker

A point. Drawn as a dot with a ring, so it stays visible over imagery that happens to share its colour.

- id: ann_tower_site
  kind: marker
  geometry: { type: Point, coordinates: [-122.3968, 37.7897] }
  label: "Salesforce Tower — 326 m"
  style: { color: "#F7FAFC" }

circle

A point plus radius_m — a real distance on the ground, not a number of pixels. An 800 m walking radius grows and shrinks as the camera moves, because 800 m does not change when you zoom.

- id: ann_walk_radius
  kind: circle
  geometry: { type: Point, coordinates: [-122.3969, 37.7896] }
  radius_m: 800
  label: "Ten minutes on foot"
  style:
    color: "#0F766E"
    fill_color: "#0F766E"
    fill_opacity: 0.1
    weight: 2

line

A LineString. Drawn with a dark casing beneath the colour so it survives a pale basemap, and lightly smoothed — a handful of coordinates drawn raw reads as a route planner’s polyline rather than a river or a current.

- id: ann_bus_ramp
  kind: line
  geometry:
    type: LineString
    coordinates:
      - [-122.3903, 37.7908]
      - [-122.3931, 37.7902]
      - [-122.3958, 37.7898]
  label: "Elevated bus ramp from the Bay Bridge"
  style: { color: "#B91C1C", weight: 3 }

polygon

A closed ring, filled and stroked. Same style fields as a circle.

Labels on a leader line

A leader block turns a label into a drafted callout: an arrow holding the subject, a line bending away from it, and the words sitting clear of the map. It goes on any annotation that has a label, so a circle or a line can have one too.

- id: ann_tower_site
  kind: marker
  geometry: { type: Point, coordinates: [-122.3968, 37.7897] }
  label: "Salesforce Tower — 326 m"
  leader:
    direction: north_east   # eight compass points
    length: 0.16            # fraction of the frame's shorter side
    elbow: true             # diagonal, then horizontal into the text
    arrow: true             # arrowhead at the subject

direction takes compass words rather than degrees, because an author thinks “up and to the right”. length is a fraction of the frame rather than metres or pixels — a leader is a graphic device, so in metres it would be absurd when the camera pulls back, and in pixels it would be wrong at 4K against 720p.

The elbow is what matters visually: diagonal out, then horizontal into the label, keeps the text baseline flat. The direction is advisory — a leader that would run off the edge of the frame is turned the other way, because the framing moves with the camera and changes with the export size.

leader is not yet in the published specification. It works today because a compliant parser preserves fields it does not recognise — see unknown field preservation. A renderer that has not heard of it still draws the label, just beside the geometry.

Motion along a line

An animate block draws the line in over time and sends particles down it. A still line says a route exists; an animated one says which way it runs and how fast, which for a current or a migration is most of the content.

- id: ann_gulf_stream
  kind: line
  geometry: { type: LineString, coordinates: [ ... ] }
  label: "Gulf Stream"
  style: { color: "#4FC3F7", weight: 4 }
  animate:
    direction: forward    # forward | reverse | both
    speed: 140            # pixels per second at 1080p
    reveal: 2.5           # seconds to draw the line in
    fade_out: 1
    particles: 26
    particle: arrow       # arrow | dot | none
    glow: true

Every field is optional and has a working default, so an author can ask for motion without describing it. Speed is quoted at 1080p, so it means the same thing on a phone and in a 4K export.

Motion is additive by design. The compiler always emits geostory.annotation.show before geostory.annotation.flow, so a renderer that ignores flow has already drawn a correct static line. The worst outcome of not understanding motion is a still picture, never an empty map.

See them working