Spatial Narrative is a location-aware interactive fiction system built on SugarCube 2. Passages unlock by physical proximity, shift their text by compass heading, and evolve over dwell time. The whole story lives in a single .twee file. A browser-based authoring tool lets you place and edit geo nodes on a live map and push directly to GitHub. The reader is a compiled SugarCube story. The authoring tool is a standalone HTML file — no build step, no server.
The current story is set in Halifax: ferry terminal, clock tower, the waterline, Citadel, Grand Parade, Commons, Harbourfront — fifteen geo nodes active as of July 2026, some with directional variants and stage-two passages that activate after dwell time has elapsed. The system is designed for site-specific narrative work: the reader walks to a location, stays there, and the text arrives.
The system runs entirely in the browser. GPS and compass data come from the device’s native APIs (navigator.geolocation, DeviceOrientationEvent). A one-second heartbeat loop continuously checks position, heading, candidate proximity, and dwell time, then updates the DOM directly. No SugarCube passage navigation happens during active play.
| Layer | What controls it |
|---|---|
| Active passage | The geo node whose radius the reader has dwelled inside long enough (default 12 seconds) |
| Displayed passage | The active passage, its @then stage-two variant, or a @dir directional variant based on compass heading |
| Compass | Points toward all geo nodes linked from the active passage (or from Start in browse mode) |
| Browse mode | Before GPS starts: compass lists all nodes linked from Start with coordinates and radius |
Every geo-tagged passage starts with @ directives before its prose body. Directional and stage-two passages inherit their parent’s location context and don’t need a @geo directive. The author writes plain prose — no SugarCube macros needed.
| Directive | Description |
|---|---|
| @geo lat,lng,r | Geographic anchor. r = trigger radius in metres. |
| @lede text | Short italic subtitle rendered above the body. |
| @dwell ms | Milliseconds the reader must remain inside the radius before the passage activates. Default: 12000. |
| @facing deg | Override the global heading threshold for this passage. |
| @after ms | Milliseconds after activation before switching to the @then passage. |
| @then Name | Second-stage passage displayed once @after elapses. |
| @image file | Image filename from media/. Shown below body text. |
| @audio file | Audio filename from media/. Rendered as native audio controls. |
| @dir S-E:Name | If heading is in the arc S°→E°, display Name instead of the base passage. |
The authoring tool at spatial-narrative/author is a standalone browser app. Paste a GitHub token, load the live story/main.twee file, place or drag markers on the map, edit passages in a form-based editor, and push changes directly to GitHub. A Raw tab shows the generated .twee block for the selected passage. It can be installed as a PWA on iOS for field use.
| Passage | Location |
|---|---|
| FerryTerminal | 44.6488, -63.5752 — 4 directional variants + late stage |
| ClockTower | 44.6476, -63.5728 — north directional variant |
| Waterline | 44.6464, -63.5699 |
| Resolutes Club | 44.6357, -63.5721 — late stage + east variant; links to Palula |
| Irving | 44.6353, -63.5710 |
| citadel1 | 44.6470, -63.5782 |
| radstorm | 44.6529, -63.5847 — tight facing threshold (25°) + north variant |
| G8 cluster (6 nodes) | World Trade Centre, Grand Parade, Commons, Harbourfront, Citadel Lookout, Route Point |
| Palula | 44.6361, -63.5721 — linked from Resolutes Club |