agentvfx 0.0.0-stage → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (483) hide show
  1. package/AGENTS.md +8 -0
  2. package/GEMINI.md +1 -0
  3. package/LICENSE +202 -0
  4. package/README.md +228 -2
  5. package/package.json +35 -4
  6. package/skills/agentvfx/LICENSE +202 -0
  7. package/skills/agentvfx/NOTICE +50 -0
  8. package/skills/agentvfx/SKILL.md +90 -0
  9. package/skills/agentvfx/engine/core/constants.mjs +84 -0
  10. package/skills/agentvfx/engine/core/flash-constants.mjs +23 -0
  11. package/skills/agentvfx/engine/core/flash.mjs +240 -0
  12. package/skills/agentvfx/engine/core/mark.mjs +25 -0
  13. package/skills/agentvfx/engine/core/palettes.mjs +36 -0
  14. package/skills/agentvfx/engine/core/schedule.mjs +85 -0
  15. package/skills/agentvfx/engine/core/templates.mjs +43 -0
  16. package/skills/agentvfx/engine/core/util.mjs +167 -0
  17. package/skills/agentvfx/engine/core/validate.mjs +334 -0
  18. package/skills/agentvfx/engine/node/analysis.mjs +172 -0
  19. package/skills/agentvfx/engine/node/audio.mjs +621 -0
  20. package/skills/agentvfx/engine/node/board.mjs +24 -0
  21. package/skills/agentvfx/engine/node/chrome.mjs +349 -0
  22. package/skills/agentvfx/engine/node/encode.mjs +110 -0
  23. package/skills/agentvfx/engine/node/eye.mjs +77 -0
  24. package/skills/agentvfx/engine/node/footage.mjs +129 -0
  25. package/skills/agentvfx/engine/node/frame-worker.mjs +39 -0
  26. package/skills/agentvfx/engine/node/host.mjs +31 -0
  27. package/skills/agentvfx/engine/node/job.mjs +181 -0
  28. package/skills/agentvfx/engine/node/png.mjs +112 -0
  29. package/skills/agentvfx/engine/node/render.mjs +161 -0
  30. package/skills/agentvfx/engine/node/stage-capture.mjs +187 -0
  31. package/skills/agentvfx/engine/node/stage-serve.mjs +72 -0
  32. package/skills/agentvfx/engine/node/stills.mjs +100 -0
  33. package/skills/agentvfx/engine/node/ws-server.mjs +132 -0
  34. package/skills/agentvfx/engine/web/gl.mjs +319 -0
  35. package/skills/agentvfx/engine/web/glsl-common.mjs +78 -0
  36. package/skills/agentvfx/engine/web/init.js +23 -0
  37. package/skills/agentvfx/engine/web/prelude.mjs +150 -0
  38. package/skills/agentvfx/engine/web/render.html +11 -0
  39. package/skills/agentvfx/engine/web/render.mjs +388 -0
  40. package/skills/agentvfx/engine/web/scale.mjs +15 -0
  41. package/skills/agentvfx/engine/web/text.mjs +158 -0
  42. package/skills/agentvfx/plates/terminalcore/README.md +61 -0
  43. package/skills/agentvfx/plates/terminalcore/__pycache__/crt.cpython-313.pyc +0 -0
  44. package/skills/agentvfx/plates/terminalcore/__pycache__/font.cpython-313.pyc +0 -0
  45. package/skills/agentvfx/plates/terminalcore/__pycache__/gallery.cpython-313.pyc +0 -0
  46. package/skills/agentvfx/plates/terminalcore/__pycache__/gallery_mats.cpython-313.pyc +0 -0
  47. package/skills/agentvfx/plates/terminalcore/__pycache__/gallery_room.cpython-313.pyc +0 -0
  48. package/skills/agentvfx/plates/terminalcore/__pycache__/materials.cpython-313.pyc +0 -0
  49. package/skills/agentvfx/plates/terminalcore/__pycache__/nodekit.cpython-313.pyc +0 -0
  50. package/skills/agentvfx/plates/terminalcore/__pycache__/room.cpython-313.pyc +0 -0
  51. package/skills/agentvfx/plates/terminalcore/__pycache__/shots.cpython-313.pyc +0 -0
  52. package/skills/agentvfx/plates/terminalcore/__pycache__/textures.cpython-313.pyc +0 -0
  53. package/skills/agentvfx/plates/terminalcore/__pycache__/wall.cpython-313.pyc +0 -0
  54. package/skills/agentvfx/plates/terminalcore/crt.py +143 -0
  55. package/skills/agentvfx/plates/terminalcore/font.py +80 -0
  56. package/skills/agentvfx/plates/terminalcore/gallery.py +61 -0
  57. package/skills/agentvfx/plates/terminalcore/gallery_mats.py +144 -0
  58. package/skills/agentvfx/plates/terminalcore/gallery_room.py +126 -0
  59. package/skills/agentvfx/plates/terminalcore/materials.py +170 -0
  60. package/skills/agentvfx/plates/terminalcore/nodekit.py +87 -0
  61. package/skills/agentvfx/plates/terminalcore/room.py +82 -0
  62. package/skills/agentvfx/plates/terminalcore/scene.py +219 -0
  63. package/skills/agentvfx/plates/terminalcore/shots.py +48 -0
  64. package/skills/agentvfx/plates/terminalcore/textures.py +79 -0
  65. package/skills/agentvfx/plates/terminalcore/wall.py +103 -0
  66. package/skills/agentvfx/references/plates.md +22 -0
  67. package/skills/agentvfx/references/template-format.md +149 -0
  68. package/skills/agentvfx/references/web.md +63 -0
  69. package/skills/agentvfx/runtime/agentvfx.js +708 -0
  70. package/skills/agentvfx/schemas/fx-score.schema.json +98 -0
  71. package/skills/agentvfx/scripts/export-web.mjs +157 -0
  72. package/skills/agentvfx/scripts/loop.mjs +129 -0
  73. package/skills/agentvfx/scripts/make-beat.mjs +133 -0
  74. package/skills/agentvfx/scripts/plate.mjs +82 -0
  75. package/skills/agentvfx/scripts/vfx.mjs +173 -0
  76. package/skills/agentvfx/templates/_test/feedback-counter/fx.json +11 -0
  77. package/skills/agentvfx/templates/_test/feedback-counter/main.frag +4 -0
  78. package/skills/agentvfx/templates/_test/feedback-counter/pass0.frag +4 -0
  79. package/skills/agentvfx/templates/_test/gradient/fx.json +23 -0
  80. package/skills/agentvfx/templates/_test/gradient/main.frag +5 -0
  81. package/skills/agentvfx/templates/_test/identity/fx.json +10 -0
  82. package/skills/agentvfx/templates/_test/identity/main.frag +4 -0
  83. package/skills/agentvfx/templates/_test/strobe/fx.json +14 -0
  84. package/skills/agentvfx/templates/_test/strobe/main.frag +6 -0
  85. package/skills/agentvfx/templates/_test/text-probe/fx.json +15 -0
  86. package/skills/agentvfx/templates/_test/text-probe/main.frag +6 -0
  87. package/skills/agentvfx/templates/brutal/NOTES.md +14 -0
  88. package/skills/agentvfx/templates/brutal/_src/boot-log/def.mjs +57 -0
  89. package/skills/agentvfx/templates/brutal/_src/boot-log/main.src.frag +129 -0
  90. package/skills/agentvfx/templates/brutal/_src/build.mjs +33 -0
  91. package/skills/agentvfx/templates/brutal/_src/halftone-field/def.mjs +72 -0
  92. package/skills/agentvfx/templates/brutal/_src/halftone-field/main.src.frag +94 -0
  93. package/skills/agentvfx/templates/brutal/_src/hud-deck/deck-left.src.glsl +100 -0
  94. package/skills/agentvfx/templates/brutal/_src/hud-deck/deck-right.src.glsl +61 -0
  95. package/skills/agentvfx/templates/brutal/_src/hud-deck/deck-tiles.src.glsl +153 -0
  96. package/skills/agentvfx/templates/brutal/_src/hud-deck/def.mjs +82 -0
  97. package/skills/agentvfx/templates/brutal/_src/hud-deck/main.src.frag +110 -0
  98. package/skills/agentvfx/templates/brutal/_src/hud-deck/pass0.src.frag +38 -0
  99. package/skills/agentvfx/templates/brutal/_src/shared/defs.mjs +28 -0
  100. package/skills/agentvfx/templates/brutal/_src/shared/icons.glsl +72 -0
  101. package/skills/agentvfx/templates/brutal/_src/shared/lib.glsl +115 -0
  102. package/skills/agentvfx/templates/brutal/_src/shared/screen.glsl +43 -0
  103. package/skills/agentvfx/templates/brutal/boot-log/demo-acid.json +1 -0
  104. package/skills/agentvfx/templates/brutal/boot-log/demo-phosphor.json +1 -0
  105. package/skills/agentvfx/templates/brutal/boot-log/demo-ultramarine.json +1 -0
  106. package/skills/agentvfx/templates/brutal/boot-log/fx.json +257 -0
  107. package/skills/agentvfx/templates/brutal/boot-log/main.frag +242 -0
  108. package/skills/agentvfx/templates/brutal/collage/_src/00-lib.glsl +73 -0
  109. package/skills/agentvfx/templates/brutal/collage/_src/10-spectrum-scope.glsl +73 -0
  110. package/skills/agentvfx/templates/brutal/collage/_src/20-meter-readout-cross.glsl +87 -0
  111. package/skills/agentvfx/templates/brutal/collage/_src/30-footage-fillers.glsl +92 -0
  112. package/skills/agentvfx/templates/brutal/collage/_src/40-editorial.glsl +232 -0
  113. package/skills/agentvfx/templates/brutal/collage/_src/50-typefx.glsl +163 -0
  114. package/skills/agentvfx/templates/brutal/collage/_src/60-scene-lib.glsl +104 -0
  115. package/skills/agentvfx/templates/brutal/collage/_src/61-scene-specimen.glsl +71 -0
  116. package/skills/agentvfx/templates/brutal/collage/_src/62-scene-wiring.glsl +96 -0
  117. package/skills/agentvfx/templates/brutal/collage/_src/63-scene-fieldcut.glsl +119 -0
  118. package/skills/agentvfx/templates/brutal/collage/_src/64-scene-pattern.glsl +64 -0
  119. package/skills/agentvfx/templates/brutal/collage/_src/641-scene-anatomy.glsl +49 -0
  120. package/skills/agentvfx/templates/brutal/collage/_src/642-scene-deck.glsl +78 -0
  121. package/skills/agentvfx/templates/brutal/collage/_src/643-scene-bootlog.glsl +60 -0
  122. package/skills/agentvfx/templates/brutal/collage/_src/644-scene-tunnel.glsl +48 -0
  123. package/skills/agentvfx/templates/brutal/collage/_src/645-scene-runner.glsl +42 -0
  124. package/skills/agentvfx/templates/brutal/collage/_src/646-scene-ascii.glsl +66 -0
  125. package/skills/agentvfx/templates/brutal/collage/_src/647-scene-cubewall.glsl +80 -0
  126. package/skills/agentvfx/templates/brutal/collage/_src/648-scene-vortex.glsl +46 -0
  127. package/skills/agentvfx/templates/brutal/collage/_src/649-scene-sticker.glsl +72 -0
  128. package/skills/agentvfx/templates/brutal/collage/_src/65-scene-main.glsl +1 -0
  129. package/skills/agentvfx/templates/brutal/collage/_src/650-scene-ribbon.glsl +55 -0
  130. package/skills/agentvfx/templates/brutal/collage/_src/651-scene-slab.glsl +38 -0
  131. package/skills/agentvfx/templates/brutal/collage/_src/652-scene-framedial.glsl +79 -0
  132. package/skills/agentvfx/templates/brutal/collage/_src/653-scene-tilt.glsl +40 -0
  133. package/skills/agentvfx/templates/brutal/collage/_src/654-scene-marquee.glsl +45 -0
  134. package/skills/agentvfx/templates/brutal/collage/_src/655-scene-lens.glsl +57 -0
  135. package/skills/agentvfx/templates/brutal/collage/_src/656-scene-liquid.glsl +35 -0
  136. package/skills/agentvfx/templates/brutal/collage/_src/657-scene-panelgrid.glsl +75 -0
  137. package/skills/agentvfx/templates/brutal/collage/_src/658-scene-mirror.glsl +49 -0
  138. package/skills/agentvfx/templates/brutal/collage/_src/66-scene-main.glsl +27 -0
  139. package/skills/agentvfx/templates/brutal/collage/_src/90-main.glsl +120 -0
  140. package/skills/agentvfx/templates/brutal/collage/_src/build.mjs +24 -0
  141. package/skills/agentvfx/templates/brutal/collage/_src/sync-presets.mjs +16 -0
  142. package/skills/agentvfx/templates/brutal/collage/demo-bone-lime.json +1 -0
  143. package/skills/agentvfx/templates/brutal/collage/demo-lime-sparse.json +1 -0
  144. package/skills/agentvfx/templates/brutal/collage/demo-orange-dense.json +1 -0
  145. package/skills/agentvfx/templates/brutal/collage/demo-ultra-slow.json +1 -0
  146. package/skills/agentvfx/templates/brutal/collage/fx.json +4882 -0
  147. package/skills/agentvfx/templates/brutal/collage/layout.mjs +97 -0
  148. package/skills/agentvfx/templates/brutal/collage/layouts.json +366 -0
  149. package/skills/agentvfx/templates/brutal/collage/main.frag +2367 -0
  150. package/skills/agentvfx/templates/brutal/collage/pass0.frag +265 -0
  151. package/skills/agentvfx/templates/brutal/halftone-field/demo-acid.json +1 -0
  152. package/skills/agentvfx/templates/brutal/halftone-field/demo-ascii.json +1 -0
  153. package/skills/agentvfx/templates/brutal/halftone-field/demo-dither.json +1 -0
  154. package/skills/agentvfx/templates/brutal/halftone-field/demo-orange.json +1 -0
  155. package/skills/agentvfx/templates/brutal/halftone-field/demo-phosphor.json +1 -0
  156. package/skills/agentvfx/templates/brutal/halftone-field/demo-ultramarine.json +1 -0
  157. package/skills/agentvfx/templates/brutal/halftone-field/fx.json +474 -0
  158. package/skills/agentvfx/templates/brutal/halftone-field/main.frag +248 -0
  159. package/skills/agentvfx/templates/brutal/hud-deck/demo-acid.json +1 -0
  160. package/skills/agentvfx/templates/brutal/hud-deck/demo-night.json +1 -0
  161. package/skills/agentvfx/templates/brutal/hud-deck/demo-octagon.json +1 -0
  162. package/skills/agentvfx/templates/brutal/hud-deck/demo-ultramarine.json +1 -0
  163. package/skills/agentvfx/templates/brutal/hud-deck/fx.json +601 -0
  164. package/skills/agentvfx/templates/brutal/hud-deck/main.frag +645 -0
  165. package/skills/agentvfx/templates/brutal/hud-deck/pass0.frag +38 -0
  166. package/skills/agentvfx/templates/brutal/lattice/demo-cobalt-fine.json +1 -0
  167. package/skills/agentvfx/templates/brutal/lattice/demo-ink-yellow.json +1 -0
  168. package/skills/agentvfx/templates/brutal/lattice/demo-vermilion.json +1 -0
  169. package/skills/agentvfx/templates/brutal/lattice/demo-violet-slow.json +1 -0
  170. package/skills/agentvfx/templates/brutal/lattice/fx.json +130 -0
  171. package/skills/agentvfx/templates/brutal/lattice/main.frag +175 -0
  172. package/skills/agentvfx/templates/brutal/lattice/pass0.frag +29 -0
  173. package/skills/agentvfx/templates/glitch/block-glitch/demo-mosaic.json +1 -0
  174. package/skills/agentvfx/templates/glitch/block-glitch/demo-onset.json +1 -0
  175. package/skills/agentvfx/templates/glitch/block-glitch/demo-static.json +1 -0
  176. package/skills/agentvfx/templates/glitch/block-glitch/demo-tear.json +1 -0
  177. package/skills/agentvfx/templates/glitch/block-glitch/fx.json +54 -0
  178. package/skills/agentvfx/templates/glitch/block-glitch/main.frag +132 -0
  179. package/skills/agentvfx/templates/glitch/block-glitch/pass0.frag +12 -0
  180. package/skills/agentvfx/templates/glitch/pixel-sort/NOTES.md +13 -0
  181. package/skills/agentvfx/templates/glitch/pixel-sort/build-passes.mjs +162 -0
  182. package/skills/agentvfx/templates/glitch/pixel-sort/demo-chunk.json +1 -0
  183. package/skills/agentvfx/templates/glitch/pixel-sort/demo-hue.json +1 -0
  184. package/skills/agentvfx/templates/glitch/pixel-sort/demo-kick.json +1 -0
  185. package/skills/agentvfx/templates/glitch/pixel-sort/demo-streak.json +1 -0
  186. package/skills/agentvfx/templates/glitch/pixel-sort/demo-vertical.json +1 -0
  187. package/skills/agentvfx/templates/glitch/pixel-sort/fx.json +60 -0
  188. package/skills/agentvfx/templates/glitch/pixel-sort/main.frag +83 -0
  189. package/skills/agentvfx/templates/glitch/pixel-sort/pass0.frag +64 -0
  190. package/skills/agentvfx/templates/glitch/pixel-sort/pass1.frag +66 -0
  191. package/skills/agentvfx/templates/glitch/pixel-sort/pass2.frag +66 -0
  192. package/skills/agentvfx/templates/glitch/pixel-sort/pass3.frag +66 -0
  193. package/skills/agentvfx/templates/glitch/pixel-sort/pass4.frag +66 -0
  194. package/skills/agentvfx/templates/glitch/pixel-sort/pass5.frag +66 -0
  195. package/skills/agentvfx/templates/glitch/pixel-sort/pass6.frag +66 -0
  196. package/skills/agentvfx/templates/glitch/pixel-sort/pass7.frag +66 -0
  197. package/skills/agentvfx/templates/glitch/pixel-sort/pass8.frag +66 -0
  198. package/skills/agentvfx/templates/glitch/rgb-split/demo-diagonal-stutter.json +1 -0
  199. package/skills/agentvfx/templates/glitch/rgb-split/demo-hard.json +1 -0
  200. package/skills/agentvfx/templates/glitch/rgb-split/demo-kick.json +1 -0
  201. package/skills/agentvfx/templates/glitch/rgb-split/demo-radial.json +1 -0
  202. package/skills/agentvfx/templates/glitch/rgb-split/fx.json +46 -0
  203. package/skills/agentvfx/templates/glitch/rgb-split/main.frag +76 -0
  204. package/skills/agentvfx/templates/glitch/vhs/demo-clean.json +1 -0
  205. package/skills/agentvfx/templates/glitch/vhs/demo-crash.json +1 -0
  206. package/skills/agentvfx/templates/glitch/vhs/demo-tape.json +1 -0
  207. package/skills/agentvfx/templates/glitch/vhs/demo-worn.json +1 -0
  208. package/skills/agentvfx/templates/glitch/vhs/fx.json +46 -0
  209. package/skills/agentvfx/templates/glitch/vhs/main.frag +96 -0
  210. package/skills/agentvfx/templates/impact/impact-1bit/demo-onebit-bayer.json +1 -0
  211. package/skills/agentvfx/templates/impact/impact-1bit/fx.json +45 -0
  212. package/skills/agentvfx/templates/impact/impact-1bit/main.frag +64 -0
  213. package/skills/agentvfx/templates/impact/impact-invert/demo-invert-snap.json +1 -0
  214. package/skills/agentvfx/templates/impact/impact-invert/fx.json +37 -0
  215. package/skills/agentvfx/templates/impact/impact-invert/main.frag +44 -0
  216. package/skills/agentvfx/templates/impact/punch-shake/demo-punch-hard.json +1 -0
  217. package/skills/agentvfx/templates/impact/punch-shake/fx.json +36 -0
  218. package/skills/agentvfx/templates/impact/punch-shake/main.frag +62 -0
  219. package/skills/agentvfx/templates/impact/rgb-hit/demo-rgb-slam.json +1 -0
  220. package/skills/agentvfx/templates/impact/rgb-hit/fx.json +39 -0
  221. package/skills/agentvfx/templates/impact/rgb-hit/main.frag +62 -0
  222. package/skills/agentvfx/templates/impact/signal-cut/demo-lime-hold.json +1 -0
  223. package/skills/agentvfx/templates/impact/signal-cut/demo-lime.json +1 -0
  224. package/skills/agentvfx/templates/impact/signal-cut/demo-orange.json +1 -0
  225. package/skills/agentvfx/templates/impact/signal-cut/demo-ultramarine.json +1 -0
  226. package/skills/agentvfx/templates/impact/signal-cut/fx.json +83 -0
  227. package/skills/agentvfx/templates/impact/signal-cut/main.frag +101 -0
  228. package/skills/agentvfx/templates/impact/signal-cut/pass0.frag +68 -0
  229. package/skills/agentvfx/templates/impact/speedline-burst/demo-speed-white.json +1 -0
  230. package/skills/agentvfx/templates/impact/speedline-burst/fx.json +44 -0
  231. package/skills/agentvfx/templates/impact/speedline-burst/main.frag +68 -0
  232. package/skills/agentvfx/templates/impact/strobe-burst/demo-strobe-white-16.json +1 -0
  233. package/skills/agentvfx/templates/impact/strobe-burst/fx.json +42 -0
  234. package/skills/agentvfx/templates/impact/strobe-burst/main.frag +43 -0
  235. package/skills/agentvfx/templates/light/anamorphic-streak/demo-anamorphic-cinema.json +10 -0
  236. package/skills/agentvfx/templates/light/anamorphic-streak/demo-data.json +10 -0
  237. package/skills/agentvfx/templates/light/anamorphic-streak/fx.json +47 -0
  238. package/skills/agentvfx/templates/light/anamorphic-streak/main.frag +45 -0
  239. package/skills/agentvfx/templates/light/anamorphic-streak/pass0.frag +22 -0
  240. package/skills/agentvfx/templates/light/anamorphic-streak/pass1.frag +16 -0
  241. package/skills/agentvfx/templates/light/anamorphic-streak/pass2.frag +16 -0
  242. package/skills/agentvfx/templates/light/anamorphic-streak/pass3.frag +16 -0
  243. package/skills/agentvfx/templates/light/bloom-glow/demo-clip01-low.json +11 -0
  244. package/skills/agentvfx/templates/light/bloom-glow/demo-neon-night.json +10 -0
  245. package/skills/agentvfx/templates/light/bloom-glow/demo-phosphor.json +11 -0
  246. package/skills/agentvfx/templates/light/bloom-glow/fx.json +53 -0
  247. package/skills/agentvfx/templates/light/bloom-glow/main.frag +85 -0
  248. package/skills/agentvfx/templates/light/bloom-glow/pass0.frag +21 -0
  249. package/skills/agentvfx/templates/light/bloom-glow/pass1.frag +50 -0
  250. package/skills/agentvfx/templates/light/bloom-glow/pass2.frag +44 -0
  251. package/skills/agentvfx/templates/light/bloom-glow/pass3.frag +32 -0
  252. package/skills/agentvfx/templates/light/bloom-glow/pass4.frag +48 -0
  253. package/skills/agentvfx/templates/light/bloom-glow/pass5.frag +46 -0
  254. package/skills/agentvfx/templates/light/god-rays/demo-golden-hour.json +10 -0
  255. package/skills/agentvfx/templates/light/god-rays/demo-point-lamp.json +10 -0
  256. package/skills/agentvfx/templates/light/god-rays/fx.json +39 -0
  257. package/skills/agentvfx/templates/light/god-rays/main.frag +54 -0
  258. package/skills/agentvfx/templates/light/lens-flare/demo-clip01-bar.json +11 -0
  259. package/skills/agentvfx/templates/light/lens-flare/demo-eye-bar.json +10 -0
  260. package/skills/agentvfx/templates/light/lens-flare/demo-sun-ghosts.json +10 -0
  261. package/skills/agentvfx/templates/light/lens-flare/fx.json +49 -0
  262. package/skills/agentvfx/templates/light/lens-flare/main.frag +86 -0
  263. package/skills/agentvfx/templates/light/lens-flare/pass0.frag +24 -0
  264. package/skills/agentvfx/templates/light/light-leak/demo-slit.json +10 -0
  265. package/skills/agentvfx/templates/light/light-leak/demo-vintage-burn.json +10 -0
  266. package/skills/agentvfx/templates/light/light-leak/fx.json +40 -0
  267. package/skills/agentvfx/templates/light/light-leak/main.frag +46 -0
  268. package/skills/agentvfx/templates/light/light-stage/fx.json +29 -0
  269. package/skills/agentvfx/templates/light/light-stage/main.frag +56 -0
  270. package/skills/agentvfx/templates/light/light-sweep/demo-hard-bar.json +12 -0
  271. package/skills/agentvfx/templates/light/light-sweep/demo-logo-sweep.json +10 -0
  272. package/skills/agentvfx/templates/light/light-sweep/demo-onset.json +11 -0
  273. package/skills/agentvfx/templates/light/light-sweep/fx.json +45 -0
  274. package/skills/agentvfx/templates/light/light-sweep/main.frag +29 -0
  275. package/skills/agentvfx/templates/light/light-sweep/pass0.frag +17 -0
  276. package/skills/agentvfx/templates/light/light-sweep/pass1.frag +15 -0
  277. package/skills/agentvfx/templates/light/neon-saber/demo-hairline.json +10 -0
  278. package/skills/agentvfx/templates/light/neon-saber/demo-saber-laser.json +10 -0
  279. package/skills/agentvfx/templates/light/neon-saber/fx.json +48 -0
  280. package/skills/agentvfx/templates/light/neon-saber/main.frag +27 -0
  281. package/skills/agentvfx/templates/light/neon-saber/pass0.frag +46 -0
  282. package/skills/agentvfx/templates/light/neon-saber/pass1.frag +15 -0
  283. package/skills/agentvfx/templates/psychedelic/echo-flow/demo-trail.json +1 -0
  284. package/skills/agentvfx/templates/psychedelic/echo-flow/fx.json +38 -0
  285. package/skills/agentvfx/templates/psychedelic/echo-flow/main.frag +19 -0
  286. package/skills/agentvfx/templates/psychedelic/echo-flow/pass0.frag +16 -0
  287. package/skills/agentvfx/templates/psychedelic/echo-flow/pass1.frag +20 -0
  288. package/skills/agentvfx/templates/psychedelic/echo-flow/pass2.frag +11 -0
  289. package/skills/agentvfx/templates/psychedelic/echo-flow/pass3.frag +4 -0
  290. package/skills/agentvfx/templates/psychedelic/hologram-scan/demo-cyan.json +1 -0
  291. package/skills/agentvfx/templates/psychedelic/hologram-scan/fx.json +36 -0
  292. package/skills/agentvfx/templates/psychedelic/hologram-scan/main.frag +30 -0
  293. package/skills/agentvfx/templates/psychedelic/kaleido-fold/demo-six.json +1 -0
  294. package/skills/agentvfx/templates/psychedelic/kaleido-fold/fx.json +37 -0
  295. package/skills/agentvfx/templates/psychedelic/kaleido-fold/main.frag +10 -0
  296. package/skills/agentvfx/templates/psychedelic/kaleido-fold/pass0.frag +34 -0
  297. package/skills/agentvfx/templates/psychedelic/mosh-melt/demo-classic.json +1 -0
  298. package/skills/agentvfx/templates/psychedelic/mosh-melt/fx.json +38 -0
  299. package/skills/agentvfx/templates/psychedelic/mosh-melt/main.frag +20 -0
  300. package/skills/agentvfx/templates/psychedelic/mosh-melt/pass0.frag +22 -0
  301. package/skills/agentvfx/templates/psychedelic/sacred/NOTES.md +13 -0
  302. package/skills/agentvfx/templates/psychedelic/sacred/demo-classic.json +1 -0
  303. package/skills/agentvfx/templates/psychedelic/sacred/demo-halo.json +1 -0
  304. package/skills/agentvfx/templates/psychedelic/sacred/demo-slow-tide.json +1 -0
  305. package/skills/agentvfx/templates/psychedelic/sacred/demo-thermal.json +1 -0
  306. package/skills/agentvfx/templates/psychedelic/sacred/fx.json +263 -0
  307. package/skills/agentvfx/templates/psychedelic/sacred/main.frag +109 -0
  308. package/skills/agentvfx/templates/psychedelic/sacred/pass0.frag +25 -0
  309. package/skills/agentvfx/templates/psychedelic/sacred/pass1.frag +23 -0
  310. package/skills/agentvfx/templates/psychedelic/tidal-bands/demo-classic.json +1 -0
  311. package/skills/agentvfx/templates/psychedelic/tidal-bands/fx.json +37 -0
  312. package/skills/agentvfx/templates/psychedelic/tidal-bands/main.frag +54 -0
  313. package/skills/agentvfx/templates/scope/_chrome.glsl +242 -0
  314. package/skills/agentvfx/templates/scope/goniometer/demo-boot-green.json +1 -0
  315. package/skills/agentvfx/templates/scope/goniometer/demo-field-lime.json +1 -0
  316. package/skills/agentvfx/templates/scope/goniometer/demo-field-ultramarine.json +1 -0
  317. package/skills/agentvfx/templates/scope/goniometer/demo-glow-phosphor.json +1 -0
  318. package/skills/agentvfx/templates/scope/goniometer/demo-hud-black.json +1 -0
  319. package/skills/agentvfx/templates/scope/goniometer/fx.json +635 -0
  320. package/skills/agentvfx/templates/scope/goniometer/main.frag +33 -0
  321. package/skills/agentvfx/templates/scope/goniometer/pass0.frag +58 -0
  322. package/skills/agentvfx/templates/scope/goniometer/pass1.frag +43 -0
  323. package/skills/agentvfx/templates/scope/goniometer/pass2.frag +12 -0
  324. package/skills/agentvfx/templates/scope/goniometer/pass3.frag +12 -0
  325. package/skills/agentvfx/templates/scope/goniometer/pass4.frag +12 -0
  326. package/skills/agentvfx/templates/scope/goniometer/pass5.frag +12 -0
  327. package/skills/agentvfx/templates/scope/goniometer/pass6.frag +251 -0
  328. package/skills/agentvfx/templates/scope/scope-polar/demo-boot-green.json +1 -0
  329. package/skills/agentvfx/templates/scope/scope-polar/demo-field-lime.json +1 -0
  330. package/skills/agentvfx/templates/scope/scope-polar/demo-field-ultramarine.json +1 -0
  331. package/skills/agentvfx/templates/scope/scope-polar/demo-glow-phosphor.json +1 -0
  332. package/skills/agentvfx/templates/scope/scope-polar/demo-hud-black.json +1 -0
  333. package/skills/agentvfx/templates/scope/scope-polar/fx.json +686 -0
  334. package/skills/agentvfx/templates/scope/scope-polar/main.frag +39 -0
  335. package/skills/agentvfx/templates/scope/scope-polar/pass0.frag +84 -0
  336. package/skills/agentvfx/templates/scope/scope-polar/pass1.frag +49 -0
  337. package/skills/agentvfx/templates/scope/scope-polar/pass2.frag +12 -0
  338. package/skills/agentvfx/templates/scope/scope-polar/pass3.frag +12 -0
  339. package/skills/agentvfx/templates/scope/scope-polar/pass4.frag +12 -0
  340. package/skills/agentvfx/templates/scope/scope-polar/pass5.frag +12 -0
  341. package/skills/agentvfx/templates/scope/scope-polar/pass6.frag +251 -0
  342. package/skills/agentvfx/templates/scope/scope-triggered/demo-boot-green.json +1 -0
  343. package/skills/agentvfx/templates/scope/scope-triggered/demo-field-lime.json +1 -0
  344. package/skills/agentvfx/templates/scope/scope-triggered/demo-field-ultramarine.json +1 -0
  345. package/skills/agentvfx/templates/scope/scope-triggered/demo-glow-phosphor.json +1 -0
  346. package/skills/agentvfx/templates/scope/scope-triggered/demo-hud-black.json +1 -0
  347. package/skills/agentvfx/templates/scope/scope-triggered/fx.json +712 -0
  348. package/skills/agentvfx/templates/scope/scope-triggered/main.frag +36 -0
  349. package/skills/agentvfx/templates/scope/scope-triggered/pass0.frag +78 -0
  350. package/skills/agentvfx/templates/scope/scope-triggered/pass1.frag +50 -0
  351. package/skills/agentvfx/templates/scope/scope-triggered/pass2.frag +12 -0
  352. package/skills/agentvfx/templates/scope/scope-triggered/pass3.frag +12 -0
  353. package/skills/agentvfx/templates/scope/scope-triggered/pass4.frag +12 -0
  354. package/skills/agentvfx/templates/scope/scope-triggered/pass5.frag +12 -0
  355. package/skills/agentvfx/templates/scope/scope-triggered/pass6.frag +251 -0
  356. package/skills/agentvfx/templates/scope/spectrogram-scroll/demo-boot-green.json +1 -0
  357. package/skills/agentvfx/templates/scope/spectrogram-scroll/demo-field-lime.json +1 -0
  358. package/skills/agentvfx/templates/scope/spectrogram-scroll/demo-field-ultramarine.json +1 -0
  359. package/skills/agentvfx/templates/scope/spectrogram-scroll/demo-glow-phosphor.json +1 -0
  360. package/skills/agentvfx/templates/scope/spectrogram-scroll/demo-hud-black.json +1 -0
  361. package/skills/agentvfx/templates/scope/spectrogram-scroll/fx.json +595 -0
  362. package/skills/agentvfx/templates/scope/spectrogram-scroll/main.frag +83 -0
  363. package/skills/agentvfx/templates/scope/spectrogram-scroll/pass0.frag +52 -0
  364. package/skills/agentvfx/templates/scope/spectrogram-scroll/pass1.frag +251 -0
  365. package/skills/agentvfx/templates/scope/xy-phosphor/demo-boot-green.json +1 -0
  366. package/skills/agentvfx/templates/scope/xy-phosphor/demo-field-lime.json +1 -0
  367. package/skills/agentvfx/templates/scope/xy-phosphor/demo-field-ultramarine.json +1 -0
  368. package/skills/agentvfx/templates/scope/xy-phosphor/demo-glow-phosphor.json +1 -0
  369. package/skills/agentvfx/templates/scope/xy-phosphor/demo-hud-black.json +1 -0
  370. package/skills/agentvfx/templates/scope/xy-phosphor/fx.json +642 -0
  371. package/skills/agentvfx/templates/scope/xy-phosphor/main.frag +33 -0
  372. package/skills/agentvfx/templates/scope/xy-phosphor/pass0.frag +56 -0
  373. package/skills/agentvfx/templates/scope/xy-phosphor/pass1.frag +44 -0
  374. package/skills/agentvfx/templates/scope/xy-phosphor/pass2.frag +12 -0
  375. package/skills/agentvfx/templates/scope/xy-phosphor/pass3.frag +12 -0
  376. package/skills/agentvfx/templates/scope/xy-phosphor/pass4.frag +12 -0
  377. package/skills/agentvfx/templates/scope/xy-phosphor/pass5.frag +12 -0
  378. package/skills/agentvfx/templates/scope/xy-phosphor/pass6.frag +251 -0
  379. package/skills/agentvfx/templates/spectrum/_src/bars-linear/fx.src.json +61 -0
  380. package/skills/agentvfx/templates/spectrum/_src/bars-linear/main.src.frag +112 -0
  381. package/skills/agentvfx/templates/spectrum/_src/bars-linear/pass0.src.frag +2 -0
  382. package/skills/agentvfx/templates/spectrum/_src/bars-mirror/fx.src.json +51 -0
  383. package/skills/agentvfx/templates/spectrum/_src/bars-mirror/main.src.frag +72 -0
  384. package/skills/agentvfx/templates/spectrum/_src/bars-mirror/pass0.src.frag +2 -0
  385. package/skills/agentvfx/templates/spectrum/_src/bass-circle/fx.src.json +56 -0
  386. package/skills/agentvfx/templates/spectrum/_src/bass-circle/main.src.frag +136 -0
  387. package/skills/agentvfx/templates/spectrum/_src/bass-circle/pass0.src.frag +2 -0
  388. package/skills/agentvfx/templates/spectrum/_src/build.mjs +68 -0
  389. package/skills/agentvfx/templates/spectrum/_src/label-bars/fx.src.json +54 -0
  390. package/skills/agentvfx/templates/spectrum/_src/label-bars/main.src.frag +102 -0
  391. package/skills/agentvfx/templates/spectrum/_src/label-bars/pass0.src.frag +2 -0
  392. package/skills/agentvfx/templates/spectrum/_src/shared/bars-fn.glsl +64 -0
  393. package/skills/agentvfx/templates/spectrum/_src/shared/bars-pass.glsl +22 -0
  394. package/skills/agentvfx/templates/spectrum/_src/shared/clock.glsl +7 -0
  395. package/skills/agentvfx/templates/spectrum/_src/shared/hud.glsl +50 -0
  396. package/skills/agentvfx/templates/spectrum/_src/shared/stage.glsl +74 -0
  397. package/skills/agentvfx/templates/spectrum/_src/spectrum-particles/fx.src.json +58 -0
  398. package/skills/agentvfx/templates/spectrum/_src/spectrum-particles/main.src.frag +119 -0
  399. package/skills/agentvfx/templates/spectrum/_src/spectrum-particles/pass0.src.frag +33 -0
  400. package/skills/agentvfx/templates/spectrum/_src/spectrum-radial/fx.src.json +56 -0
  401. package/skills/agentvfx/templates/spectrum/_src/spectrum-radial/main.src.frag +95 -0
  402. package/skills/agentvfx/templates/spectrum/_src/spectrum-radial/pass0.src.frag +2 -0
  403. package/skills/agentvfx/templates/spectrum/_src/waveform-line/fx.src.json +60 -0
  404. package/skills/agentvfx/templates/spectrum/_src/waveform-line/main.src.frag +98 -0
  405. package/skills/agentvfx/templates/spectrum/_src/waveform-line/pass0.src.frag +43 -0
  406. package/skills/agentvfx/templates/spectrum/bars-linear/demo-graph-acid.json +1 -0
  407. package/skills/agentvfx/templates/spectrum/bars-linear/demo-graph-black.json +1 -0
  408. package/skills/agentvfx/templates/spectrum/bars-linear/fx.json +632 -0
  409. package/skills/agentvfx/templates/spectrum/bars-linear/main.frag +233 -0
  410. package/skills/agentvfx/templates/spectrum/bars-linear/pass0.frag +91 -0
  411. package/skills/agentvfx/templates/spectrum/bars-mirror/demo-field-acid.json +1 -0
  412. package/skills/agentvfx/templates/spectrum/bars-mirror/demo-field-ultramarine.json +1 -0
  413. package/skills/agentvfx/templates/spectrum/bars-mirror/fx.json +539 -0
  414. package/skills/agentvfx/templates/spectrum/bars-mirror/main.frag +193 -0
  415. package/skills/agentvfx/templates/spectrum/bars-mirror/pass0.frag +91 -0
  416. package/skills/agentvfx/templates/spectrum/bass-circle/demo-bracket-black.json +1 -0
  417. package/skills/agentvfx/templates/spectrum/bass-circle/demo-bracket-ultramarine.json +1 -0
  418. package/skills/agentvfx/templates/spectrum/bass-circle/fx.json +552 -0
  419. package/skills/agentvfx/templates/spectrum/bass-circle/main.frag +258 -0
  420. package/skills/agentvfx/templates/spectrum/bass-circle/pass0.frag +91 -0
  421. package/skills/agentvfx/templates/spectrum/label-bars/demo-deck-black.json +1 -0
  422. package/skills/agentvfx/templates/spectrum/label-bars/demo-deck-ultramarine.json +1 -0
  423. package/skills/agentvfx/templates/spectrum/label-bars/fx.json +552 -0
  424. package/skills/agentvfx/templates/spectrum/label-bars/main.frag +223 -0
  425. package/skills/agentvfx/templates/spectrum/label-bars/pass0.frag +91 -0
  426. package/skills/agentvfx/templates/spectrum/spectrum-particles/demo-cloud-black.json +1 -0
  427. package/skills/agentvfx/templates/spectrum/spectrum-particles/demo-cloud-ultramarine.json +1 -0
  428. package/skills/agentvfx/templates/spectrum/spectrum-particles/fx.json +584 -0
  429. package/skills/agentvfx/templates/spectrum/spectrum-particles/main.frag +240 -0
  430. package/skills/agentvfx/templates/spectrum/spectrum-particles/pass0.frag +101 -0
  431. package/skills/agentvfx/templates/spectrum/spectrum-radial/demo-starburst-black.json +1 -0
  432. package/skills/agentvfx/templates/spectrum/spectrum-radial/demo-starburst-ultramarine.json +1 -0
  433. package/skills/agentvfx/templates/spectrum/spectrum-radial/fx.json +566 -0
  434. package/skills/agentvfx/templates/spectrum/spectrum-radial/main.frag +217 -0
  435. package/skills/agentvfx/templates/spectrum/spectrum-radial/pass0.frag +91 -0
  436. package/skills/agentvfx/templates/spectrum/waveform-line/demo-strip-acid.json +1 -0
  437. package/skills/agentvfx/templates/spectrum/waveform-line/demo-strip-black.json +1 -0
  438. package/skills/agentvfx/templates/spectrum/waveform-line/fx.json +481 -0
  439. package/skills/agentvfx/templates/spectrum/waveform-line/main.frag +219 -0
  440. package/skills/agentvfx/templates/spectrum/waveform-line/pass0.frag +48 -0
  441. package/skills/agentvfx/templates/spectrum/waveform-line/pass1.frag +86 -0
  442. package/skills/agentvfx/test/_render_light.mjs +38 -0
  443. package/skills/agentvfx/test/audio-stereo.test.mjs +45 -0
  444. package/skills/agentvfx/test/audio.test.mjs +257 -0
  445. package/skills/agentvfx/test/brutal.test.mjs +190 -0
  446. package/skills/agentvfx/test/concept-collage-layout.test.mjs +236 -0
  447. package/skills/agentvfx/test/concept-collage-scenes.test.mjs +305 -0
  448. package/skills/agentvfx/test/concept-collage-typefx.test.mjs +153 -0
  449. package/skills/agentvfx/test/concept-collage.test.mjs +84 -0
  450. package/skills/agentvfx/test/concept-lattice.test.mjs +133 -0
  451. package/skills/agentvfx/test/concept-signal-cut.test.mjs +172 -0
  452. package/skills/agentvfx/test/credit-overlay.test.mjs +58 -0
  453. package/skills/agentvfx/test/credit.test.mjs +54 -0
  454. package/skills/agentvfx/test/doctor.test.mjs +31 -0
  455. package/skills/agentvfx/test/encode.test.mjs +22 -0
  456. package/skills/agentvfx/test/fixtures/r7-collage-LAYOUTS.json +5780 -0
  457. package/skills/agentvfx/test/fixtures/score-bad-duration.json +7 -0
  458. package/skills/agentvfx/test/fixtures/score-bad-safety.json +8 -0
  459. package/skills/agentvfx/test/fixtures/score-identity-footage.json +8 -0
  460. package/skills/agentvfx/test/fixtures/score-missing-template.json +7 -0
  461. package/skills/agentvfx/test/fixtures/score-ok.json +8 -0
  462. package/skills/agentvfx/test/fixtures/score-strobe-12hz.json +8 -0
  463. package/skills/agentvfx/test/fixtures/score-text-probe.json +1 -0
  464. package/skills/agentvfx/test/flash-audit.test.mjs +150 -0
  465. package/skills/agentvfx/test/flash.test.mjs +83 -0
  466. package/skills/agentvfx/test/footage.test.mjs +88 -0
  467. package/skills/agentvfx/test/glitch.test.mjs +272 -0
  468. package/skills/agentvfx/test/impact.test.mjs +231 -0
  469. package/skills/agentvfx/test/imports.test.mjs +39 -0
  470. package/skills/agentvfx/test/light.test.mjs +200 -0
  471. package/skills/agentvfx/test/loop.test.mjs +80 -0
  472. package/skills/agentvfx/test/psychedelic.test.mjs +99 -0
  473. package/skills/agentvfx/test/render.test.mjs +73 -0
  474. package/skills/agentvfx/test/sacred.test.mjs +175 -0
  475. package/skills/agentvfx/test/schema.test.mjs +103 -0
  476. package/skills/agentvfx/test/scope.test.mjs +306 -0
  477. package/skills/agentvfx/test/spectrum.test.mjs +165 -0
  478. package/skills/agentvfx/test/text.test.mjs +142 -0
  479. package/skills/agentvfx/test/web.test.mjs +400 -0
  480. package/skills/agentvfx/test-media/SOURCES.md +39 -0
  481. package/skills/agentvfx/test-media/beat-132.mp3 +0 -0
  482. package/skills/agentvfx/test-media/clip-01.mp4 +0 -0
  483. package/skills/agentvfx/test-media/clip-02.mp4 +0 -0
@@ -0,0 +1,319 @@
1
+ // Raw WebGL2 plumbing: HDR render targets, full-screen shader passes, a compositor and Canvas2D
2
+ // layers uploaded as sRGB textures. Re-expressed without three.js from the mechanism of
3
+ // mexicat/pdoom-video app/src/engine/gl.ts (MIT, see ../NOTICE).
4
+ //
5
+ // Every look-library pass draws through `Pass.draw`, the one uniform-setter wrapper: it records
6
+ // the uniforms and counts draws per pass for the render log (MO-SH-00a), so no pass can draw
7
+ // without leaving a trace the gate can check.
8
+ import { GLSL_COMMON } from "./glsl-common.mjs";
9
+ import { SCALE, W, H, PW, PH } from "./scale.mjs";
10
+
11
+ export { SCALE, W, H, PW, PH };
12
+
13
+ const VERT = `#version 300 es
14
+ precision highp float;
15
+ out vec2 vUv;
16
+ void main() {
17
+ vec2 p = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
18
+ vUv = p;
19
+ gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);
20
+ }`;
21
+
22
+ /** Per-frame render-log recorder shared by every pass. */
23
+ export class Tracker {
24
+ constructor() {
25
+ this.frame = new Map();
26
+ this.recordUniforms = true;
27
+ }
28
+ reset() {
29
+ this.frame = new Map();
30
+ }
31
+ entry(pass) {
32
+ let e = this.frame.get(pass);
33
+ if (!e) {
34
+ e = { draws: 0, uniforms: {} };
35
+ this.frame.set(pass, e);
36
+ }
37
+ return e;
38
+ }
39
+ draw(pass, uniforms) {
40
+ const e = this.entry(pass);
41
+ e.draws += 1;
42
+ if (this.recordUniforms) {
43
+ for (const [name, value] of Object.entries(uniforms)) {
44
+ if (value && typeof value === "object" && value.isTexture) continue;
45
+ e.uniforms[name] = Array.isArray(value) ? value.map((v) => +(+v).toFixed(6)) : typeof value === "number" ? +value.toFixed(6) : value;
46
+ }
47
+ }
48
+ }
49
+ lines() {
50
+ return [...this.frame.entries()].map(([pass, e]) => ({ pass, draws: e.draws, uniforms: e.uniforms }));
51
+ }
52
+ }
53
+
54
+ export class GL {
55
+ constructor(canvas) {
56
+ const gl = canvas.getContext("webgl2", { antialias: false, alpha: false, depth: false, stencil: false, preserveDrawingBuffer: true, premultipliedAlpha: false, powerPreference: "high-performance" });
57
+ if (!gl) throw new Error("NO_WEBGL2: canvas.getContext('webgl2') returned null");
58
+ if (!gl.getExtension("EXT_color_buffer_float")) throw new Error("NO_WEBGL2: EXT_color_buffer_float is unavailable, so HDR render targets cannot be drawn");
59
+ this.gl = gl;
60
+ this.canvas = canvas;
61
+ this.vao = gl.createVertexArray();
62
+ this.tracker = new Tracker();
63
+ this.programs = new Map();
64
+ }
65
+
66
+ renderer() {
67
+ const gl = this.gl;
68
+ const ext = gl.getExtension("WEBGL_debug_renderer_info");
69
+ return ext ? String(gl.getParameter(ext.UNMASKED_RENDERER_WEBGL)) : "unknown (debug-info extension unavailable)";
70
+ }
71
+
72
+ /** A render target in physical px. `format` is "half" (RGBA16F, linear HDR) or "rgba8". */
73
+ target(width = PW, height = PH, format = "half") {
74
+ const gl = this.gl;
75
+ const tex = gl.createTexture();
76
+ gl.bindTexture(gl.TEXTURE_2D, tex);
77
+ if (format === "half") gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA16F, width, height);
78
+ else gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, width, height);
79
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
80
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
81
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
82
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
83
+ const fbo = gl.createFramebuffer();
84
+ gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
85
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
86
+ const status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
87
+ if (status !== gl.FRAMEBUFFER_COMPLETE) throw new Error(`framebuffer incomplete (${status}) for ${format} ${width}x${height}`);
88
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
89
+ return { fbo, tex: { isTexture: true, handle: tex }, width, height, format };
90
+ }
91
+
92
+ bind(target) {
93
+ const gl = this.gl;
94
+ gl.bindFramebuffer(gl.FRAMEBUFFER, target ? target.fbo : null);
95
+ gl.viewport(0, 0, target ? target.width : PW, target ? target.height : PH);
96
+ }
97
+
98
+ clear(target, rgb = [0, 0, 0], alpha = 0) {
99
+ const gl = this.gl;
100
+ this.bind(target);
101
+ gl.disable(gl.BLEND);
102
+ gl.clearColor(rgb[0], rgb[1], rgb[2], alpha);
103
+ gl.clear(gl.COLOR_BUFFER_BIT);
104
+ }
105
+
106
+ program(frag) {
107
+ const cached = this.programs.get(frag);
108
+ if (cached) return cached;
109
+ const gl = this.gl;
110
+ const compile = (type, source) => {
111
+ const shader = gl.createShader(type);
112
+ gl.shaderSource(shader, source);
113
+ gl.compileShader(shader);
114
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw new Error(`shader compile failed: ${gl.getShaderInfoLog(shader)}`);
115
+ return shader;
116
+ };
117
+ const fragSource = `#version 300 es\nprecision highp float;\nprecision highp int;\nin vec2 vUv;\nout vec4 fragColor;\n${GLSL_COMMON}\n${frag}`;
118
+ const program = gl.createProgram();
119
+ gl.attachShader(program, compile(gl.VERTEX_SHADER, VERT));
120
+ gl.attachShader(program, compile(gl.FRAGMENT_SHADER, fragSource));
121
+ gl.linkProgram(program);
122
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) throw new Error(`program link failed: ${gl.getProgramInfoLog(program)}`);
123
+ const uniforms = new Map();
124
+ const count = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
125
+ for (let i = 0; i < count; i++) {
126
+ const info = gl.getActiveUniform(program, i);
127
+ const name = info.name.replace(/\[0\]$/u, "");
128
+ uniforms.set(name, { location: gl.getUniformLocation(program, info.name), type: info.type, size: info.size });
129
+ }
130
+ const entry = { program, uniforms };
131
+ this.programs.set(frag, entry);
132
+ return entry;
133
+ }
134
+
135
+ setUniforms(entry, values) {
136
+ const gl = this.gl;
137
+ let unit = 0;
138
+ for (const [name, value] of Object.entries(values)) {
139
+ const u = entry.uniforms.get(name);
140
+ if (!u) continue;
141
+ const v = typeof value === "boolean" ? (value ? 1 : 0) : value;
142
+ switch (u.type) {
143
+ case gl.FLOAT: gl.uniform1f(u.location, v); break;
144
+ case gl.FLOAT_VEC2: gl.uniform2fv(u.location, v); break;
145
+ case gl.FLOAT_VEC3: gl.uniform3fv(u.location, v); break;
146
+ case gl.FLOAT_VEC4: gl.uniform4fv(u.location, v); break;
147
+ case gl.INT: case gl.BOOL: gl.uniform1i(u.location, v); break;
148
+ case gl.UNSIGNED_INT: gl.uniform1ui(u.location, v >>> 0); break;
149
+ case gl.SAMPLER_2D:
150
+ gl.activeTexture(gl.TEXTURE0 + unit);
151
+ gl.bindTexture(gl.TEXTURE_2D, v ? v.handle : null);
152
+ gl.uniform1i(u.location, unit);
153
+ unit += 1;
154
+ break;
155
+ default: throw new Error(`unsupported uniform type for ${name}`);
156
+ }
157
+ }
158
+ }
159
+
160
+ blend(mode) {
161
+ const gl = this.gl;
162
+ if (mode === "replace") {
163
+ gl.disable(gl.BLEND);
164
+ return;
165
+ }
166
+ gl.enable(gl.BLEND);
167
+ if (mode === "normal") {
168
+ // Premultiplied colour over the target; the target's alpha (glyph coverage) is kept.
169
+ gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
170
+ gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE);
171
+ } else if (mode === "glyph") {
172
+ // Glyph ink: colour over, coverage = max(target, glyph) so alpha carries the glyph mask.
173
+ gl.blendEquationSeparate(gl.FUNC_ADD, gl.MAX);
174
+ gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE);
175
+ } else if (mode === "add") {
176
+ gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
177
+ gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE);
178
+ } else throw new Error(`unknown blend mode ${mode}`);
179
+ }
180
+
181
+ /** Download a target's RGBA8 pixels through a pixel-pack buffer and a fence (no GPU stall). */
182
+ async readPixelsAsync(target, out) {
183
+ const gl = this.gl;
184
+ const bytes = target.width * target.height * 4;
185
+ const buffer = out ?? new Uint8Array(bytes);
186
+ if (!this.pbo || this.pboBytes !== bytes) {
187
+ if (this.pbo) gl.deleteBuffer(this.pbo);
188
+ this.pbo = gl.createBuffer();
189
+ gl.bindBuffer(gl.PIXEL_PACK_BUFFER, this.pbo);
190
+ gl.bufferData(gl.PIXEL_PACK_BUFFER, bytes, gl.STREAM_READ);
191
+ this.pboBytes = bytes;
192
+ }
193
+ this.bind(target);
194
+ gl.bindBuffer(gl.PIXEL_PACK_BUFFER, this.pbo);
195
+ gl.readPixels(0, 0, target.width, target.height, gl.RGBA, gl.UNSIGNED_BYTE, 0);
196
+ const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
197
+ gl.flush();
198
+ for (;;) {
199
+ const state = gl.clientWaitSync(sync, 0, 0);
200
+ if (state === gl.ALREADY_SIGNALED || state === gl.CONDITION_SATISFIED) break;
201
+ if (state === gl.WAIT_FAILED) throw new Error("clientWaitSync failed during pixel readback");
202
+ await new Promise((resolve) => setTimeout(resolve, 0));
203
+ }
204
+ gl.deleteSync(sync);
205
+ gl.getBufferSubData(gl.PIXEL_PACK_BUFFER, 0, buffer);
206
+ gl.bindBuffer(gl.PIXEL_PACK_BUFFER, null);
207
+ return buffer;
208
+ }
209
+ }
210
+
211
+ /**
212
+ * A full-screen fragment pass. `frag` declares its uniforms and writes `fragColor`; `vUv` (0..1,
213
+ * y up) and GLSL_COMMON are provided. `pass` names the look-library pass it belongs to (null for
214
+ * engine plumbing); only named passes are logged.
215
+ */
216
+ export class Pass {
217
+ constructor(glw, frag, { pass = null } = {}) {
218
+ this.glw = glw;
219
+ this.frag = frag;
220
+ this.pass = pass;
221
+ this.entry = glw.program(frag);
222
+ }
223
+ draw(target, uniforms = {}, { blend = "replace" } = {}) {
224
+ const { glw } = this;
225
+ const gl = glw.gl;
226
+ glw.bind(target);
227
+ gl.useProgram(this.entry.program);
228
+ glw.setUniforms(this.entry, uniforms);
229
+ glw.blend(blend);
230
+ gl.bindVertexArray(glw.vao);
231
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
232
+ gl.bindVertexArray(null);
233
+ if (this.pass) glw.tracker.draw(this.pass, uniforms);
234
+ }
235
+ }
236
+
237
+ const COMPOSITE_FRAG = /* glsl */ `
238
+ uniform sampler2D src; uniform float opacity; uniform vec3 tint;
239
+ void main() {
240
+ // Canvas2D layers are uploaded unpremultiplied as SRGB8_ALPHA8, so RGB arrives already linear
241
+ // and is premultiplied here.
242
+ vec4 c = texture(src, vUv);
243
+ float a = c.a * opacity;
244
+ fragColor = vec4(c.rgb * tint * a, a);
245
+ }`;
246
+
247
+ /** Draws a texture over a target: `normal` keeps the target's glyph mask, `glyph` adds to it. */
248
+ export class Compositor {
249
+ constructor(glw) {
250
+ this.pass = new Pass(glw, COMPOSITE_FRAG);
251
+ }
252
+ draw(texture, target, { mode = "normal", opacity = 1, tint = [1, 1, 1], logAs = null } = {}) {
253
+ this.pass.pass = logAs;
254
+ this.pass.draw(target, { src: texture, opacity, tint }, { blend: mode });
255
+ this.pass.pass = null;
256
+ }
257
+ }
258
+
259
+ /**
260
+ * A logical 1920x1080 Canvas2D surface uploaded as an sRGB texture. The context is CPU-backed
261
+ * (willReadFrequently) so its rasterization does not depend on GPU raster scheduling, and it is
262
+ * pre-scaled so drawing code works in logical px at every output scale.
263
+ */
264
+ export class Layer2D {
265
+ constructor(glw, width = W, height = H) {
266
+ this.glw = glw;
267
+ this.width = width;
268
+ this.height = height;
269
+ this.canvas = document.createElement("canvas");
270
+ this.canvas.width = Math.round(width * SCALE);
271
+ this.canvas.height = Math.round(height * SCALE);
272
+ this.ctx = this.canvas.getContext("2d", { willReadFrequently: true, alpha: true });
273
+ const gl = glw.gl;
274
+ this.handle = gl.createTexture();
275
+ gl.bindTexture(gl.TEXTURE_2D, this.handle);
276
+ gl.texStorage2D(gl.TEXTURE_2D, 1, gl.SRGB8_ALPHA8, this.canvas.width, this.canvas.height);
277
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
278
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
279
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
280
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
281
+ this.texture = { isTexture: true, handle: this.handle };
282
+ this.clear();
283
+ }
284
+ clear() {
285
+ const c = this.ctx;
286
+ c.setTransform(SCALE, 0, 0, SCALE, 0, 0);
287
+ c.globalAlpha = 1;
288
+ c.globalCompositeOperation = "source-over";
289
+ c.filter = "none";
290
+ c.shadowBlur = 0;
291
+ c.clearRect(0, 0, this.width, this.height);
292
+ }
293
+ upload() {
294
+ const gl = this.glw.gl;
295
+ gl.bindTexture(gl.TEXTURE_2D, this.handle);
296
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
297
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
298
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
299
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.canvas);
300
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
301
+ return this.texture;
302
+ }
303
+ /** Re-upload only a logical-px rectangle of the canvas (the rest of the texture is kept). */
304
+ uploadRegion(x, y, w, h) {
305
+ const gl = this.glw.gl;
306
+ const px = Math.max(0, Math.floor(x * SCALE));
307
+ const py = Math.max(0, Math.floor(y * SCALE));
308
+ const pw = Math.min(this.canvas.width - px, Math.ceil((x + w) * SCALE) - px);
309
+ const ph = Math.min(this.canvas.height - py, Math.ceil((y + h) * SCALE) - py);
310
+ const region = this.ctx.getImageData(px, py, pw, ph);
311
+ gl.bindTexture(gl.TEXTURE_2D, this.handle);
312
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
313
+ gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
314
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
315
+ gl.texSubImage2D(gl.TEXTURE_2D, 0, px, this.canvas.height - py - ph, pw, ph, gl.RGBA, gl.UNSIGNED_BYTE, region);
316
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
317
+ return this.texture;
318
+ }
319
+ }
@@ -0,0 +1,78 @@
1
+ // Shared GLSL ES 3.0 header prepended to every full-screen pass. Adapted in structure from
2
+ // mexicat/pdoom-video app/src/engine/glsl/common.ts (MIT, see ../NOTICE): output-scale-aware
3
+ // fragment coordinates, colour transfer helpers and pure noise. The noise here is this engine's
4
+ // own integer-hash value noise, seeded through `uint` uniforms (MO-SH-01), so every pass that needs
5
+ // randomness is a pure function of (pixel, seed, t).
6
+ import { SCALE } from "./scale.mjs";
7
+
8
+ export const GLSL_COMMON = /* glsl */ `
9
+ #define PI 3.14159265359
10
+ #define TAU 6.28318530718
11
+ const float PX_SCALE = ${SCALE.toFixed(1)};
12
+ #define FRAG_PX (gl_FragCoord.xy / PX_SCALE)
13
+ const vec2 LOGICAL = vec2(1920.0, 1080.0);
14
+
15
+ float sat(float x) { return clamp(x, 0.0, 1.0); }
16
+ vec3 sat(vec3 x) { return clamp(x, 0.0, 1.0); }
17
+ float luma(vec3 c) { return dot(c, vec3(0.2126, 0.7152, 0.0722)); }
18
+ mat2 rot2(float a) { float c = cos(a), s = sin(a); return mat2(c, -s, s, c); }
19
+
20
+ vec3 toSRGB(vec3 c) { c = max(c, 0.0); return mix(12.92 * c, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, c)); }
21
+ vec3 toLinear(vec3 c) { return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c)); }
22
+
23
+ // 32-bit integer hash (xorshift-multiply). Deterministic on every WebGL2 implementation because it
24
+ // only uses uint multiply, xor and shifts.
25
+ uint uhash(uint x) {
26
+ x ^= x >> 16u; x *= 0x7feb352du;
27
+ x ^= x >> 15u; x *= 0x846ca68bu;
28
+ x ^= x >> 16u;
29
+ return x;
30
+ }
31
+ uint uhash2(uvec2 v) { return uhash(v.x ^ uhash(v.y + 0x9e3779b9u)); }
32
+ uint uhash3(uvec3 v) { return uhash(v.x ^ uhash(v.y ^ uhash(v.z + 0x85ebca6bu))); }
33
+ float unit(uint h) { return float(h >> 8u) * (1.0 / 16777216.0); }
34
+ float hashCell(ivec2 c, uint seed) { return unit(uhash3(uvec3(uint(c.x), uint(c.y), seed))); }
35
+ float hashCell3(ivec3 c, uint seed) { return unit(uhash(uhash3(uvec3(c)) ^ seed)); }
36
+
37
+ vec2 quintic(vec2 t) { return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); }
38
+ vec3 quintic(vec3 t) { return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); }
39
+
40
+ // Value noise in [-1, 1].
41
+ float vnoise(vec2 p, uint seed) {
42
+ ivec2 i = ivec2(floor(p)); vec2 f = quintic(fract(p));
43
+ float a = hashCell(i, seed), b = hashCell(i + ivec2(1, 0), seed);
44
+ float c = hashCell(i + ivec2(0, 1), seed), d = hashCell(i + ivec2(1, 1), seed);
45
+ return mix(mix(a, b, f.x), mix(c, d, f.x), f.y) * 2.0 - 1.0;
46
+ }
47
+ float vnoise(vec3 p, uint seed) {
48
+ ivec3 i = ivec3(floor(p)); vec3 f = quintic(fract(p));
49
+ float n000 = hashCell3(i, seed), n100 = hashCell3(i + ivec3(1, 0, 0), seed);
50
+ float n010 = hashCell3(i + ivec3(0, 1, 0), seed), n110 = hashCell3(i + ivec3(1, 1, 0), seed);
51
+ float n001 = hashCell3(i + ivec3(0, 0, 1), seed), n101 = hashCell3(i + ivec3(1, 0, 1), seed);
52
+ float n011 = hashCell3(i + ivec3(0, 1, 1), seed), n111 = hashCell3(i + ivec3(1, 1, 1), seed);
53
+ float x00 = mix(n000, n100, f.x), x10 = mix(n010, n110, f.x), x01 = mix(n001, n101, f.x), x11 = mix(n011, n111, f.x);
54
+ return mix(mix(x00, x10, f.y), mix(x01, x11, f.y), f.z) * 2.0 - 1.0;
55
+ }
56
+ float fbm(vec3 p, int octaves, uint seed) {
57
+ float sum = 0.0, amp = 0.5;
58
+ for (int i = 0; i < 8; i++) {
59
+ if (i >= octaves) break;
60
+ sum += amp * vnoise(p, seed + uint(i) * 101u);
61
+ p = p * 2.02 + vec3(17.1, 9.3, 4.7);
62
+ amp *= 0.5;
63
+ }
64
+ return sum;
65
+ }
66
+ // Divergence-free flow direction from the gradient of a scalar noise field.
67
+ vec2 curl(vec2 p, float z, uint seed) {
68
+ const float e = 0.02;
69
+ float n1 = vnoise(vec3(p + vec2(0.0, e), z), seed), n2 = vnoise(vec3(p - vec2(0.0, e), z), seed);
70
+ float n3 = vnoise(vec3(p + vec2(e, 0.0), z), seed), n4 = vnoise(vec3(p - vec2(e, 0.0), z), seed);
71
+ return vec2(n1 - n2, n4 - n3) / (2.0 * e);
72
+ }
73
+
74
+ // Ordered-dither thresholds in [0, 1).
75
+ float bayer2(ivec2 p) { int x = p.x & 1, y = p.y & 1; return float((x ^ y) * 2 + y) / 4.0; }
76
+ float bayer4(ivec2 p) { return (bayer2(p / 2) + bayer2(p) * 4.0) / 4.0; }
77
+ float bayer8(ivec2 p) { return (bayer4(p / 2) + bayer2(p) * 16.0) / 4.0; }
78
+ `;
@@ -0,0 +1,23 @@
1
+ // agentvfx (Apache-2.0, see LICENSE). Injected before any page script: the page has no wall clock and no
2
+ // unseeded randomness. Math.random is a seeded mulberry32; Date and performance.now are frozen at 0
3
+ // (time comes only from the frame index the host passes to window.__litStep).
4
+ (() => {
5
+ let s = __LIT_SEED__ >>> 0;
6
+ const rand = () => {
7
+ s = (s + 0x6d2b79f5) >>> 0;
8
+ let t = s;
9
+ t = Math.imul(t ^ (t >>> 15), t | 1);
10
+ t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
11
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
12
+ };
13
+ Object.defineProperty(Math, "random", { value: rand, writable: false, configurable: false });
14
+ const RealDate = Date;
15
+ class FrozenDate extends RealDate {
16
+ constructor(...a) { super(...(a.length ? a : [0])); }
17
+ static now() { return 0; }
18
+ }
19
+ window.Date = FrozenDate;
20
+ if (window.performance) Object.defineProperty(window.performance, "now", { value: () => 0, configurable: false });
21
+ window.requestAnimationFrame = () => { throw new Error("requestAnimationFrame is not available on the render page"); };
22
+ window.__LIT_SEED = __LIT_SEED__ >>> 0;
23
+ })();
@@ -0,0 +1,150 @@
1
+ // agentvfx (Apache-2.0, see LICENSE). The GLSL prelude prepended to every template pass, and the program source
2
+ // builder. Contract: references/template-format.md. Importable in Node (tests) and in the page.
3
+ // Helper credits: value noise and fbm after The Book of Shaders ch.11/13 (https://thebookofshaders.com),
4
+ // cosine palette after Inigo Quilez (https://iquilezles.org/articles/palettes/), hsv conversions after
5
+ // Sam Hocevar's public-domain formulation; all re-written here.
6
+
7
+ /** Score seed (integer) -> SEED uniform in [0, 1): an integer hash so nearby seeds give unrelated values. */
8
+ export function seedToUnit(seed) {
9
+ let x = seed >>> 0;
10
+ x ^= x >>> 16;
11
+ x = Math.imul(x, 0x7feb352d) >>> 0;
12
+ x ^= x >>> 15;
13
+ x = Math.imul(x, 0x846ca68b) >>> 0;
14
+ x ^= x >>> 16;
15
+ return (x >>> 0) / 4294967296;
16
+ }
17
+
18
+ export const VERT = `#version 300 es
19
+ precision highp float;
20
+ out vec2 vUv;
21
+ void main() {
22
+ vec2 p = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
23
+ vUv = p;
24
+ gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);
25
+ }`;
26
+
27
+ export const PRELUDE_HEAD = `#version 300 es
28
+ precision highp float;
29
+ precision highp int;
30
+ precision highp sampler2D;
31
+ in vec2 vUv;
32
+ out vec4 fragColor;
33
+ uniform float TIME;
34
+ uniform float TIMEDELTA;
35
+ uniform int FRAMEINDEX;
36
+ uniform int PASSINDEX;
37
+ uniform vec2 RENDERSIZE;
38
+ uniform float SEED;
39
+ uniform sampler2D inputImage;
40
+ uniform bool HAS_INPUT;
41
+ uniform vec3 PALETTE[8];
42
+ uniform int PALETTE_COUNT;
43
+ uniform float AUDIO_RMS, AUDIO_PEAK, AUDIO_BASS, AUDIO_MID, AUDIO_TREB, AUDIO_BASS_ATT, AUDIO_MID_ATT,
44
+ AUDIO_TREB_ATT, AUDIO_FLUX, AUDIO_ONSET, AUDIO_BEAT, AUDIO_BEATPHASE, AUDIO_BPM;
45
+ uniform sampler2D audio;
46
+ uniform sampler2D audioFFT;
47
+ uniform float AUDIO_BANDS[32];
48
+ uniform sampler2D TEXTMASK; // engine text layer: R = glyph/line ink, G = solid box/bar fill (0..1); items with channel g or b draw their glyph ink into G or B
49
+ uniform bool HAS_TEXT;
50
+ #define isf_FragNormCoord vUv
51
+ #define IMG_NORM_PIXEL(img, uv) texture(img, uv)
52
+ #define IMG_THIS_NORM_PIXEL(img) texture(img, vUv)
53
+ #define IMG_PIXEL(img, px) texture(img, (px) / vec2(textureSize(img, 0)))
54
+ #define IMG_THIS_PIXEL(img) texture(img, vUv)
55
+ #define IMG_SIZE(img) vec2(textureSize(img, 0))
56
+ `;
57
+
58
+ export const PRELUDE_HELPERS = `
59
+ float hash12(vec2 p) {
60
+ vec3 p3 = fract(vec3(p.xyx) * 0.1031 + SEED * 17.17);
61
+ p3 += dot(p3, p3.yzx + 33.33);
62
+ return fract((p3.x + p3.y) * p3.z);
63
+ }
64
+ vec2 hash22(vec2 p) {
65
+ vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973) + SEED * 17.17);
66
+ p3 += dot(p3, p3.yzx + 33.33);
67
+ return fract((p3.xx + p3.yz) * p3.zy);
68
+ }
69
+ float vnoise(vec2 p) {
70
+ vec2 i = floor(p);
71
+ vec2 f = fract(p);
72
+ vec2 u = f * f * (3.0 - 2.0 * f);
73
+ float a = hash12(i);
74
+ float b = hash12(i + vec2(1.0, 0.0));
75
+ float c = hash12(i + vec2(0.0, 1.0));
76
+ float d = hash12(i + vec2(1.0, 1.0));
77
+ return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
78
+ }
79
+ float fbm(vec2 p, int octaves) {
80
+ float v = 0.0;
81
+ float a = 0.5;
82
+ float norm = 0.0;
83
+ for (int i = 0; i < 8; i++) {
84
+ if (i >= octaves) break;
85
+ v += a * vnoise(p);
86
+ norm += a;
87
+ p = mat2(1.6, 1.2, -1.2, 1.6) * p + 7.31;
88
+ a *= 0.5;
89
+ }
90
+ return norm > 0.0 ? v / norm : 0.0;
91
+ }
92
+ float luma(vec3 c) { return dot(c, vec3(0.2126, 0.7152, 0.0722)); }
93
+ vec3 rgb2hsv(vec3 c) {
94
+ vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
95
+ vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
96
+ vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
97
+ float d = q.x - min(q.w, q.y);
98
+ float e = 1.0e-10;
99
+ return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
100
+ }
101
+ vec3 hsv2rgb(vec3 c) {
102
+ vec3 p = abs(fract(c.xxx + vec3(1.0, 2.0 / 3.0, 1.0 / 3.0)) * 6.0 - 3.0);
103
+ return c.z * mix(vec3(1.0), clamp(p - 1.0, 0.0, 1.0), c.y);
104
+ }
105
+ vec3 cosPalette(float t, vec3 a, vec3 b, vec3 c, vec3 d) { return a + b * cos(6.28318530718 * (c * t + d)); }
106
+ vec3 paletteRamp(float t) {
107
+ int n = max(PALETTE_COUNT, 1);
108
+ if (n == 1) return PALETTE[0];
109
+ float x = clamp(t, 0.0, 1.0) * float(n - 1);
110
+ int i = int(floor(x));
111
+ int j = min(i + 1, n - 1);
112
+ return mix(PALETTE[i], PALETTE[j], x - float(i));
113
+ }
114
+ vec3 paletteCycle(float t) {
115
+ int n = max(PALETTE_COUNT, 1);
116
+ float x = fract(t) * float(n);
117
+ int i = int(floor(x)) % n;
118
+ int j = (i + 1) % n;
119
+ return mix(PALETTE[i], PALETTE[j], x - floor(x));
120
+ }
121
+ vec3 srgbToLinear(vec3 c) { return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c)); }
122
+ vec3 linearToSrgb(vec3 c) { c = max(c, 0.0); return mix(c * 12.92, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, c)); }
123
+ mat2 rot(float a) { float c = cos(a); float s = sin(a); return mat2(c, s, -s, c); }
124
+ `;
125
+
126
+ const UNIFORM_TYPE = { float: "float", long: "int", bool: "bool", color: "vec4", point2D: "vec2", image: "sampler2D", audio: "sampler2D", audioFFT: "sampler2D" };
127
+
128
+ /** Fragment source for one pass: prelude + input uniforms + target samplers + the template body. */
129
+ export function buildFragment({ inputs = [], targets = [], body }) {
130
+ const decl = inputs.filter((i) => UNIFORM_TYPE[i.TYPE] && !["inputImage", "audio", "audioFFT"].includes(i.NAME))
131
+ .map((i) => `uniform ${UNIFORM_TYPE[i.TYPE]} ${i.NAME};`);
132
+ const tdecl = targets.map((t) => `uniform sampler2D ${t};`);
133
+ return `${PRELUDE_HEAD}${decl.join("\n")}\n${tdecl.join("\n")}\n${PRELUDE_HELPERS}\n#line 1\n${body}\n`;
134
+ }
135
+
136
+ /** The output pass: linear light -> sRGB with a seeded sub-LSB dither, drawn to the canvas. */
137
+ export const OUTPUT_FRAG = `#version 300 es
138
+ precision highp float;
139
+ in vec2 vUv;
140
+ out vec4 fragColor;
141
+ uniform sampler2D src;
142
+ uniform int FRAMEINDEX;
143
+ uniform float SEED;
144
+ float h(vec2 p) { vec3 p3 = fract(vec3(p.xyx) * 0.1031 + SEED * 3.7); p3 += dot(p3, p3.yzx + 33.33); return fract((p3.x + p3.y) * p3.z); }
145
+ vec3 toSrgb(vec3 c) { c = clamp(c, 0.0, 1.0); return mix(c * 12.92, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, c)); }
146
+ void main() {
147
+ vec3 c = toSrgb(texture(src, vUv).rgb);
148
+ float d = h(gl_FragCoord.xy + float(FRAMEINDEX % 64) * 7.0) - 0.5;
149
+ fragColor = vec4(c + d / 255.0, 1.0);
150
+ }`;
@@ -0,0 +1,11 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <style>html, body { margin: 0; padding: 0; background: #000; overflow: hidden; } canvas { display: block; }</style>
6
+ </head>
7
+ <body>
8
+ <canvas id="c"></canvas>
9
+ <script type="module" src="/lit/engine/render.mjs"></script>
10
+ </body>
11
+ </html>