PURPOSE
VFX tab inside the Ship Playground. Live-edits darkness/lighting, fog layers (below + above ships), particle dust + bokeh, post-processing knobs, and biome/level-design VFX (4-color palette, spoke style, hub style, illumination + lantern preset). Pushes config to the running mission in real time and supports save/load of planet presets.
OWNS
- Local section open/close flags (
biomeOpen,darknessOpen,fogOpen,particleOpen,paletteOpen,spokeStyleOpen,hubStyleOpen,illuminationOpen). - Local biome + nebula selection (
biome,nebulaIdx). - Local FPS sampler (rAF counter + 1s interval to update
fps). - Local clipboard-confirmation flag (
copied). - Internal
ToggleandColorPickersubcomponents. - Static option lists:
ALL_ARCHETYPE_INDICES,BIOMES,SPOKE_STYLES,HUB_STYLES,HUB_PARTICLES,LANTERN_PRESETS.
READS FROM
- Props (
TabProps):missionRef,vfxState(aliasedvs),setVfxState(setVs),levelConfig(lc),setLevelConfig(setLc). DEFAULT_VFX_STATEandDEFAULT_LEVEL_CONFIGas fallbacks when state is undefined.ARCHETYPESfrom../../data/nebula-archetypes(length + per-indexname).- Shared styles
BTN_STYLE,LABEL_STYLEand sharedPanel+StatRowfrom./PlaygroundShared. LevelConfigtype and id typesSpokeStyleId,HubStyleId,HubParticleType,LanternPresetIdfrom../../data/level-config.pushStatsfrom../../services/playgroundPushfor preset save.
PUSHES TO
- VFX state via
setVs(prev => ({ ...prev, ...patch }))(helperset). - Level config via
setLc(prev => ({ ...prev, ...patch }))(helpersetC). - Mission handle methods on
missionRef.current:sandboxRegenerateWorld(biomeId)on biome change and on REGENERATE TERRAIN.sandboxSetNebula(index)on nebula cycle.sandboxSetLighting({ enabled, darkOpacity, ambientLight, baseRadius, dimWidth, enemyLights, bulletLights }).sandboxSetPostProcessing({ bloomAlphaMult, contrastBoost, saturationShift }).sandboxSetFog({ fogBelow, fogAbove, fogBelowAlpha, fogAboveAlpha, dustEnabled, bokehEnabled, fogBelowTex, fogAboveTex, fogBelowTintR/G/B, fogAboveTintR/G/B, fogShipCutout }).
navigator.clipboard.writeText(...)for export and preset save fallback.pushStats({ target: 'vfx-preset', id: 'current', patch: s })to persist current VFX stack.window.prompt/window.alertfor the import JSON flow.
DOES NOT
- Does not own VFX state or level config (lifted to
ShipPlaygroundScreen). - Does not render the mission canvas or any gameplay surface.
- Does not implement darkness, fog, dust, bokeh, lighting, or post-processing — only forwards parameters via the mission handle.
- Does not write to Supabase, telemetry, or any persistent store besides the
playgroundPushdev endpoint and the system clipboard. - Does not validate JSON imports beyond a try/catch around
JSON.parse. - Does not include the previously planned bloom/contrast/vignette post-processing UI (cut, per trailing comment).
Signals
- Biome
<select>callschangeBiome(id), which resetsnebulaIdxto 0 and triggerssandboxRegenerateWorld. - Nebula chevrons call
cycleNebula(±1)orcycleNebula(±10), wrapping moduloARCHETYPES.lengthand pushingsandboxSetNebula. - Three
useEffects push lighting, post-processing, and fog/dust to the mission whenever their dependency slice ofschanges. - Fog hex tints are parsed to
{ r, g, b }integer triplets before being sent (fallback values 255/255/255 if the hex is malformed). - SAVE PLANET PRESET attempts
pushStatsfirst, falls back to clipboard; LOAD reads a pasted JSON string viapromptand merges it into VFX state. - FPS sampler runs a
requestAnimationFrameloop counting frames; once per second asetIntervaldivides by elapsed seconds and updates the displayed FPS (cleaned up on unmount). - FPS color: green at >= 100, amber at >= 50, red below 50.
selectand similar inputs stop key propagation so playground hotkeys do not fire while typing.
Entry points
- Default-exported
VfxTab(props: TabProps)React component. Rendered byShipPlaygroundScreenwhen the active tab is'vfx'.
Pattern notes
- State-lift pattern: VFX and level config live on the parent so values survive tab switches; section open flags stay local because resetting them on switch is acceptable.
setandsetCcallbacks use functional updates (prev => ({ ...prev, ...patch })) to avoid stale-closure issues across the many handlers.- Level Design controls are wrapped in an IIFE that destructures
lc ?? DEFAULT_LEVEL_CONFIGonce, keepingcfgandsetClocal to that sub-tree. - Inline styling throughout (no CSS module). Color accents per panel: purple
#a855f7for biome/hub, indigo#6366f1for below-fog, violet#8b5cf6for above-fog, blue#60a5fafor spoke, amber#fbbf24for lantern. - Toggle visual state communicated via tinted background and matching border color derived from the prop
color. - Trailing comment marks the post-processing UI as intentionally removed; the underlying
sandboxSetPostProcessingcall still fires from state and stays at default values.