level-config.ts

What

Type definitions, defaults, and runtime data shapes for the Voidstar level system. Defines a LevelConfig — the single object a designer touches to author one level tier. Everything visual and gameplay-related (palette, pattern, terrain, spawn pools, illumination behavior, lantern preset) derives from this config plus a seed. Same seed + same config = identical world (deterministic).

No runtime logic, no functions — purely types, enums, two default constants.

Topology

Hub-and-spoke on an infinite 2D plane divided into chunks. Hubs are circular clearings; spokes are corridors connecting hub pairs. Zones (wilds, spoke_dark, spoke_lit, hub_dark, hub_lit) drive zone-based enemy spawning.

Enums / String unions

TypeValues
PatternTypechaotic, rings, grid, zigzag
SpokeStyleIdhighway, energy, ghost
HubStyleIdstation, nexus, crater
TerrainTypeIdasteroids, city, voidstar_mix, pillars, debris, crystals, organic, mechanical
HubParticleTypenone, dust, embers, data, spores
LanternPresetIdsolar_flare, dawn, shatter
WorldModeprecomputed, scripted
TriggerTypedialogue, spawn_wave, spawn_zone, checkpoint, event
ZoneTypewilds, spoke_dark, spoke_lit, hub_dark, hub_lit

Interfaces

ColorPalette

4-color palette — the single highest-leverage control. Every visual element samples exclusively from these 4 colors at varying opacities.

FieldUsed for
baseBackground, dark fills, wilds terrain tint, spoke fill
lineSpoke edges, hub rims, structure lines, grid patterns
accentParticles, active glow effects, enemy tint, UI highlights
illuminatedLantern glow, lit hub wash, lit spoke edges, beacon color

ZonePool / ZonePoolEntry

Per-zone spawn pool. spawnRate is enemies/second pre-director-modulation. pool is weighted entries; weights are relative, not percentages (comment recommends summing to 100 for readability).

SpawnZoneConfig

Five ZonePool slots: wilds, spoke_dark, spoke_illuminated, hub_dark, hub_illuminated. Backbone of zone-based spawning.

SpokeFlowConfig

enabled: boolean, speed: number (0-1; 0.2 barely perceptible, 0.5 clear current, 1.0 rushing stream).

ScriptedHub / ScriptedSpoke

Explicit placements for worldMode: 'scripted'. Hub has x, y, r, id. Spoke connects two hub IDs (aId, bId).

TriggerPayload / LevelTrigger

Proximity-based events. LevelTrigger fields: id, type, x, y, radius, optional oneShot, payload. Payload is a union grab-bag: text, speakerId, duration (dialogue); enemies, spawnRadius, pool, spawnRate (spawn_wave / spawn_zone); eventType (event).

Hub (runtime)

x, y, r, id, chunkKey. ID format "cx,cy:index".

Spoke (runtime)

a, b — indices into the allHubs array.

PrecomputedWorld

World data produced at level load: hubs[], spokes[], chunkSize, chunkHubIndices (Map "cx,cy" → indices), illuminationMap (Map hub.id → lit), eventCompletionMap (Map event.id → completed).

LevelConfig (the master object)

SectionFields
Identityseed, pattern
Geometry knobs (0-1)hubSize, spokeWidth, density (chaotic), ringRadius / ringCount (rings; ringCount maps to 1-3), blockSize (grid), stepSize / amplitude (zigzag)
11 Designer Controlspalette (1), spokeStyle (2), hubStyle (3), terrainDensity (4), terrainType (5), illuminationColor (6), illuminationSpeed (7), spokeFlow (9), hubParticles (10), dangerTint (11)
WildspathableWilds (when true, terrain fills only wilds zone with 75px minimum gap — ensures navigable corridors)
World modeworldMode?, scriptedHubs?, scriptedSpokes?
Triggerstriggers?
Lantern VFXlanternPreset
SpawningspawnZones
Derived limits (set per terrain type, not user-tunable)hubRMin, hubRMax, spokeWMin, spokeWMax

Note: comments number designer controls 1–11 but skip “Control 8” — only 10 controls are present in source (palette, spokeStyle, hubStyle, terrainDensity, terrainType, illuminationColor, illuminationSpeed, spokeFlow, hubParticles, dangerTint).

illuminationSpeed: 0 = instant, 1 = 2s slow bloom. dangerTint: 0 = neutral, 1 = oppressive red on unlit hubs/spokes.

Exported defaults

DEFAULT_SPAWN_ZONES

Placeholder until per-planet tuning. Spawn rates by zone:

ZoneRate (enemies/s)Pool
wilds0.4orb_common 50, charger_common 30, shooter_common 20
spoke_dark0.6orb_common 45, shooter_common 25, charger_common 20, mortar_common 10
spoke_illuminated0.2orb_common 75, shooter_common 25
hub_dark0.8shooter_common 35, orb_common 30, mortar_common 20, charger_common 15
hub_illuminated0.1orb_common 70, shooter_common 30

Pattern: dark zones spawn faster and pull harder enemies (mortars, chargers); illuminated zones spawn slow + only the soft pool (orbs + shooters). Hub_dark is the spike (0.8/s); hub_illuminated is the floor (0.1/s).

DEFAULT_PALETTE

Derelict Station — deep navy + cold blue + bright blue + warm gold.

FieldHex
base#0a0e1a
line#1e40af
accent#60a5fa
illuminated#fbbf24

DEFAULT_LEVEL_CONFIG

Chaotic pattern, Derelict Station preset. Hub/spoke sizes scaled for ~5000px world, terrain 100-960px.

FieldValue
seed42
patternchaotic
hubSize / spokeWidth0.4 / 0.5
density0.5
ringRadius / ringCount0.5 / 0.3
blockSize0.5
stepSize / amplitude0.5 / 0.5
paletteDEFAULT_PALETTE
spokeStyle / hubStylehighway / station
terrainDensity / terrainType0.5 / asteroids
illuminationColor#fbbf24
illuminationSpeed0.5
spokeFlow{ enabled: true, speed: 0.5 }
hubParticlesdata
dangerTint0.5
pathableWildstrue
worldModeprecomputed
lanternPresetsolar_flare
spawnZonesDEFAULT_SPAWN_ZONES
hubRMin / hubRMax300 / 800
spokeWMin / spokeWMax120 / 400

How it is used

  • Designer authors a LevelConfig literal per planet/tier.
  • World generator consumes seed, pattern, geometry knobs, and worldMode to emit a PrecomputedWorld (or honor scriptedHubs / scriptedSpokes).
  • Renderer consumes palette, spokeStyle, hubStyle, terrainType, hubParticles, spokeFlow, dangerTint, lanternPreset for all visuals.
  • AI Director multiplies spawnZones[zone].spawnRate at runtime; pool weights are sampled when a slot fires.
  • Illumination system reads illuminationColor and illuminationSpeed to drive the golden-wash bloom when a lantern is lit.
  • Trigger system polls triggers[] against player position vs radius; fires payload based on type.

EXTRACT-CANDIDATE

  • Per-planet LevelConfig literals. This file holds the schema and one default. Each planet/tier should live in its own data file (e.g. data/levels/derelict-station.ts, data/levels/<planet>.ts) exporting a fully-populated LevelConfig. Keeps planet content in tables, schema in code.
  • Spawn pool tables. DEFAULT_SPAWN_ZONES is flagged in-source as a placeholder. Extract per-planet spawn pools to a data table keyed by planet ID + zone, so balancing doesn’t touch type files.
  • Palette presets. DEFAULT_PALETTE is hand-coded as “Derelict Station.” A palettes.ts table mapping preset ID → ColorPalette (Derelict Station, plus future biomes) would let configs reference palette: PALETTES.derelict_station instead of inline hex.
  • Lantern preset table. LanternPresetId is a string union but the preset bodies (timings, curves, particle counts) presumably live elsewhere; if they’re inlined in renderer code, lift to a lanternPresets.ts data table.
  • Terrain-type → derived-limits table. Comment says hubRMin/Max, spokeWMin/Max are “set per terrain type, not user-tunable.” That implies a TerrainTypeId → limits lookup table is the right home, not free fields on LevelConfig.
  • Numbered-comment drift. Comments label designer controls 1, 2, 3, 4, 5, 6, 7, 9, 10, 11 — Control 8 is missing. Either the numbering is stale or a control was removed. Reconcile.