Files
jpmschweitzerandClaude Opus 5 0817befcba docs(diagrams): SVG replaces PNG, and a map of the wiki generator flow
d2 emits SVG natively; its PNG path wants a ~150 MB headless-Chromium
download and prompts interactively, so every PNG here was produced by an
out-of-band magick step. There is no Chromium on this system. Dropping PNG
removes the dependency rather than trading one format for another, and cuts
docs/diagrams/ from 17 MB to 3.3 MB. SVG renders in Gitea and in clide
(`clide draw --file <path>`, which takes .d2 source directly), and diffs as
text.

One PNG is kept on purpose: design/star-map-concentric.png has no .d2 source.

Also renders the 7 star-map .d2 files for the first time. star-map-plan.md
listed their renders as a deliverable in March and the step never ran; the
new `make check-diagrams` is what surfaced it.

New: docs/diagrams/data-flow/wiki-generator-flow.d2 — which way the arrows
point for any file under wiki/. Every edge was read in the tool's own source
rather than inferred. It records the trap that keeps costing us: scaffold_bodies.py
writes a body page once and never overwrites it, and the generator then reads
that frontmatter directly — so a hand-edit there is not reverted, it is obeyed,
and silently changes world generation.

Two rendering traps found the expensive way and now written down:

- A d2 `|md` block becomes an SVG <foreignObject>. ImageMagick and flutter_svg
  both silently drop it, so the legend was in the file and invisible in every
  viewer except a browser. Plain labels render as real <text> everywhere.
- Container boxes fight the layout engine. Grouping nodes whose flow-depths
  differ forces long edge routes; this diagram went from an unreadable 2.4:1
  sprawl to a legible 0.75:1 by deleting five containers and changing nothing
  else. Colour classes carry the grouping instead.

make diagrams / make check-diagrams render and gate. Repo-specific rules in
.claude/rules/diagrams.md; d2 syntax and the traps live in the user-scope
d2-diagram skill, whose PNG default was flipped to SVG to match.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 01:49:19 +02:00

30 KiB
Raw Permalink Blame History

Star Map Generation — Plan

Status: Working plan — not yet a canonical decision record Created: 2026-03-13 Updated: 2026-03-13 (star naming section added) Author: Miri (worldbuilding) Precedes: star-map generation work, CSV population


What the star map is

The star map is the one deliverable from the systems framework that the CSV cannot encode. It is a graph: nodes are systems, edges are gate connections. Once it exists, the adjacent_systems transit graph database can be populated, earth_proximity hop-distances can be computed, and generation of the 300-system CSV can begin.

The map has two consumers:

  1. The simulation — needs a machine-readable edge list (source system ID, destination system ID, both aperture counts decremented accordingly)
  2. Content authors and the team — need a navigable visual reference that shows clusters, corridors, chokepoints, and the distribution of topology types

These two needs drive the split architecture described below.


On d2 for 300 nodes

d2 is the right tool for diagrams in this project. The existing examples (district-topology.d2, system-tiers.d2, etc.) are all well within d2's comfort zone — tens of nodes, carefully laid out.

300 nodes with hundreds of edges is a different problem. The honest assessment:

d2 will render 300 nodes. It will not produce a readable diagram. d2 uses automatic layout algorithms (ELK, dagre, or its own). At 300 nodes with a web topology — where many nodes have 24 connections and some hubs have 68 — the auto-layout will produce a hairball. The SVG or PNG output will be technically correct and visually useless. This is not a d2 limitation specifically; it is a property of automatic layout at this scale. Force-directed graph tools (Gephi, GraphViz neato, d3-force) have the same problem at 300 nodes unless significant hand-tuning is done.

The conclusion: d2 is not the right rendering tool for the full map. We use it for sector-level breakdowns where node counts are manageable (3060 nodes per sector map). The full map gets a different treatment.


Architecture: three representations

The star map lives in three forms, each serving a different purpose. They are all generated from one canonical source.

1. Canonical source: star-map.json

A single JSON file is the authoritative record of the graph. It contains:

  • A node array: one entry per system with system_id, system_name, geographic_sector, settlement_wave, gate_topology, and aperture_count
  • An edge array: undirected pairs [system_id_a, system_id_b], one entry per gate connection

Everything else — hop distances, earth_proximity values, gate_connections counts per node, the adjacent_systems transit database entries — is derived from this file by script. The JSON does not store derived data.

Why JSON over CSV edge list: The node array and edge array are structurally distinct. A CSV edge list forces either two files or a mixed format that conflates them. JSON keeps them separate while remaining human-readable and trivially parseable by Python.

Why not a graph database: Overkill. The graph is static for the purposes of generation. A database adds operational complexity without benefit at this stage. The transit graph database that the simulation uses is populated from this JSON, not replaced by it.

2. Sector maps: d2 diagrams (×6)

Six d2 files, one per geographic sector: star-map-core.d2, star-map-north-reach.d2, etc.

Each diagram contains:

  • All systems in that sector as labeled nodes, color-coded by settlement wave
  • All intra-sector gate connections as edges
  • Inter-sector connections shown as stubs: a node for the connected system in another sector, visually distinct (dashed border, dimmed), with a label indicating which sector it belongs to

This keeps each diagram to 3060 nodes — well within d2's readable range — while preserving the full connectivity picture. Cross-sector corridors are visible on both sides.

A seventh d2 file (star-map-overview.d2) shows sectors as large cluster nodes with inter-sector edge bundles labeled with connection counts. This gives a macro view of how the sectors relate without trying to render individual systems.

All d2 files are generated programmatically. No hand-writing of 300 node declarations.

3. The overview diagram

The star-map-overview.d2 is the map that lives in presentations and high-level references. Seven nodes (six sectors + Gateway as a special diplomatic_periphery node), edges between them labeled with the number of gate connections crossing that boundary, and the Gateway's special status called out explicitly.


Generation algorithm

Writing a realistic gate network by hand is not feasible at 300 nodes. But pure random generation produces garbage — too uniform, no chokepoints, no corridors, no narrative texture. The algorithm needs to be guided.

Phase 1: Sector seed placement

Divide the 300 systems among six sectors according to the framework's distribution guidance:

  • Core: ~25 systems (Wave 12 heavy)
  • Each of four cardinal sectors: ~4555 systems
  • Deep frontier: ~2530 systems

Within each sector, assign systems a rough positional weight: inner-band systems are closer to the core, outer-band systems are farther. This is used to guide connection probability, not to produce actual 2D coordinates — the map is a topology, not a spatial map.

Phase 2: Backbone construction (spanning tree)

Build a spanning tree across all 300 systems using a modified Prim's algorithm with the following weights:

  • Inner-band systems connect to other inner-band systems with high probability
  • Outer-band systems connect inward (toward the nearest already-connected system)
  • Sector crossings are allowed but weighted down — they should happen at specific chokepoint systems, not uniformly

This guarantees connectivity (the framework requirement: no stranded systems) while producing organic clustering. The spanning tree alone gives every system exactly one connection — the minimum for connectivity.

Phase 3: Augmentation passes

The spanning tree is the skeleton. Multiple augmentation passes add edges to produce realistic topology:

Pass A — Hub formation. For each system flagged as hub or junction topology, add connections until it reaches its target degree (48 for hubs, 34 for junctions). Hub systems are pre-seeded in high-traffic locations: the Gateway, core systems that will become institutional anchors, and 23 per cardinal sector.

Pass B — Loop formation. Select pairs of systems that are 35 hops apart in the current graph and share a sector. Add a direct connection between them. This creates the routing redundancy that makes some systems loop_member. Target: 1525 loops total across the full graph.

Pass C — Spur extension. Some outer-band and deep-frontier systems should be spurs: one inbound connection only. These are created by adding leaf nodes in Pass A that are not subsequently augmented. dead_end systems get one connection (the minimum from Phase 2) and no augmentation.

Pass D — Cross-sector bridges. Ensure each sector has 24 connections to neighboring sectors. These should run through the highest-degree systems on each side — that is what makes those systems chokepoints. Identify under-connected sector boundaries and add bridging edges.

Phase 4: Topology classification

After augmentation, classify each system by its final degree (connection count):

  • degree 1: dead_end
  • degree 2, no cycles: spur_end
  • degree 2, part of a loop: loop_member
  • degree 3: through_route (if on a clear path) or junction (if it branches)
  • degree 4+: junction or hub

Check the resulting distribution against the framework guidance. If hub count is too low or dead_end percentage is wrong, adjust augmentation weights and regenerate.

Phase 5: Aperture count assignment

Each system's aperture_count must be >= its gate_connections count (you cannot have more connections than apertures). The framework allows 18 apertures for systems that have a horizon station, and states ~75% of systems have stations.

Assignment rules:

  • Systems with no horizon station: aperture_count = 0, gate_connections = 0 (these are transit-dead; they exist but are unreachable by gate)
  • Systems with a station: aperture_count = max(gate_connections, 1) as a floor, then add 02 unused apertures for systems flagged as research_periphery or contested_activation (the unused apertures are narratively interesting)
  • Single-aperture stations with one connection: valid. One way in, one way out.

Phase 6: Validation

Run automated checks before accepting the graph:

  1. Connectivity: BFS from the Gateway system reaches all systems that have horizon stations. Systems without stations are documented as intentionally isolated.
  2. Aperture consistency: No system has gate_connections > aperture_count.
  3. Hub distribution: At least one hub per sector. No more than 15% of systems are hubs.
  4. Dead-end distribution: 2035% of systems are dead_end or spur_end. (The framework says dead-ends are "valid and interesting" — they should be common, not rare.)
  5. Gateway placement: The Gateway is in the core sector, diplomatic_periphery zone, and has 35 connections (enough to be a nexus, not so many it's trivially robust).
  6. earth_proximity derivability: BFS hop count from Gateway to every connected system should produce a plausible distribution: 1015 systems within 2 hops (immediate), 4060 within 10 hops (proximate), remainder at 1130 (distant) or 30+ (irrelevant).

The Gateway system

The Gateway system requires hand-crafting. It is the one system the algorithm cannot place procedurally because its position determines earth_proximity for the entire network.

Placement constraints:

  • Geographic sector: core
  • Political zone: diplomatic_periphery
  • Gate topology: junction or hub (35 connections)
  • One of its apertures is the Sol-facing connection (currently closed / restricted but physically present)
  • It should sit at a natural boundary of the core sector — close enough to institutional power to be politically significant, far enough to feel like a threshold

Narrative constraints:

  • The Gateway is the most surveilled system in the Reach. commission_presence: dominant, institute_presence: dominant
  • It is not a commerce hub. It is an institutional system. The people here are administrators, archivists, permit processors, and watchers.
  • Its silence_topic is the Sol-aperture permit process. Its silence_threshold is unreachable for most questions and investigation_depth for the narrowest ones.

Name: Needs to be decided. "Gateway" is a working descriptor, not a canonical name. Setting note: the system's canonical name should feel like something Wave 1 settlers would have named — they knew what they were building. It should carry weight without being on-the-nose. Candidates to be proposed in a separate discussion.


Implementation: the generation script

A Python script at tooling/generate-star-map.py will:

  1. Read a seed configuration file (tooling/star-map-seed.json) that specifies:

    • System count per sector
    • Pre-seeded hub locations (by index, before naming)
    • Gateway position
    • Target topology distribution percentages
    • Random seed for reproducibility
  2. Run the Phase 16 algorithm and produce:

    • docs/design/star-map.json — canonical edge/node data
    • docs/diagrams/design/star-map-core.d2
    • docs/diagrams/design/star-map-north-reach.d2
    • docs/diagrams/design/star-map-south-reach.d2
    • docs/diagrams/design/star-map-east-reach.d2
    • docs/diagrams/design/star-map-west-reach.d2
    • docs/diagrams/design/star-map-deep-frontier.d2
    • docs/diagrams/design/star-map-overview.d2
  3. Print a validation summary: node count, edge count, topology distribution, sector cross-connections, hop distances from Gateway.

The script should be deterministic given the same seed. If the topology needs adjustment, we change the seed or the configuration weights, not the output files directly. The output files are always regeneratable.

Script dependencies: Python standard library only. No networkx required — the graph operations needed (BFS, spanning tree, degree calculation) are simple enough to implement inline and keeping dependencies minimal means the script runs anywhere.


Star naming — the dual-identifier system

Every system has two identifiers. They serve different purposes and must both be present in star-map.json and the generated CSV.

The two fields

astronomical_id — The catalog designation. This is what astronomers would call the star: HD 10700, Gliese 667 C, HIP 113576, 2MASS J05540421-6001245. It is the star's "real" name in the setting's scientific and institutional record. The Veil Institute indexes systems by astronomical ID. Commission permits reference astronomical IDs. Old survey documents use them.

system_name — The common or friendly name. This is what people actually call the place. Some stars have well-known proper names from Earth's pre-settlement astronomy (Tau Ceti, Barnard's Star, Procyon) — those keep them. The rest were named by the settlers who founded them, drawing on their founding culture's naming traditions. This is the name that appears on transit boards, in casual conversation, and on the header of every system wiki page.

The framework's existing system_name column becomes system_name (unchanged) and is joined by a new astronomical_id column in Section I. The framework document needs a one-line amendment. See the framework change flag at the end of this section.

Star selection: 300 from ~2,500

The nearest ~2,500 stars to Sol are the realistic candidate pool at the game's implied technology level (horizon stations are found out to roughly 250300 light-years; no station has ever been found beyond that). From this pool, ~300 receive a horizon station.

Why only 300? The gate builders were selective. Their selection logic is unknown to humans in the setting — this is part of what makes the Veil Institute's research so difficult. The apparent selection criteria do not map cleanly onto habitability, stellar stability, or any other human-legible principle. Some dead systems have stations. Some garden worlds do not. This is not an error; it is a mystery, and it is the oldest silence in the Reach.

Human-observable distribution of gate-bearing stars (how it actually worked out):

The Veil Institute has catalogued correlations without being able to explain them. For our purposes, the 300 selected systems should feel like a slightly skewed sample of real stellar neighborhoods, not a clean filter:

  • M-type dwarfs (red dwarfs): ~4550% of gated systems — broadly proportional to their share of all nearby stars
  • K-type stars (orange dwarfs): ~2528% — modestly over-represented relative to pure frequency; K stars are common targets for human settlement anyway
  • G-type stars (Sun-like): ~1215% — roughly proportional
  • F-type (slightly hotter/larger): ~57%
  • Binary systems: ~1520% of gated systems are in binary or multiple-star systems; both stars may or may not have their own designation depending on which component hosts the station
  • Unusual / white dwarf / subdwarf: ~35% — the Veil Institute finds these disproportionately interesting, often as research_enclave_active sites

What this means for generation: The seed file should specify spectral type distribution targets. The procedural generator fills in star_type values consistent with these targets. The actual star catalog population (matching each S-NNN ID to a real or fabricated designation) is a content pass after topology is validated.

Sourcing: real stars first, fabricated second

Real stars to anchor the list — The nearest ~300 stars (within roughly 80 light-years) are well-documented in the HYG database (Hipparcos + Yale + Gliese catalog merge). We draw on these for our nearest-to-Sol systems. Stars with proper names keep those names. Stars known only by catalog designations get settler-given friendly names.

Well-known nearby stars with proper names that anchor the real-star pool:

  • Proxima Centauri (4.2 ly, M5Ve) — HIP 70890
  • Alpha Centauri A / Rigil Kentaurus (4.4 ly, G2V) — HD 128620, HIP 71683
  • Alpha Centauri B (4.4 ly, K1V) — HD 128621, HIP 71681
  • Barnard's Star (5.9 ly, M4Ve) — HIP 87937, GJ 699
  • Sirius (8.6 ly, A1V) — HD 48915, HIP 32349
  • Epsilon Eridani (10.5 ly, K2V) — HD 22049, HIP 16537
  • Tau Ceti (11.9 ly, G8V) — HD 10700, HIP 8102, GJ 71
  • Procyon (11.4 ly, F5V) — HD 61421, HIP 37279
  • 61 Cygni A/B (11.4 ly, K5V/K7V) — HD 201091/201092, HIP 104214/104217
  • Epsilon Indi (11.8 ly, K5Ve) — HD 209100, HIP 108870
  • Lalande 21185 (8.3 ly, M2V) — HIP 54035, GJ 411
  • Ross 128 (10.9 ly, M4.5V) — HIP 57548, GJ 447
  • Lacaille 9352 (10.7 ly, M2V) — HIP 114046, GJ 887
  • Groombridge 1618 (15.9 ly, K7V) — HD 36395, HIP 26335
  • 70 Ophiuchi A/B (16.6 ly, K1V/K5V) — HD 165341, HIP 88601
  • Sigma Draconis / Alsafi (18.8 ly, G9V) — HD 185144, HIP 96100
  • Eta Cassiopeiae / Achird (24.6 ly, G0V) — HD 4614, HIP 3821
  • Gliese 570 / 33 G. Librae (19.2 ly, K4V) — HD 131977, HIP 73184
  • 82 Eridani (19.8 ly, G8V) — HD 20794, HIP 15510
  • Gliese 667 C (22.7 ly, M2V) — GJ 667C, part of HD 156384 system
  • Beta Hydri (24.4 ly, G2IV) — HD 2151, HIP 2021
  • Fomalhaut (25.1 ly, A3V) — HD 216956, HIP 113368
  • Vega (25.3 ly, A0V) — HD 172167, HIP 91262
  • Gliese 250 (28.4 ly, K3V/M2.5) — HD 50281, HIP 33226
  • 61 Virginis (27.8 ly, G5V) — HD 115617, HIP 64924
  • Pi3 Orionis / Tabit (26.2 ly, F6V) — HD 30652, HIP 22449
  • Chara / Beta CVn (27.4 ly, G0V) — HD 109358, HIP 61317
  • Delta Pavonis (19.9 ly, G8IV) — HD 190248, HIP 99240
  • Omicron2 Eridani (16.4 ly, K1Ve + DA4 + M4.5Ve) — HD 26965, HIP 19849
  • HR 1614 (28.4 ly, K3V) — HD 32147, HIP 23311
  • 107 Piscium (24.4 ly, K1V) — HD 10476, HIP 7981
  • Groombridge 1830 (29.9 ly, G8Vp) — HD 103095, HIP 57939
  • Kappa1 Ceti (29.8 ly, G5V) — HD 20630, HIP 15457
  • Mu Cassiopeiae / Marfak (24.6 ly, G5VIp) — HD 6582, HIP 5336
  • HD 40307 (42.0 ly, K2.5V) — HIP 27887, GJ 2046
  • Altair (16.8 ly, A7V) — HD 187642, HIP 97649

Beyond this core of well-known stars, the real catalog runs out of familiar proper names quickly. Most stars in the 30100+ light-year range are known only by catalog designations (HD numbers, HIP numbers, Gliese numbers). These are the stars that get settler-given names.

Fabricated stars (systems beyond the well-mapped region) — For systems beyond ~100 light-years, or for systems where a real star was not assigned, we fabricate plausible catalog designations. The fabrication rules:

  1. Use mixed catalogs. Real catalogs don't all use the same numbering system. Our fabricated entries should mix: some HD, some HIP, some GJ (Gliese-Jahreiss), some 2MASS.

  2. Do not use neat sequential numbering. Real catalog numbers have gaps, inconsistencies, and historical accidents. HD numbers jump around. HIP numbers don't correlate with distance or brightness in a simple way. Our fabricated numbers should look like they were generated by different survey campaigns at different times.

  3. HD number range: HD catalog goes up to ~225,000. For fabricated HD designations, use numbers in the ranges that suggest less well-known stars: HD 70000HD 180000, with scattered gaps. Avoid HD 1HD 10000 (too bright, too famous).

  4. HIP number range: HIP catalog has ~118,000 entries. Fabricated HIP numbers should fall in ranges not covered by well-known stars. Use: HIP 12000HIP 118000, with realistic gaps.

  5. GJ number range: Gliese-Jahreiss catalog. GJ numbers go up to ~4500. GJ 3NNN designations (GJ 3001GJ 3999) are a supplementary list of less well-characterized stars — good for fabrication. Also GJ 4NNN (GJ 4000+).

  6. 2MASS designations: Format is 2MASS J followed by RA/Dec encoded coordinates: 2MASS JHHMMSS.SS±DDMMSS.S. Use these sparingly — they feel like stars discovered late, not well-characterized. Good for deep-frontier systems or recently activated horizon stations.

Examples of plausible fabricated designations:

  • HD 127643 (a G-type star in a not-too-famous range)
  • HIP 44891 (Hipparcos entry in a mid-range)
  • GJ 3471 (Gliese supplementary catalog)
  • GJ 4012 (later Gliese-Jahreiss entry)
  • 2MASS J14182612-3104543 (deep survey coordinates)
  • HD 98711 (another Henry Draper mid-range entry)

Friendly naming conventions by founding culture

When a star has no established proper name, the settlers who founded the system gave it one. Naming happened at first permanent settlement — the name in use today reflects the Wave and culture that planted the flag first.

This is not about assigning names to real stars (which have their own proper names if they have any). It is about naming the catalog-only stars that make up the majority of the 300-system pool.

Naming conventions by founding culture type:

founding_culture_primary Naming register Examples
nordic_diaspora Old Norse place-names, kennings, and mythological geography. Short, consonant-heavy. Often evocative of landscape or weather. Skarveld, Grenvann, Hvitholm, Dagnfjord, Kolsheim
east_asian_diaspora Classical Chinese or Japanese characters transliterated, place-names evoking natural features (mountain, water, light). Lintian, Suiyuan, Akishima, Torashima, Xianmen
south_asian_diaspora Sanskrit-derived, often astronomical or mythological terms. Two or three syllables. Taraval, Suryavat, Indravaan, Nalvara, Dharket
iberian_diaspora Spanish or Portuguese place-name conventions: saints' names reduced to nickname, geographic descriptors, colonial-era cadence. Novo Terceira, Corteval, Riomar, Aguada, Belverde
west_african_diaspora Pan-African place-name blend: Yoruba, Akan, Swahili, Wolof roots. Often meaning-bearing (strength, river, dawn, iron). Odufemi, Kwavela, Salimani, Iroko, Sembele
administrative_charter Committee-named: tends toward Roman-style designations, Latinate compound words, or founding-figure surnames. Feels official. Vestius, Caldaren, Harmon's Point, Nova Meria, Tertios
syndic_company Named by a company or combine: often a founder's name, a commodity reference, or a commercial-era place-name. Aldren Station, Cortex Prime, Havelock, Miren Reach, Cadrex
religious_refugee Named after scripture, martyrs, sacred geography, or doctrinal concepts. Tends toward the weighty and aspirational. Covenant's Rest, Thresh, Navarethis, Solara, Kereneth
separatist_charter Named to signal independence: often an Abstract virtue, a deliberate break from Earth-heritage naming, sometimes a founder-name with political resonance. Autonoma, Clearwater, Vanthis, Aldgate, New Resolve
academic_scientific Named after scientists, mathematicians, philosophical concepts, or methodological terms. Veritas, Hawking's Claim, Curien, Bayes Point, Lamarck
military_frontier Named after military terms, commanders, engagements, or fortification concepts. Rampart, Vorfeld, Callister's Landing, Thornwall, Basset
asteroid_mining Named after ore deposits, geological terms, survey designations, or mining company shorthand. Ferric Station, Vein-3, Gravel Point, Cressite, Marl
agricultural_breadbasket Named after crops, seasons, harvests, or pastoral landscapes from the home culture. Harvestholm, Granero, Sumai Plains, Kettlebrook, Ashfallow
penal_exile Named by the authority that established it, often with numbering or administrative designations. May have been renamed by survivors. Colony Seven, Redemption, Strandvik, Auger's Station, Penitent
refugee_wave Named for what was lost, where they came from, or an expression of the displacement. Often carries grief. New Calais, Remnant, Dusk Harbor, Careva, Farland
speculative_venture Named by an investor syndicate: often hopeful, commercial-sounding, or bearing a founder's name. Goldcrest, Brightwater, Primus Holding, Vansen, Aldine

Multi-culture systems: When founding_culture_secondary is set, the system name may blend conventions or use the dominant culture's convention with a secondary-culture flavor in the names of major settlements within the system.

The naming pass in practice

The generation script assigns placeholder IDs (S-001 through S-300, sequenced by wave and sector). After topology is validated, a naming pass runs:

  1. Sort systems by distance band. The innermost systems (nearest to Sol) get real-star astronomical IDs from the catalog pool above. Farther systems get fabricated IDs.

  2. Assign proper names first. Any system whose real star has a proper name (Tau Ceti, Barnard's Star, etc.) takes that name as its system_name. Overrides founding-culture naming.

  3. Apply founding-culture naming to the remainder. The content author or generation script draws from the culture's naming register to produce a system_name for each catalog-only star. These should feel like real place-names, not made-up sci-fi words — the naming register above is the constraint.

  4. The Gateway system and Van Maanen's Star receive their canonical names before the CSV phase, as they anchor everything else. (Gateway name still pending team decision.)

Framework change flag

The framework document (docs/design/systems-framework.md) currently has one field in Section I — Identity and Location — where this change lands:

Existing:

| `system_name` | string | free text | (C)(G) | Name derived from founding culture naming conventions. |

Proposed amendment (do not make yet — flag only):

| `astronomical_id` | string | catalog designation | (C) | Primary catalog identifier: HD, HIP, GJ, or 2MASS designation. Real where available; fabricated per spec for systems beyond the well-mapped region. |
| `system_name` | string | free text | (C)(G) | Common or friendly name. Proper name where star has one; settler-given per founding culture naming conventions otherwise. |

This adds one column to Section I (67 total, not 66). The column count summary in the framework doc needs updating. astronomical_id is (C) only — it is a content-author reference and worldbuilding anchor, not a runtime input to the simulation. The simulation addresses systems by system_id.


What comes after the map

Once star-map.json is validated:

  1. Populate adjacent_systems in the transit graph database from the edge list
  2. Run BFS from Gateway to populate earth_proximity for all 300 systems
  3. Verify gate_connections per node matches the framework's stored column values
  4. Begin CSV population — the map provides the topology columns; everything else is the content generation phase

The galactic history wiki is a parallel deliverable (not dependent on the map) and can proceed concurrently.


d2 style conventions for sector maps

Consistent with existing project d2 conventions (dark background, #1a1e24 base, #c8d0e0 text):

  • Node color by settlement wave:
    • Wave 1: bright institutional blue (#3060c0)
    • Wave 2: commercial amber (#b8a020)
    • Wave 3: working grey-green (#3a8a50)
    • Wave 4: frontier orange (#c86010)
    • Wave 5: activation edge red (#c02020)
    • Unsettled: dim neutral (#4a5060)
  • Node shape by topology:
    • hub: hexagon
    • junction: diamond
    • dead_end / spur_end: rectangle (default)
    • loop_member / through_route: oval
  • Cross-sector stub nodes: dashed border, dimmed fill, labeled with [sector]
  • Gateway: distinct visual treatment — double border or highlight stroke, labeled explicitly

Open decisions before work begins

  1. Gateway system name — needs team discussion before the map is authored. Blocking for the hand-crafted node.
  2. Target topology distribution — the framework says "hub, junction, through_route, loop_member, spur_end, dead_end" are all valid. It does not give percentages. Before running the generation script, we need a target distribution to validate against. Proposed defaults:
    • dead_end: 20%
    • spur_end: 15%
    • through_route: 25%
    • loop_member: 15%
    • junction: 18%
    • hub: 7% These are parameters in star-map-seed.json, not hard-coded. They can be adjusted after reviewing the first generated map.
  3. Cultural corridors — the framework reserves cultural_corridor as a column. Corridors follow gate paths. The map generation script can flag obvious corridor candidates (chains of systems with similar founding cultures that are gate-connected), but corridor canonization is a content-author decision, not an algorithm output.
  4. Framework amendment approval — the dual-identifier system requires adding astronomical_id to Section I of the framework doc (67 columns total, up from 66). This needs lead sign-off before the framework doc is modified. The amendment is flagged in the naming section above and is low-impact: it adds one (C)-only column that does not affect any runtime system. Pending team review.

Summary of deliverables

Deliverable Format Author When
tooling/generate-star-map.py Python script Miri (or assigned) Before map generation
tooling/star-map-seed.json JSON config Miri Before map generation
docs/design/star-map.json JSON graph Generated Output of script
docs/diagrams/design/star-map-*.d2 (×7) d2 source Generated Output of script
docs/diagrams/design/star-map-*.svg (×7) SVG renders Generated via d2 (make diagrams) After d2 source — done 2026-08-20
Gateway system profile Hand-authored Miri After name decided
Framework amendment: add astronomical_id Edit to systems-framework.md Miri After lead sign-off
Naming catalog: real-star pool + fabrication rules Embedded in this doc Miri Done (see naming section above)

Plan authored 2026-03-13 by Miri. Updated 2026-03-13 with star naming section. Immediate next action: decide Gateway system name, confirm topology distribution targets, get lead sign-off on framework amendment, then implement generation script.