PURPOSE
Flat declarative registry of every tunable parameter exposed by the playground UI. One KnobDef per slider/toggle/dropdown/color control. The knobStore reads this at init to populate defaults and current values, and downstream apply logic uses applyGroup to route changes to the correct MissionHandle method group.
OWNS
KnobControltype alias ('slider' | 'toggle' | 'dropdown' | 'color').KnobDefinterface —id,label,category,control, optionalmin/max/step,default,applyGroup.KNOB_REGISTRY— the canonical ordered list of all knob definitions grouped by category (Ship Stats, Spawner, VFX Lighting, VFX Fog, Physics, Level Gen, Game Flow).KNOB_MAP—Record<string, KnobDef>lookup built fromKNOB_REGISTRYviaObject.fromEntries.- Private constructor helpers
slider(...)andtoggle(...)that buildKnobDefobjects with the appropriatecontrolfield set.
READS FROM
Nothing. This module is a pure data/type definition file with no imports.
PUSHES TO
Nothing directly. Consumers (knobStore, playground apply layer) import KNOB_REGISTRY, KNOB_MAP, KnobDef, and KnobControl.
DOES NOT
- Does not apply knob values to game state — it only describes them.
- Does not store current values — that lives in
knobStore. - Does not render UI — the playground screen does.
- Does not validate
min/maxranges at runtime. - Does not define
dropdownorcolorcontrol entries despite theKnobControlunion allowing them — onlysliderandtogglehelpers exist and only those two control types appear in the current registry. - Does not provide a
dropdown(...)orcolor(...)helper.
Signals
None. No events emitted, no observers, no callbacks. Pure data export.
Entry points
KNOB_REGISTRY— primary import for any consumer that needs to enumerate all knobs (e.g. store init, UI rendering).KNOB_MAP— primary import for any consumer that needs O(1) lookup by knob id.KnobDef/KnobControltypes — imported by consumers that type-check against knob shapes.
Pattern notes
- Data table, not code. Every tunable parameter is one row; logic lives elsewhere. Aligns with the “content in data tables, behavior in code” rule.
- Flat array of records, no nesting. Categories are a string field on each row rather than a nested grouping structure; UI groups by
categoryat render time. applyGroupis the routing discriminator. Each knob declares whichMissionHandlemethod group consumes it (shipStats,worldKnobs,lighting,fog,postProcess,physics,levelConfig,direct), so the apply layer can dispatch without per-knob switch statements.iduses dotted namespacing (ship.hpMax,vfx.fogBelow,spawner.spawnRate) — first segment matches the category prefix.defaultis typed asnumber | string | booleanto support all control types, even though current rows only use number and boolean.KNOB_MAPis derived fromKNOB_REGISTRYat module load — single source of truth, no risk of drift between list and lookup.slider(...)andtoggle(...)helpers exist purely for readability of long literal rows; they collapse the positional arguments into a uniform call site so the registry reads like a table.postProcessappears in theapplyGroupunion but no current row uses it — reserved for future post-processing knobs.