agentvfx 0.0.0-stage → 0.3.4

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 +172 -0
  4. package/README.md +236 -2
  5. package/package.json +35 -4
  6. package/skills/agentvfx/LICENSE +172 -0
  7. package/skills/agentvfx/NOTICE +44 -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 +28 -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 +155 -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 +42 -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 +397 -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,97 @@
1
+ // agentvfx (agentvfx licence, see LICENSE). Collage layout as data: up to 16 cells on a 32 x 18 grid, validated here and packed
2
+ // into the template's integer inputs. Three ints per cell:
3
+ // cellN = role * 1e8 + x * 1e6 + y * 1e4 + w * 100 + h (RRXXYYWWHH, plain decimal)
4
+ // styleN = variant * 1e4 + tone * 1e3 + fill * 100 + frame * 10 + rot
5
+ // srcN = sheet * 1e6 + scale * 10 * 1e4 + (src.x + 10) * 2 * 100 + (src.y + 10) * 2 (text-sheet window; 0 = unused)
6
+ // A cell is { x, y, w, h, role } plus optional { frame, fill, tone, variant, rot, src: { x, y, scale, sheet } }.
7
+ // Role "typefx" is warped type (variant 1 micro-type field, 2 glyph window, 3 slit-scan word, 4 echo stack, 5 echo ripple, 6 type equalizer);
8
+ // `src.sheet` picks which text-sheet channel a type or typefx cell reads: "r" (default, the editorial sheet), "g" or "b".
9
+ // Role "scene" is a whole mixed-material composition (variant 1 specimen, 2 wiring, 3 field-cut, 4 pattern-sheet) that fills its cell;
10
+ // it reads its own text set (the template input textSet) and the tint colours.
11
+ // Cells are drawn in list order, later on top, and may overlap unless both are frame "tile" (the old boxed panel).
12
+ export const GRID = Object.freeze({ cols: 32, rows: 18 });
13
+ export const MAX_CELLS = 16;
14
+ export const ROLES = Object.freeze({ footage: 1, spectrum: 2, scope: 3, meter: 4, readout: 5, crosshair: 6, ruler: 7, plate: 8, hatch: 9, pixels: 10, type: 11, rule: 12, typefx: 13, scene: 14 });
15
+ export const SHEETS = Object.freeze({ r: 0, g: 1, b: 2 });
16
+ export const FRAMES = Object.freeze({ tile: 0, none: 1, hairline: 2, corners: 3 });
17
+ export const FILLS = Object.freeze({ none: 0, ground: 1, ink: 2, accent: 3 });
18
+ export const TONES = Object.freeze({ ink: 0, ground: 1, accent: 2 });
19
+ export const ROTS = Object.freeze([0, 1, 2]);
20
+ const CELL_KEYS = Object.freeze(["x", "y", "w", "h", "role", "frame", "fill", "tone", "variant", "rot", "src"]);
21
+ const SRC_KEYS = Object.freeze(["x", "y", "scale", "sheet"]);
22
+ const isInt = (v) => Number.isInteger(v);
23
+ const isHalf = (v) => Number.isFinite(v) && Number.isInteger(v * 2);
24
+
25
+ /** A layouts.json entry is either a bare cell list (old form) or { cells, params?, description? }. */
26
+ export const layoutCells = (entry) => (Array.isArray(entry) ? entry : entry?.cells);
27
+
28
+ /** Returns a list of { path, message } errors; an empty list means the layout is valid. */
29
+ export function checkLayout(entry) {
30
+ const cells = layoutCells(entry);
31
+ const errors = [];
32
+ const err = (path, message) => errors.push({ path, message });
33
+ if (!Array.isArray(cells) || cells.length < 1 || cells.length > MAX_CELLS) {
34
+ err("", `layout must be a list of 1 to ${MAX_CELLS} cells`);
35
+ return errors;
36
+ }
37
+ const ok = [];
38
+ cells.forEach((c, i) => {
39
+ const p = `[${i}]`;
40
+ if (c === null || typeof c !== "object" || Array.isArray(c)) return err(p, "must be an object { x, y, w, h, role }");
41
+ for (const k of Object.keys(c)) if (!CELL_KEYS.includes(k)) err(`${p}.${k}`, `unknown key (allowed: ${CELL_KEYS.join(", ")})`);
42
+ if (!Object.hasOwn(ROLES, c.role)) err(`${p}.role`, `must be one of ${Object.keys(ROLES).join(", ")}`);
43
+ if (c.frame !== undefined && !Object.hasOwn(FRAMES, c.frame)) err(`${p}.frame`, `must be one of ${Object.keys(FRAMES).join(", ")}`);
44
+ if (c.fill !== undefined && !Object.hasOwn(FILLS, c.fill)) err(`${p}.fill`, `must be one of ${Object.keys(FILLS).join(", ")}`);
45
+ if (c.tone !== undefined && !Object.hasOwn(TONES, c.tone)) err(`${p}.tone`, `must be one of ${Object.keys(TONES).join(", ")}`);
46
+ if (c.variant !== undefined && !(isInt(c.variant) && c.variant >= 0 && c.variant <= 9)) err(`${p}.variant`, "must be an integer 0..9");
47
+ if (c.rot !== undefined && !ROTS.includes(c.rot)) err(`${p}.rot`, "must be 0, 1 (text reads upward) or 2 (text reads downward)");
48
+ if (c.src !== undefined) checkSrc(c.src, `${p}.src`, err);
49
+ const dims = CELL_KEYS.slice(0, 4);
50
+ for (const k of dims) if (!isInt(c[k])) err(`${p}.${k}`, "must be an integer grid unit");
51
+ if (!dims.every((k) => isInt(c[k]))) return;
52
+ if (c.x < 0 || c.y < 0) err(p, "x and y must be >= 0");
53
+ if (c.w < 1 || c.h < 1) err(p, "w and h must be >= 1");
54
+ if (c.x + c.w > GRID.cols) err(p, `out of bounds: x + w = ${c.x + c.w} > ${GRID.cols}`);
55
+ if (c.y + c.h > GRID.rows) err(p, `out of bounds: y + h = ${c.y + c.h} > ${GRID.rows}`);
56
+ ok.push([i, c]);
57
+ });
58
+ const tile = (c) => (c.frame ?? "tile") === "tile";
59
+ for (let a = 0; a < ok.length; a++) {
60
+ for (let b = a + 1; b < ok.length; b++) {
61
+ const [i, p] = ok[a];
62
+ const [j, q] = ok[b];
63
+ if (tile(p) && tile(q) && p.x < q.x + q.w && q.x < p.x + p.w && p.y < q.y + q.h && q.y < p.y + p.h) err(`[${j}]`, `overlaps cell [${i}] (only cells with frame none, hairline or corners may overlap)`);
64
+ }
65
+ }
66
+ return errors;
67
+ }
68
+
69
+ function checkSrc(s, path, err) {
70
+ if (s === null || typeof s !== "object" || Array.isArray(s)) return err(path, "must be an object { x, y, scale, sheet }");
71
+ if (s.sheet !== undefined && !Object.hasOwn(SHEETS, s.sheet)) err(`${path}.sheet`, `must be one of ${Object.keys(SHEETS).join(", ")}`);
72
+ for (const k of Object.keys(s)) if (!SRC_KEYS.includes(k)) err(`${path}.${k}`, `unknown key (allowed: ${SRC_KEYS.join(", ")})`);
73
+ for (const k of ["x", "y"]) if (s[k] !== undefined && !(isHalf(s[k]) && s[k] >= -10 && s[k] <= 39.5)) err(`${path}.${k}`, "must be a multiple of 0.5 between -10 and 39.5 (grid units of the text sheet)");
74
+ if (s.scale !== undefined && !(Number.isFinite(s.scale) && Number.isInteger(Math.round(s.scale * 10)) && Math.abs(s.scale * 10 - Math.round(s.scale * 10)) < 1e-9 && s.scale >= 0.1 && s.scale <= 9.9)) err(`${path}.scale`, "must be 0.1 steps between 0.1 and 9.9");
75
+ }
76
+
77
+ /** One cell -> the packed decimal integer (0 stays 0 = empty slot). */
78
+ export const packCell = (c) => ROLES[c.role] * 100000000 + c.x * 1000000 + c.y * 10000 + c.w * 100 + c.h;
79
+ export const packStyle = (c) => (c.variant ?? 0) * 10000 + TONES[c.tone ?? "ink"] * 1000 + FILLS[c.fill ?? "none"] * 100 + FRAMES[c.frame ?? "tile"] * 10 + (c.rot ?? 0);
80
+ export const packSrc = (c) => {
81
+ if (c.src === undefined && c.role !== "type" && c.role !== "typefx") return 0;
82
+ const s = { x: 0, y: 0, scale: 1, sheet: "r", ...c.src };
83
+ return SHEETS[s.sheet] * 1000000 + Math.round(s.scale * 10) * 10000 + Math.round((s.x + 10) * 2) * 100 + Math.round((s.y + 10) * 2);
84
+ };
85
+
86
+ /** A valid layout -> { cell0.., style0.., src0.. } score params (unused slots are 0). Throws on an invalid layout. */
87
+ export function layoutToParams(entry) {
88
+ const errors = checkLayout(entry);
89
+ if (errors.length) throw new Error(`invalid collage layout: ${errors.map((e) => `${e.path} ${e.message}`).join("; ")}`);
90
+ const cells = layoutCells(entry);
91
+ const slots = Array.from({ length: MAX_CELLS }, (_, k) => cells[k]);
92
+ return {
93
+ ...Object.fromEntries(slots.map((c, k) => [`cell${k}`, c ? packCell(c) : 0])),
94
+ ...Object.fromEntries(slots.map((c, k) => [`style${k}`, c ? packStyle(c) : 0])),
95
+ ...Object.fromEntries(slots.map((c, k) => [`src${k}`, c ? packSrc(c) : 0])),
96
+ };
97
+ }
@@ -0,0 +1,366 @@
1
+ {
2
+ "poster": {
3
+ "description": "Full-bleed footage, one giant cropped word whose letters fill with vermilion on the rms, a single hairline spectrum standing on the word's cap line, captions, a cut counter and a registration mark in the margins.",
4
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.016,"footageScan":0,"footageSat":0.6,"footageContrast":1.1,"groundColor":[0.045,0.045,0.05,1],"inkColor":[0.93,0.92,0.88,1],"accentColor":[0.9,0.22,0.08,1]},
5
+ "cells": [
6
+ {"x":0,"y":0,"w":32,"h":18,"role":"footage","frame":"none","variant":5},
7
+ {"x":0,"y":8,"w":30,"h":10,"role":"type","frame":"none","variant":4,"src":{"x":0,"y":-1.5,"scale":1.6}},
8
+ {"x":0,"y":7,"w":32,"h":6,"role":"spectrum","frame":"none","variant":1},
9
+ {"x":1,"y":1,"w":9,"h":3,"role":"type","frame":"none","src":{"x":26,"y":0,"scale":1}},
10
+ {"x":23,"y":1,"w":8,"h":2,"role":"type","frame":"none","src":{"x":26,"y":4,"scale":1}},
11
+ {"x":1,"y":4,"w":1,"h":1,"role":"readout","frame":"none","variant":2},
12
+ {"x":29,"y":3,"w":2,"h":2,"role":"crosshair","frame":"none","variant":1}
13
+ ]
14
+ },
15
+ "spread": {
16
+ "description": "Magazine spread: footage fills the left page, the right page is a bone sheet with a serif headline that a vermilion bar sweeps on every onset, a small mono paragraph, four thin level bars and a vertical spine; one vermilion scope line runs across both pages.",
17
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":0.65,"groundColor":[0.05,0.05,0.055,1],"inkColor":[0.92,0.9,0.85,1],"accentColor":[0.9,0.22,0.08,1]},
18
+ "cells": [
19
+ {"x":0,"y":0,"w":16,"h":18,"role":"footage","frame":"none","variant":4},
20
+ {"x":16,"y":0,"w":16,"h":18,"role":"rule","frame":"none","fill":"ink"},
21
+ {"x":18,"y":2,"w":12,"h":8,"role":"type","frame":"none","tone":"ground","variant":5,"src":{"x":0,"y":9,"scale":1.4}},
22
+ {"x":18,"y":10,"w":12,"h":1,"role":"rule","frame":"none","tone":"ground","variant":1},
23
+ {"x":18,"y":11,"w":10,"h":4,"role":"type","frame":"none","tone":"ground","src":{"x":10,"y":9,"scale":1.2}},
24
+ {"x":16,"y":1,"w":1,"h":14,"role":"type","frame":"none","tone":"ground","rot":1,"src":{"x":0,"y":15.5,"scale":1}},
25
+ {"x":28,"y":11,"w":3,"h":4,"role":"meter","frame":"none","tone":"ground","variant":1},
26
+ {"x":0,"y":15,"w":32,"h":3,"role":"scope","frame":"none","variant":1},
27
+ {"x":1,"y":1,"w":2,"h":2,"role":"crosshair","frame":"none","variant":1},
28
+ {"x":25,"y":1,"w":4,"h":2,"role":"type","frame":"none","tone":"ground","src":{"x":26,"y":4,"scale":1}},
29
+ {"x":30,"y":1,"w":1,"h":1,"role":"readout","frame":"none","tone":"ground","variant":2}
30
+ ]
31
+ },
32
+ "index": {
33
+ "description": "Catalogue card on bone paper: a giant tall numeral that fills with vermilion on the rms, a small footage plate inside crop marks, a ruled field table whose rows carry four thin live level bars, a comb spectrum and a registration mark.",
34
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.01,"footageScan":0,"footageSat":0.85,"groundColor":[0.91,0.89,0.83,1],"inkColor":[0.07,0.07,0.075,1],"accentColor":[0.9,0.22,0.08,1]},
35
+ "cells": [
36
+ {"x":1,"y":2,"w":9,"h":13,"role":"type","frame":"none","variant":4,"src":{"x":19,"y":0,"scale":1.5}},
37
+ {"x":12,"y":2,"w":16,"h":8,"role":"footage","frame":"none"},
38
+ {"x":11,"y":1,"w":18,"h":10,"role":"rule","frame":"corners"},
39
+ {"x":12,"y":11,"w":16,"h":4,"role":"rule","frame":"none","variant":8},
40
+ {"x":12,"y":11,"w":10,"h":4,"role":"type","frame":"none","src":{"x":19,"y":9,"scale":1}},
41
+ {"x":23,"y":11,"w":5,"h":1,"role":"rule","frame":"none","variant":4},
42
+ {"x":23,"y":12,"w":5,"h":1,"role":"rule","frame":"none","variant":5},
43
+ {"x":23,"y":13,"w":5,"h":1,"role":"rule","frame":"none","variant":6},
44
+ {"x":23,"y":14,"w":5,"h":1,"role":"rule","frame":"none","variant":7},
45
+ {"x":12,"y":15,"w":16,"h":3,"role":"spectrum","frame":"none","variant":2},
46
+ {"x":29,"y":15,"w":2,"h":2,"role":"crosshair","frame":"none","variant":1},
47
+ {"x":1,"y":15,"w":10,"h":3,"role":"type","frame":"none","src":{"x":26,"y":0,"scale":1}},
48
+ {"x":1,"y":1,"w":4,"h":2,"role":"type","frame":"none","src":{"x":26,"y":4,"scale":1}}
49
+ ]
50
+ },
51
+ "glyph-flood": {
52
+ "description": "Experimental type: one monstrous letter (sheet word `mega`, default A, Monument Extended) cropped by the frame, footage seen through it, a hard vermilion extrusion behind it, a flood of MesloLGS NF micro-type over everything whose rows are the spectrum, a giant vermilion numeral colliding with the letter. On the beat the letter tears into horizontal slices; on every onset it stretches taller and its extrusion jumps out.",
53
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.02,"footageScan":0,"footageSat":0.55,"footageContrast":1.2,"groundColor":[0.04,0.04,0.045,1],"inkColor":[0.93,0.92,0.88,1],"accentColor":[0.9,0.22,0.08,1]},
54
+ "cells": [
55
+ {"x":0,"y":0,"w":32,"h":18,"role":"footage","frame":"none","variant":6},
56
+ {"x":0,"y":0,"w":32,"h":18,"role":"typefx","frame":"none","variant":1,"src":{"x":0,"y":0,"scale":1,"sheet":"b"}},
57
+ {"x":0,"y":0,"w":14,"h":18,"role":"type","frame":"none","tone":"accent","src":{"x":19.5,"y":0.5,"scale":2.4}},
58
+ {"x":1,"y":1,"w":9,"h":3,"role":"type","frame":"none","src":{"x":26,"y":0,"scale":1},"fill":"ground"},
59
+ {"x":2,"y":0,"w":29,"h":18,"role":"typefx","frame":"none","variant":2,"src":{"x":-1,"y":0.5,"scale":2.5,"sheet":"g"}},
60
+ {"x":30,"y":1,"w":1,"h":15,"role":"type","frame":"none","rot":1,"src":{"x":0,"y":15.5,"scale":1},"tone":"accent"},
61
+ {"x":25,"y":16,"w":5,"h":1,"role":"rule","frame":"none","fill":"ground"},
62
+ {"x":25,"y":16,"w":5,"h":1,"role":"readout","frame":"none","variant":3}
63
+ ]
64
+ },
65
+ "glyph-flood-ko": {
66
+ "description": "Experimental type, paper version in Hangul: one giant Pretendard syllable (sheet word `megaK`, default light, 빛) with footage seen through it and a hard vermilion extrusion, over a flood of Pretendard micro-type, a caption and a spine. Same tearing, stretching and extrusion reactions as glyph-flood on a bone ground.",
67
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.016,"footageScan":0,"footageSat":0.5,"footageContrast":1.25,"groundColor":[0.91,0.89,0.83,1],"inkColor":[0.06,0.06,0.065,1],"accentColor":[0.9,0.22,0.08,1],"typeWarp":0.6},
68
+ "cells": [
69
+ {"x":0,"y":0,"w":32,"h":18,"role":"typefx","frame":"none","variant":1,"src":{"x":0,"y":0,"scale":1,"sheet":"g"}},
70
+ {"x":1,"y":1,"w":9,"h":3,"role":"type","frame":"none","src":{"x":26,"y":0,"scale":1},"fill":"ground"},
71
+ {"x":9,"y":0,"w":21,"h":18,"role":"typefx","frame":"none","variant":2,"src":{"x":21.5,"y":0,"scale":2.4,"sheet":"g"}},
72
+ {"x":30,"y":1,"w":1,"h":15,"role":"type","frame":"none","rot":1,"src":{"x":0,"y":15.5,"scale":1}},
73
+ {"x":26,"y":16,"w":4,"h":1,"role":"readout","frame":"none","variant":3}
74
+ ]
75
+ },
76
+ "glyph-flood-solid": {
77
+ "description": "Experimental type, flat colour version: a huge Monument Extended ampersand (sheet word `mega2`) filled with solid vermilion instead of footage (tone accent), a bone extrusion behind it, the footage only a dark ghost, hairline rules and a MesloLGS NF micro-type flood. Same tearing, stretching and extrusion reactions.",
78
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.016,"footageScan":0,"footageSat":0.5,"footageContrast":1.2,"groundColor":[0.04,0.04,0.045,1],"inkColor":[0.93,0.92,0.88,1],"accentColor":[0.9,0.22,0.08,1],"typeWarp":0.6},
79
+ "cells": [
80
+ {"x":0,"y":0,"w":32,"h":18,"role":"footage","frame":"none","variant":6},
81
+ {"x":0,"y":0,"w":32,"h":18,"role":"typefx","frame":"none","variant":1,"src":{"x":0,"y":0,"scale":1,"sheet":"b"}},
82
+ {"x":0,"y":3,"w":32,"h":1,"role":"rule","frame":"none","variant":1},
83
+ {"x":0,"y":15,"w":32,"h":1,"role":"rule","frame":"none","variant":1},
84
+ {"x":3,"y":0,"w":23,"h":18,"role":"typefx","frame":"none","variant":2,"src":{"x":10.5,"y":0,"scale":2.3,"sheet":"g"},"tone":"accent"},
85
+ {"x":1,"y":1,"w":9,"h":3,"role":"type","frame":"none","src":{"x":26,"y":0,"scale":1},"fill":"ground"},
86
+ {"x":22,"y":16,"w":9,"h":2,"role":"type","frame":"none","fill":"ground","src":{"x":26,"y":4,"scale":1}},
87
+ {"x":1,"y":16,"w":8,"h":1,"role":"readout","frame":"none","variant":4}
88
+ ]
89
+ },
90
+ "slit-scan": {
91
+ "description": "Experimental type: a tall Pretendard Black word (sheet word `slit`, default SCAN) as a window onto still footage on a vermilion field. Every row of the word reads the music at its own delay, so each beat enters at the bottom and travels up the letters as a sideways shear; the beat also smears the word into a streak; black MesloLGS NF micro-type lines, a timecode bar and a spine column frame it.",
92
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.016,"footageScan":0,"footageSat":0.6,"footageContrast":1.2,"groundColor":[0.9,0.22,0.08,1],"inkColor":[0.06,0.06,0.065,1],"accentColor":[0.93,0.92,0.88,1]},
93
+ "cells": [
94
+ {"x":12,"y":1,"w":20,"h":17,"role":"typefx","frame":"none","variant":1,"src":{"x":0,"y":0,"scale":1,"sheet":"b"}},
95
+ {"x":0,"y":1,"w":32,"h":17,"role":"typefx","frame":"none","variant":3,"src":{"x":-0.5,"y":-0.5,"scale":1.9,"sheet":"b"}},
96
+ {"x":0,"y":0,"w":32,"h":1,"role":"rule","frame":"none","fill":"ink"},
97
+ {"x":1,"y":0,"w":8,"h":1,"role":"readout","frame":"none","tone":"ground","variant":4},
98
+ {"x":24,"y":0,"w":5,"h":1,"role":"readout","frame":"none","tone":"ground","variant":3},
99
+ {"x":0,"y":2,"w":1,"h":15,"role":"type","frame":"none","rot":1,"src":{"x":0,"y":15.5,"scale":1}}
100
+ ]
101
+ },
102
+ "slit-scan-ko": {
103
+ "description": "Experimental type, calm Hangul version: the tall Pretendard word 신호 (sheet word `slitK`) as a footage window on near-black, vermilion smear, Hangul micro-type behind it, typeWarp 0.45 so the shear and smear are gentler and the flash audit reports far fewer transitions than slit-scan.",
104
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.016,"footageScan":0,"footageSat":0.6,"footageContrast":1.2,"groundColor":[0.04,0.04,0.045,1],"inkColor":[0.93,0.92,0.88,1],"accentColor":[0.9,0.22,0.08,1],"typeWarp":0.45},
105
+ "cells": [
106
+ {"x":0,"y":0,"w":32,"h":18,"role":"typefx","frame":"none","variant":1,"src":{"x":0,"y":0,"scale":1,"sheet":"g"}},
107
+ {"x":4,"y":0,"w":24,"h":18,"role":"typefx","frame":"none","variant":3,"src":{"x":18,"y":0.5,"scale":2.4,"sheet":"b"}},
108
+ {"x":31,"y":0,"w":1,"h":18,"role":"rule","frame":"none","fill":"accent"},
109
+ {"x":1,"y":1,"w":9,"h":3,"role":"type","frame":"none","src":{"x":26,"y":0,"scale":1},"fill":"ground"},
110
+ {"x":22,"y":16,"w":8,"h":1,"role":"readout","frame":"none","variant":4}
111
+ ]
112
+ },
113
+ "slit-scan-bone": {
114
+ "description": "Experimental type, paper version: the Pretendard Black word SCAN blown up to 3x and cropped by the frame on a bone ground, black MesloLGS NF micro-type, vermilion smear on the beat; typeWarp 0.5 keeps the shear softer than slit-scan.",
115
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.016,"footageScan":0,"footageSat":0.6,"footageContrast":1.2,"groundColor":[0.91,0.89,0.83,1],"inkColor":[0.06,0.06,0.065,1],"accentColor":[0.9,0.22,0.08,1],"typeWarp":0.5},
116
+ "cells": [
117
+ {"x":0,"y":0,"w":32,"h":18,"role":"typefx","frame":"none","variant":1,"src":{"x":0,"y":0,"scale":1,"sheet":"b"}},
118
+ {"x":0,"y":1,"w":32,"h":17,"role":"typefx","frame":"none","variant":3,"src":{"x":1,"y":0,"scale":2.6,"sheet":"b"}},
119
+ {"x":1,"y":1,"w":9,"h":3,"role":"type","frame":"none","src":{"x":26,"y":0,"scale":1},"fill":"ground"},
120
+ {"x":31,"y":1,"w":1,"h":16,"role":"type","frame":"none","rot":1,"src":{"x":0,"y":15.5,"scale":1}},
121
+ {"x":22,"y":16,"w":8,"h":1,"role":"readout","frame":"none","variant":4}
122
+ ]
123
+ },
124
+ "echo-stack": {
125
+ "description": "Experimental type: a Monument Extended word (sheet word `echo`, default ECHO) so large the frame crops it, repeated 2 to 10 times in a stack stepping up and to the right, odd copies solid vermilion, even copies knocked out of a bone ground, footage in the front copy, over a field of black MesloLGS NF micro-type. The stack count follows the rms and jumps on every beat frame (a little on onsets).",
126
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":0.7,"footageContrast":1.2,"groundColor":[0.91,0.89,0.83,1],"inkColor":[0.06,0.06,0.065,1],"accentColor":[0.9,0.22,0.08,1]},
127
+ "cells": [
128
+ {"x":0,"y":0,"w":32,"h":18,"role":"typefx","frame":"none","variant":1,"src":{"x":0,"y":0,"scale":1,"sheet":"b"}},
129
+ {"x":0,"y":4,"w":32,"h":14,"role":"typefx","frame":"none","variant":4,"src":{"x":0.5,"y":8,"scale":2.2,"sheet":"g"}},
130
+ {"x":1,"y":1,"w":9,"h":3,"role":"type","frame":"none","src":{"x":26,"y":0,"scale":1},"fill":"ground"},
131
+ {"x":31,"y":1,"w":1,"h":16,"role":"type","frame":"none","rot":1,"src":{"x":0,"y":15.5,"scale":1}}
132
+ ]
133
+ },
134
+ "echo-stack-ko": {
135
+ "description": "Experimental type, dark Hangul version: the Pretendard Black word 메아리 (sheet word `echoK`, \"echo\") stacked 2 to 10 times, odd copies solid vermilion, even copies knocked out to near-black with bone edges, footage in the front copy, Hangul micro-type behind. Count follows the rms and the beat as in echo-stack.",
136
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.016,"footageScan":0,"footageSat":0.7,"footageContrast":1.2,"groundColor":[0.04,0.04,0.045,1],"inkColor":[0.93,0.92,0.88,1],"accentColor":[0.9,0.22,0.08,1]},
137
+ "cells": [
138
+ {"x":0,"y":0,"w":32,"h":18,"role":"typefx","frame":"none","variant":1,"src":{"x":0,"y":0,"scale":1,"sheet":"g"}},
139
+ {"x":0,"y":3,"w":32,"h":15,"role":"typefx","frame":"none","variant":4,"src":{"x":16.5,"y":8,"scale":2.2,"sheet":"g"}},
140
+ {"x":1,"y":1,"w":9,"h":3,"role":"type","frame":"none","src":{"x":26,"y":0,"scale":1},"fill":"ground"},
141
+ {"x":31,"y":1,"w":1,"h":16,"role":"type","frame":"none","rot":1,"src":{"x":0,"y":15.5,"scale":1},"tone":"accent"}
142
+ ]
143
+ },
144
+ "echo-ripple": {
145
+ "description": "Experimental type, new: a Monument Extended ampersand (sheet word `mega2`) with footage inside it, ringed by 2 to 12 hairline outlines that grow out of it in alternating bone and vermilion; the ring count follows the rms and jumps on the beat frame. Near-black ground, footage ghost, MesloLGS NF micro-type.",
146
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.016,"footageScan":0,"footageSat":0.55,"footageContrast":1.2,"groundColor":[0.04,0.04,0.045,1],"inkColor":[0.93,0.92,0.88,1],"accentColor":[0.9,0.22,0.08,1]},
147
+ "cells": [
148
+ {"x":0,"y":0,"w":32,"h":18,"role":"footage","frame":"none","variant":6},
149
+ {"x":0,"y":0,"w":32,"h":18,"role":"typefx","frame":"none","variant":1,"src":{"x":0,"y":0,"scale":1,"sheet":"b"}},
150
+ {"x":3,"y":0,"w":24,"h":18,"role":"typefx","frame":"none","variant":5,"src":{"x":11,"y":0.5,"scale":2.6,"sheet":"g"}},
151
+ {"x":1,"y":1,"w":9,"h":3,"role":"type","frame":"none","src":{"x":26,"y":0,"scale":1},"fill":"ground"},
152
+ {"x":24,"y":16,"w":6,"h":1,"role":"readout","frame":"none","variant":4}
153
+ ]
154
+ },
155
+ "type-eq": {
156
+ "description": "Experimental type, new: the word SIGNAL in Monument Extended is the spectrum analyzer. Every column of the letters fills solid vermilion up to the level of the band under it (bass left, treble right) and is only an outline over a dim footage ghost above that; a giant vermilion numeral, MesloLGS NF micro-type and a timecode frame it.",
157
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.016,"footageScan":0,"footageSat":0.5,"footageContrast":1.2,"groundColor":[0.04,0.04,0.045,1],"inkColor":[0.93,0.92,0.88,1],"accentColor":[0.9,0.22,0.08,1]},
158
+ "cells": [
159
+ {"x":0,"y":0,"w":32,"h":18,"role":"footage","frame":"none","variant":6},
160
+ {"x":0,"y":0,"w":32,"h":18,"role":"typefx","frame":"none","variant":1,"src":{"x":0,"y":0,"scale":1,"sheet":"b"}},
161
+ {"x":24,"y":0,"w":6,"h":9,"role":"type","frame":"none","tone":"accent","src":{"x":19.5,"y":0.5,"scale":1}},
162
+ {"x":1,"y":8,"w":29,"h":6,"role":"typefx","frame":"none","variant":6,"src":{"x":0,"y":9.5,"scale":1.7,"sheet":"b"}},
163
+ {"x":0,"y":13,"w":32,"h":1,"role":"rule","frame":"none","variant":3},
164
+ {"x":1,"y":1,"w":9,"h":3,"role":"type","frame":"none","src":{"x":26,"y":0,"scale":1},"fill":"ground"},
165
+ {"x":1,"y":16,"w":8,"h":1,"role":"readout","frame":"none","variant":4}
166
+ ]
167
+ },
168
+ "type-eq-ko": {
169
+ "description": "Experimental type, new, paper version in Hangul: the word 소리 (\"sound\") in Pretendard Black as the spectrum analyzer on a bone ground, columns filled vermilion to their band level, outline over a footage ghost above it, Hangul micro-type behind.",
170
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.016,"footageScan":0,"footageSat":0.5,"footageContrast":1.2,"groundColor":[0.91,0.89,0.83,1],"inkColor":[0.06,0.06,0.065,1],"accentColor":[0.9,0.22,0.08,1]},
171
+ "cells": [
172
+ {"x":0,"y":0,"w":32,"h":18,"role":"typefx","frame":"none","variant":1,"src":{"x":0,"y":0,"scale":1,"sheet":"g"}},
173
+ {"x":6,"y":5,"w":20,"h":10,"role":"typefx","frame":"none","variant":6,"src":{"x":19,"y":9,"scale":2.4,"sheet":"b"}},
174
+ {"x":1,"y":1,"w":9,"h":3,"role":"type","frame":"none","src":{"x":26,"y":0,"scale":1},"fill":"ground"},
175
+ {"x":31,"y":1,"w":1,"h":16,"role":"type","frame":"none","rot":1,"src":{"x":0,"y":15.5,"scale":1}},
176
+ {"x":24,"y":16,"w":6,"h":1,"role":"readout","frame":"none","variant":4}
177
+ ]
178
+ },
179
+ "specimen": {
180
+ "description": "Round 7 scene: a deep ultramarine specimen sheet. The plate is a single-tone lavender dither inside a tall arch; an ultra-tall thin word (Pretendard Thin stretched) stands as a column; pink and cyan micro bars on the arch edges are live band levels; a solid black square with a semicircle snaps to a new place of a fixed set on every beat; MesloLGS NF captions with live numbers.",
181
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.01,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":1,"groundColor":[0.04,0.04,0.66,1],"inkColor":[0.8,0.77,1,1],"accentColor":[1,0.45,0.72,1],"tintA":[0.2,0.9,1,1],"tintB":[0.02,0.02,0.05,1]},
182
+ "cells": [
183
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":1}
184
+ ]
185
+ },
186
+ "wiring": {
187
+ "description": "Round 7 scene: a black ground with the plate as a cyan / yellow duotone and scanline bands that re-seed on every beat; five yellow cables run from fixed points on the CRT wall to boxed annotations with live pixel-font readouts and level bars; pixel arcs and a dot grid sit in a corner; a small crimson pixel glyph blinks on every onset and each onset sends a packet down the next cable. Monument Extended is used only as small label caps.",
188
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":1,"footageContrast":1.25,"cutMode":0,"textSet":2,"groundColor":[0.02,0.02,0.025,1],"inkColor":[0.93,0.93,0.9,1],"accentColor":[1,0.83,0,1],"tintA":[0,0.88,1,1],"tintB":[0.91,0,0.18,1]},
189
+ "cells": [
190
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":2}
191
+ ]
192
+ },
193
+ "field-cut": {
194
+ "description": "Round 7 scene over time: every beat hard-cuts to the next of four full fields, each with its own fixed composition. Acid lime with a halftone of the plate and a black dot-matrix tower whose height is the bass; signal orange with rows of a condensed Pretendard Black word in blue that shear on every onset and a blue dither window of the plate; ultramarine with the plate in a ringed circle, a Hangul word and checker blocks; a white field with the plate torn into RGB pixel slabs and a lime brush chunk. The fields advance on beats only.",
195
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.01,"footageScan":0,"footageSat":1,"footageContrast":1.15,"cutMode":0,"textSet":3,"groundColor":[0.03,0.03,0.035,1],"inkColor":[0.97,0.97,0.95,1],"accentColor":[0.784,1,0,1],"tintA":[1,0.56,0.02,1],"tintB":[0.08,0.08,1,1]},
196
+ "cells": [
197
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":3}
198
+ ]
199
+ },
200
+ "pattern-sheet": {
201
+ "description": "Round 7 scene: a bone sheet in a signal-green border. The plate is a black line-screen engraving in the big circle; a heavy grotesk label sits between magenta serif quote marks; outline circles step their radius on every onset; thin rules, ticks and crosshairs; QR-like pixel stamps that re-seed on every beat; a vertical waveform strip with a 0 to 5 ruler on the left edge.",
202
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":0,"footageContrast":1.1,"cutMode":0,"textSet":4,"groundColor":[0,0.69,0.33,1],"inkColor":[0.04,0.04,0.045,1],"accentColor":[1,0.18,0.58,1],"tintA":[0.92,0.9,0.84,1]},
203
+ "cells": [
204
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":4}
205
+ ]
206
+ },
207
+ "anatomy": {
208
+ "description": "Round 8 scene: a sepia paper field with a huge cropped Times numeral, a dark panel holding the plate as a cream hairline wireframe (edge detection) that grows denser on every beat while a rust scan band jumps to a new height on every cut, a thin ring, three callout cables to Pretendard Light labels, a checkerboard tower of the mid level and tiny rust code columns.",
209
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":1,"footageContrast":1.3,"cutMode":0,"textSet":5,"groundColor":[0.78,0.66,0.46,1],"inkColor":[0.12,0.07,0.04,1],"accentColor":[0.72,0.2,0.08,1],"tintA":[0.07,0.04,0.03,1],"tintB":[0.96,0.9,0.72,1]},
210
+ "cells": [
211
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":5}
212
+ ]
213
+ },
214
+ "deck": {
215
+ "description": "Round 8 scene: a hot pink field and a HUD deck of thin black lines. The plate sits in a chamfered octagon window; outlined tab-box labels (DIN Condensed, Pretendard Hangul) down the left, a lilac particle cloud box that scatters on the onset, a starburst glyph whose rays are band levels and that steps round on every beat, a text ring that turns a notch per onset, a contour-map box whose terrain shifts on the beat and a 0 to 5 ruler strip.",
216
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":6,"groundColor":[1,0.18,0.54,1],"inkColor":[0.04,0.03,0.04,1],"accentColor":[1,1,1,1],"tintA":[0.78,0.72,1,1]},
217
+ "cells": [
218
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":6}
219
+ ]
220
+ },
221
+ "bootlog": {
222
+ "description": "Round 8 scene: phosphor green on near-black. A boot log the engine types over the clip, a dot-matrix terminal icon, a boot progress bar that fills a step on every beat, a big Hangul word, the plate as a single-tone phosphor CRT with raster lines, a ghost and a roll bar, and data streaks along the bottom whose length is the spectrum; every beat inverts one log row.",
223
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.014,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":7,"groundColor":[0.01,0.025,0.012,1],"inkColor":[0.22,1,0.1,1],"accentColor":[0.8,1,0.78,1],"tintA":[0.05,0.35,0.06,1]},
224
+ "cells": [
225
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":7}
226
+ ]
227
+ },
228
+ "tunnel": {
229
+ "description": "Round 8 scene: a pixel checker tunnel in electric blue on black that jumps one ring deeper and turns half a step on every beat; the plate sits in a curved letterbox at its vanishing point; a white-hot horizontal eye bar flares on the onset; a black block with a giant Monument Extended word and live depth numbers.",
230
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.01,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":8,"groundColor":[0,0,0.01,1],"inkColor":[0.96,0.97,1,1],"accentColor":[0.12,0.3,1,1],"tintA":[0.02,0.06,0.4,1]},
231
+ "cells": [
232
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":8}
233
+ ]
234
+ },
235
+ "runner": {
236
+ "description": "Round 8 scene: the plate as a black and grey monotone under scanline bands (a few slide sideways on every onset), white-hot data streaks whose length is the spectrum and that jump on the onset, and a vermilion bar with a heavy Arial Black word that swaps to the next of three words and slams to a new left edge on every beat; black pixel crosses, a checker block and MesloLGS NF captions.",
237
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":9,"groundColor":[0.02,0.02,0.025,1],"inkColor":[1,1,0.94,1],"accentColor":[1,0.24,0.04,1],"tintA":[0.02,0.02,0.03,1],"tintB":[0.8,0.8,0.78,1]},
238
+ "cells": [
239
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":9}
240
+ ]
241
+ },
242
+ "ascii": {
243
+ "description": "Round 8 scene: the plate drawn as ASCII, one character per cell from the pixel font by tone (mint, the lightest cells lilac) on dark teal; after every onset a hot column sweeps across it and lifts the characters it passes; a contour-map box whose terrain shifts on the beat, a lilac particle cloud box that scatters on the onset, live readouts and a big Pretendard Hangul word.",
244
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":10,"groundColor":[0.01,0.07,0.07,1],"inkColor":[0.49,1,0.83,1],"accentColor":[0.9,1,0.96,1],"tintA":[0.7,0.58,1,1]},
245
+ "cells": [
246
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":0}
247
+ ]
248
+ },
249
+ "cube-wall": {
250
+ "description": "Round 9 scene: a salmon field and a 4 x 3 wall of cubes. On every beat each cube turns to its next face in three frames (even columns sideways, odd columns upward); a face is a cobalt rounded tile with a cream letter, a cream tile with a cobalt letter, a cobalt Bayer dither of the plate, or a dot grid whose dot radius is the bass; each onset swaps the letter of one cube. Big Shoulders Display letters, MesloLGS NF caption.",
251
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.01,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":11,"groundColor":[0.98,0.55,0.5,1],"inkColor":[0.98,0.93,0.8,1],"accentColor":[0,0.2,0.85,1],"tintA":[0.78,0.35,0.33,1]},
252
+ "cells": [
253
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":0,"rot":1}
254
+ ]
255
+ },
256
+ "vortex-count": {
257
+ "description": "Round 9 scene: a blue-grey field whose log-polar rings of Bebas Neue text spiral out of the centre (white and navy rings alternate, the spiral steps on every beat), a round window at the vanishing point holding the plate as white halftone dots that grow with the bass, and a ring of 24 countdown ticks that loses one tick on every beat.",
258
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.01,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":12,"groundColor":[0.4,0.47,0.55,1],"inkColor":[0.97,0.98,1,1],"accentColor":[0.05,0.1,0.3,1],"tintA":[0.72,0.78,0.85,1]},
259
+ "cells": [
260
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":1,"rot":1}
261
+ ]
262
+ },
263
+ "sticker-slap": {
264
+ "description": "Round 9 scene: a black field and a pile of cream stickers. Every beat a new sticker slaps on with an overshoot (1.35, 1.12, 0.97, 1); the pile keeps the last eight; every onset flips one sticker over to a 1-bit dither of the plate. Filled and outlined Impact words, a round Georgia tag, small mustard pills (under about 15 percent of the frame), two rows of Impact text along the top.",
265
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":13,"groundColor":[0.02,0.02,0.02,1],"inkColor":[0.96,0.92,0.8,1],"accentColor":[0.9,0.65,0.1,1],"tintA":[0.72,0.62,0.95,1]},
266
+ "cells": [
267
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":2,"rot":1}
268
+ ]
269
+ },
270
+ "ribbon-rays": {
271
+ "description": "Round 9 scene: an ochre field with a fan of white hairline rays whose count grows on every beat, and a twisted ribbon crossing the frame: its front face is black with a heavy condensed word flowing along it (the flow steps on every beat), its back face is an ochre duotone of the plate; four echo copies trail behind in colour steps; one DIN Condensed label at the root of the rays.",
272
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":14,"groundColor":[0.82,0.55,0.12,1],"inkColor":[1,1,0.96,1],"accentColor":[0.04,0.03,0.02,1],"tintA":[0.5,0.3,0.05,1],"tintB":[0.95,0.8,0.5,1]},
273
+ "cells": [
274
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":3,"rot":1}
275
+ ]
276
+ },
277
+ "slab-shear": {
278
+ "description": "Round 9 scene: a concrete-grey field with a giant Futura word that flows on a sine wave (the wave steps on every beat) cut into nine horizontal slabs; on every beat some slabs slide sideways and some become safety-blue slabs holding the plate as a 1-bit Bayer dither with the word in white; a typed Menlo label on a seam, a crosshair target and ticks.",
279
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":15,"groundColor":[0.62,0.62,0.6,1],"inkColor":[1,1,0.98,1],"accentColor":[0,0.3,0.95,1],"tintA":[0.03,0.03,0.04,1]},
280
+ "cells": [
281
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":4,"rot":1}
282
+ ]
283
+ },
284
+ "frame-loop-dial": {
285
+ "description": "Round 9 scene: a dark aubergine field with a line of Georgia text running round the border of the frame (every onset jumps it ahead); an arch window with the plate as a peach Bayer dither; a dial of 60 ticks filled up on every beat with a split-flap countdown in its middle (the top half of the old digit folds away in three frames); a typed Menlo input line.",
286
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":16,"groundColor":[0.17,0.05,0.14,1],"inkColor":[0.96,0.94,0.88,1],"accentColor":[1,0.72,0.55,1],"tintA":[0.33,0.12,0.3,1]},
287
+ "cells": [
288
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":5,"rot":1}
289
+ ]
290
+ },
291
+ "tilt-tiles": {
292
+ "description": "Round 10 scene: a lemon field tilted about 14 degrees into rows of Rockwell word tiles; neighbouring rows flow the other way and every beat each row jumps a different distance; filled and outlined rows alternate and each onset swaps the kind of one row; a tilted window holds the plate as a three-tone posterize (black, lemon, white), with a white caption box and a numbered black disc.",
293
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.01,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":17,"groundColor":[1,0.9,0,1],"inkColor":[0.04,0.04,0.04,1],"accentColor":[1,1,1,1],"tintA":[0,0.35,0.2,1]},
294
+ "cells": [
295
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":6,"rot":1}
296
+ ]
297
+ },
298
+ "marquee-stack": {
299
+ "description": "Round 10 scene: a teal field of six stacked word rows (Gill Sans Bold, the last row in Hangul); every beat each row jumps its own distance in its own direction (a marquee that moves in steps), each with three echo copies trailing in colour steps; a cream-framed window holds the plate as a coarse four-colour mosaic.",
300
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.01,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":18,"groundColor":[0,0.5,0.45,1],"inkColor":[0.97,0.93,0.8,1],"accentColor":[1,0.55,0.1,1],"tintA":[0,0.22,0.22,1]},
301
+ "cells": [
302
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":7,"rot":1}
303
+ ]
304
+ },
305
+ "lens-wrap": {
306
+ "description": "Round 10 scene: a mint field; the plate wrapped on a sphere with a red-blue lens fringe and a specular patch, swelling with the bass; a perspective floor of forest-green tile lines that steps toward you on every beat; a 4 x 3 block of small panels that each turn a quarter on every third onset; Didot and Courier New type.",
307
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":19,"groundColor":[0.55,0.82,0.68,1],"inkColor":[0.04,0.26,0.16,1],"accentColor":[0.03,0.03,0.03,1],"tintA":[0.33,0.62,0.5,1],"tintB":[0.96,0.95,0.86,1]},
308
+ "cells": [
309
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":8,"rot":1}
310
+ ]
311
+ },
312
+ "liquid-type": {
313
+ "description": "Round 10 scene: a sky-blue field; the plate blurred and thresholded into ink-blot shapes (mid blue, one orange blot in the brightest part); a big Bodoni 72 word on a double sine ripple whose phase steps on every beat; a typed American Typewriter note and a crosshair reticle that jumps to a new place on every beat.",
314
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.01,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":20,"groundColor":[0.68,0.84,1,1],"inkColor":[0.04,0.08,0.3,1],"accentColor":[1,0.5,0.1,1],"tintA":[0.9,0.96,1,1],"tintB":[0.38,0.58,0.92,1]},
315
+ "cells": [
316
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":9,"rot":1}
317
+ ]
318
+ },
319
+ "panel-grid": {
320
+ "description": "Round 10 scene: an ice-white sheet with a 6 x 4 grid of small square panels, each a thin-line instrument (plate isolines, spectrum comb, bass gauge, big number, starburst, waveform, checker, reticle); on every onset one panel in turn swings a quarter turn in three frames and shows its next instrument; brick accents, Optima and SF Mono type.",
321
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.008,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":21,"groundColor":[0.94,0.95,0.96,1],"inkColor":[0.05,0.05,0.06,1],"accentColor":[0.85,0.35,0.2,1],"tintA":[0.6,0.6,0.62,1]},
322
+ "cells": [
323
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":0,"rot":2}
324
+ ]
325
+ },
326
+ "mirror-track": {
327
+ "description": "Round 10 scene: a dusty violet field and a central window holding the plate mirrored about its vertical axis and solarized into brick red, indigo and cream; five outline target squares with tiny number labels jump to new places on every beat and are mirrored with the plate; a barcode strip that re-seeds on every beat; a D2Coding file-lookup block with struck-through rows and a big Phosphate word.",
328
+ "params": {"margin":0,"gridDots":0,"construction":false,"grain":0.012,"footageScan":0,"footageSat":1,"footageContrast":1.2,"cutMode":0,"textSet":22,"groundColor":[0.45,0.34,0.62,1],"inkColor":[0.97,0.93,0.82,1],"accentColor":[0.85,0.25,0.15,1],"tintA":[0.12,0.07,0.3,1],"tintB":[0.7,0.6,0.85,1]},
329
+ "cells": [
330
+ {"x":0,"y":0,"w":32,"h":18,"role":"scene","frame":"none","variant":1,"rot":2}
331
+ ]
332
+ },
333
+ "wide-hero": [
334
+ {"x":0,"y":0,"w":22,"h":12,"role":"footage"},
335
+ {"x":22,"y":0,"w":6,"h":5,"role":"readout"},
336
+ {"x":22,"y":5,"w":6,"h":7,"role":"crosshair"},
337
+ {"x":28,"y":0,"w":4,"h":12,"role":"meter"},
338
+ {"x":0,"y":12,"w":13,"h":6,"role":"spectrum"},
339
+ {"x":13,"y":12,"w":13,"h":6,"role":"scope"},
340
+ {"x":26,"y":12,"w":3,"h":6,"role":"plate"},
341
+ {"x":29,"y":12,"w":3,"h":3,"role":"ruler"},
342
+ {"x":29,"y":15,"w":3,"h":3,"role":"pixels"}
343
+ ],
344
+ "split": [
345
+ {"x":0,"y":0,"w":15,"h":15,"role":"footage"},
346
+ {"x":0,"y":15,"w":15,"h":3,"role":"ruler"},
347
+ {"x":15,"y":0,"w":17,"h":5,"role":"spectrum"},
348
+ {"x":15,"y":5,"w":17,"h":4,"role":"scope"},
349
+ {"x":15,"y":9,"w":17,"h":3,"role":"meter"},
350
+ {"x":15,"y":12,"w":8,"h":6,"role":"readout"},
351
+ {"x":23,"y":12,"w":6,"h":6,"role":"crosshair"},
352
+ {"x":29,"y":12,"w":3,"h":6,"role":"pixels"}
353
+ ],
354
+ "mosaic": [
355
+ {"x":0,"y":0,"w":10,"h":6,"role":"spectrum"},
356
+ {"x":10,"y":0,"w":6,"h":6,"role":"crosshair"},
357
+ {"x":16,"y":0,"w":6,"h":6,"role":"readout"},
358
+ {"x":22,"y":0,"w":10,"h":6,"role":"scope"},
359
+ {"x":0,"y":6,"w":4,"h":12,"role":"meter"},
360
+ {"x":4,"y":6,"w":10,"h":10,"role":"footage"},
361
+ {"x":14,"y":6,"w":5,"h":10,"role":"plate"},
362
+ {"x":19,"y":6,"w":13,"h":5,"role":"pixels"},
363
+ {"x":4,"y":16,"w":15,"h":2,"role":"ruler"},
364
+ {"x":19,"y":11,"w":13,"h":7,"role":"hatch"}
365
+ ]
366
+ }