shader-templates/registry.ts

PURPOSE

Central registry of every baked-VFX shader template available to the workbench. Imports each .frag.ts GLSL module, tags it with a family + uniform schema, and exports the flat TEMPLATES record for O(1) lookup by string id plus a templatesInFamily() helper for UI grouping.

OWNS

  • TEMPLATES: Record<TemplateId, TemplateSpec> — single source of truth for what templates exist.
  • TemplateFamily union — nine category tags.
  • TemplateId union — full enumerated list of every template string id.
  • UniformType / UniformEntry / TemplateSpec interfaces — the shape every template entry must conform to.
  • TEMPLATE_FAMILIES — stable display order for the library pane.
  • Local U() / U2() helpers — terse builders for float and vec2 uniform entries.

READS FROM

  • ./baked/*.frag — 17 legacy baked-shader GLSL modules.
  • ./shape/*.frag — 7 SDF primitives.
  • ./fill/*.frag — 13 fill generators.
  • ./mask/*.frag — 4 mask generators.
  • ./stroke/*.frag — 3 outline shaders.
  • ./glow/*.frag — 1 halo shader.
  • ./energy/*.frag — 6 energy-effect shaders.
  • ./impact/*.frag — 3 impact shaders.
  • ./post/*.frag — 10 post-process shaders (sample u_src).

PUSHES TO

Nothing — pure data export. Consumers (workbench UI, baked-atlas compositor) import TEMPLATES / templatesInFamily / TEMPLATE_FAMILIES and drive rendering, library tree population, and uniform-handle editors off of these structures.

DOES NOT

  • Does not compile or compose GLSL — only references frag strings imported from sibling files.
  • Does not instantiate GL programs, bind uniforms, or render anything.
  • Does not validate uniform values at runtime — range is advisory metadata for the editor.
  • Does not version templates or migrate uniform schemas.
  • Does not own the shared uniform contract itself (u_time / u_resolution / u_palette[4] / u_intensity); it just references it in the add-a-template comment.

Signals

SignalSourceShape
TEMPLATES[id]exported constTemplateSpec{ id, family, fragGlsl, uniformSchema }
templatesInFamily(family)helper fnTemplateSpec[] filtered by family
TEMPLATE_FAMILIESexported constordered list of 9 family strings
UniformEntrytype{ name, type, default, range?, handle?, handleColor?, doc? }

Entry points

  • Library pane tree calls templatesInFamily(family) once per family in TEMPLATE_FAMILIES order.
  • Workbench renderer does TEMPLATES[id].fragGlsl to fetch GLSL by string id.
  • Uniform editor reads TEMPLATES[id].uniformSchema to build sliders / vec2 drag handles, using range for slider bounds and handle / handleColor for canvas-overlay gizmos.

Pattern notes

  • Flat record, grouped comments. The registry is grouped visually by family in source order with ── family (N) ── separators, but exported as one flat Record<TemplateId, TemplateSpec> so id-lookup is O(1) and no nested traversal is needed.
  • Family count distribution (66 templates total):
    • baked — 17 (arc, beam, bolt, chevron, crescent, cross, diamond, disc, fire_flame, plasma_ball, ring, smoke_puff, sparkle, spiral, star, streak, teardrop)
    • shape — 7 (SDF capsule / cone / pie / polygon_n / rose / heart / ellipse)
    • fill — 13 (solid, two gradients, fbm + warped fbm, worley, voronoi_cracks, fire_rising, smoke_rising, plasma_hue_wobble, nebula_2stop, hex_grid, mandala_n_fold)
    • mask — 4 (sdf_primitive, noise_threshold, scrolling_flow, kaleidoscope)
    • stroke — 3 (sdf_outline, pulse_outline, fuzzy_outline)
    • glow — 1 (inverse_distance_halo)
    • energy — 6 (fresnel_rim, electric_arc, shield_hex, portal_swirl, reactor_core, hologram_stack)
    • impact — 3 (shockwave_ring, explosion_fireball, muzzle_starburst)
    • post — 10 (bloom, chromatic_aberration, five warp variants, grain, vignette, barrel)
  • Uniform types are minimal. UniformType = 'float' | 'vec2' | 'vec3' | 'vec3[4]'. vec3[4] is reserved for palette uniforms; only float and vec2 are actually built via the U() / U2() helpers in this file.
  • Handle metadata is editor-only. handle: 'point' | 'radius' | 'angle' plus optional handleColor tell the workbench UI to draw a draggable gizmo on the preview canvas — they have no GLSL effect.
  • Post family contract. Templates in family: 'post' are documented as sampling u_src and writing a modified output — they are the only family that reads from a prior framebuffer rather than synthesizing from scratch.
  • Add-a-template recipe (from header comment): create <family>/<name>.frag.ts exporting default GLSL matching the shared uniform contract, import here, add a TEMPLATES entry with uniformSchema, and widen TemplateId.
  • No magic ids. Every template’s string id matches the property key, the id field, and the TemplateId union member — three locations, kept in sync manually.

EXTRACT-CANDIDATE

  • Schema drift risk. TemplateId is hand-maintained alongside TEMPLATES keys — could be inferred via keyof typeof TEMPLATES once the file stops needing the union as a forward reference, eliminating one place to update when adding a template.
  • Family counts are scattered. The ── family (N) ── comments hard-code counts that must be updated by hand when templates are added; a one-liner derived from templatesInFamily(f).length in the workbench UI would prevent drift between comment and reality.
  • vec3 and vec3[4] uniform types are declared but unused by every current entry (palette is presumed injected outside uniformSchema). Either prune them from UniformType or add the U3() / UPalette() helpers to make the contract complete.
  • fire_flame import is named fireFlame (no Frag suffix) while every other baked import uses the *Frag convention — minor inconsistency worth normalizing on the next touch.