PURPOSE
Authoring panel for a single LiveSection of a VFX component. Exposes a Monaco-based GLSL fragment editor, a uniform-schema editor, a sample-inputs editor, and a blend-mode selector, alongside a small live WebGL preview that recompiles on shader or schema changes.
OWNS
- The 128x128 preview canvas DOM node mounted into a ref’d container div.
- A
PreviewSurfaceinstance held in a ref for the lifetime of the current shader/schema pair. - The
requestAnimationFrameloop driving the preview render. - Local helpers
setFragGlsl,setUniforms,setBlendthat spread updates back throughonChange. - The constant
PREVIEW_SIZE = 128.
READS FROM
- Props
value: LiveSectionandonChange: (next: LiveSection) => void. value.fragGlsl,value.uniformSchema,value.previewSampleInputs,value.blendModefor editor state and preview uniforms.- Types
LiveSection,BlendMode,UniformDeclfrom@engine/vfx-workbench/component-schema. PreviewSurfaceclass from@engine/vfx-workbench/preview-surface.performance.now()for the preview animation clock.
PUSHES TO
- Parent component via
onChangewith a newLiveSectionwheneverfragGlsl,uniformSchema,previewSampleInputs, orblendModechanges. PreviewSurface.useRawFragment(fragGlsl, uniformSchema)on (re)mount of the preview effect.PreviewSurface.setUniforms(previewSampleInputs)per animation frame and onpreviewSampleInputschange.PreviewSurface.render(tSec % 1)per animation frame.- Delegates uniform-schema editing to
UniformSchemaEditorand sample-input editing toPreviewSampleInputsEditor.
DOES NOT
- Persist or load
LiveSectiondata; it is a controlled component. - Compile or validate GLSL itself; compilation is delegated to
PreviewSurface.useRawFragmentand compile errors are swallowed so the preview stays blank. - Resize the preview; the canvas is hard-coded to
PREVIEW_SIZEsquare. - Drive the production VFX render path; the surface here is preview-only.
- Edit anything outside the single
LiveSectionpassed in (no full-component editing, no save/export). - Wrap
previewSampleInputswrites in the recompile effect; sample-input changes intentionally skip recompilation.
Signals
data-testid="live-preview-canvas"on the preview container div.data-testid="live-blend-mode"on the blend-mode<select>.- The
<select>exposes optionsadditiveandalphaforBlendMode. - Monaco editor uses
defaultLanguage="cpp"andtheme="vs-dark"for GLSL syntax highlighting.
Entry points
- Exported function component
LiveShaderEditor({ value, onChange }: Props). - Mounted by the weapon-workbench live-section UI as part of editing a VFX component’s live shader stack.
Pattern notes
- Two
useEffecthooks split concerns: one keyed on[value.fragGlsl, value.uniformSchema]rebuilds thePreviewSurfaceand starts a freshrequestAnimationFrameloop; the second keyed on[value.previewSampleInputs]pushes uniform updates into the live surface without recompiling. - Cleanup of the recompile effect cancels the pending animation frame, calls
surface.destroy(), and clearssurfaceRef.currentto prevent leaked GL contexts. - On compile failure, the surface is destroyed and the effect returns early, leaving the preview box blank rather than throwing.
- The animation loop normalizes time as
(performance.now() - start) / 1000 % 1, so the preview drives the shader on a one-second loop. - An
eslint-disable-next-line react-hooks/exhaustive-depscomment is used to scope the recompile dependency array deliberately. - Inline styles are used throughout; typography uses
Cal Sans, sans-serifwith letter-spacing for section labels.