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.
- package/AGENTS.md +8 -0
- package/GEMINI.md +1 -0
- package/LICENSE +172 -0
- package/README.md +236 -2
- package/package.json +35 -4
- package/skills/agentvfx/LICENSE +172 -0
- package/skills/agentvfx/NOTICE +44 -0
- package/skills/agentvfx/SKILL.md +90 -0
- package/skills/agentvfx/engine/core/constants.mjs +84 -0
- package/skills/agentvfx/engine/core/flash-constants.mjs +23 -0
- package/skills/agentvfx/engine/core/flash.mjs +240 -0
- package/skills/agentvfx/engine/core/mark.mjs +28 -0
- package/skills/agentvfx/engine/core/palettes.mjs +36 -0
- package/skills/agentvfx/engine/core/schedule.mjs +85 -0
- package/skills/agentvfx/engine/core/templates.mjs +43 -0
- package/skills/agentvfx/engine/core/util.mjs +167 -0
- package/skills/agentvfx/engine/core/validate.mjs +334 -0
- package/skills/agentvfx/engine/node/analysis.mjs +172 -0
- package/skills/agentvfx/engine/node/audio.mjs +621 -0
- package/skills/agentvfx/engine/node/board.mjs +24 -0
- package/skills/agentvfx/engine/node/chrome.mjs +349 -0
- package/skills/agentvfx/engine/node/encode.mjs +110 -0
- package/skills/agentvfx/engine/node/eye.mjs +77 -0
- package/skills/agentvfx/engine/node/footage.mjs +129 -0
- package/skills/agentvfx/engine/node/frame-worker.mjs +39 -0
- package/skills/agentvfx/engine/node/host.mjs +31 -0
- package/skills/agentvfx/engine/node/job.mjs +181 -0
- package/skills/agentvfx/engine/node/png.mjs +112 -0
- package/skills/agentvfx/engine/node/render.mjs +161 -0
- package/skills/agentvfx/engine/node/stage-capture.mjs +187 -0
- package/skills/agentvfx/engine/node/stage-serve.mjs +72 -0
- package/skills/agentvfx/engine/node/stills.mjs +100 -0
- package/skills/agentvfx/engine/node/ws-server.mjs +132 -0
- package/skills/agentvfx/engine/web/gl.mjs +319 -0
- package/skills/agentvfx/engine/web/glsl-common.mjs +78 -0
- package/skills/agentvfx/engine/web/init.js +23 -0
- package/skills/agentvfx/engine/web/prelude.mjs +150 -0
- package/skills/agentvfx/engine/web/render.html +11 -0
- package/skills/agentvfx/engine/web/render.mjs +388 -0
- package/skills/agentvfx/engine/web/scale.mjs +15 -0
- package/skills/agentvfx/engine/web/text.mjs +158 -0
- package/skills/agentvfx/plates/terminalcore/README.md +61 -0
- package/skills/agentvfx/plates/terminalcore/__pycache__/crt.cpython-313.pyc +0 -0
- package/skills/agentvfx/plates/terminalcore/__pycache__/font.cpython-313.pyc +0 -0
- package/skills/agentvfx/plates/terminalcore/__pycache__/gallery.cpython-313.pyc +0 -0
- package/skills/agentvfx/plates/terminalcore/__pycache__/gallery_mats.cpython-313.pyc +0 -0
- package/skills/agentvfx/plates/terminalcore/__pycache__/gallery_room.cpython-313.pyc +0 -0
- package/skills/agentvfx/plates/terminalcore/__pycache__/materials.cpython-313.pyc +0 -0
- package/skills/agentvfx/plates/terminalcore/__pycache__/nodekit.cpython-313.pyc +0 -0
- package/skills/agentvfx/plates/terminalcore/__pycache__/room.cpython-313.pyc +0 -0
- package/skills/agentvfx/plates/terminalcore/__pycache__/shots.cpython-313.pyc +0 -0
- package/skills/agentvfx/plates/terminalcore/__pycache__/textures.cpython-313.pyc +0 -0
- package/skills/agentvfx/plates/terminalcore/__pycache__/wall.cpython-313.pyc +0 -0
- package/skills/agentvfx/plates/terminalcore/crt.py +143 -0
- package/skills/agentvfx/plates/terminalcore/font.py +80 -0
- package/skills/agentvfx/plates/terminalcore/gallery.py +61 -0
- package/skills/agentvfx/plates/terminalcore/gallery_mats.py +144 -0
- package/skills/agentvfx/plates/terminalcore/gallery_room.py +126 -0
- package/skills/agentvfx/plates/terminalcore/materials.py +170 -0
- package/skills/agentvfx/plates/terminalcore/nodekit.py +87 -0
- package/skills/agentvfx/plates/terminalcore/room.py +82 -0
- package/skills/agentvfx/plates/terminalcore/scene.py +219 -0
- package/skills/agentvfx/plates/terminalcore/shots.py +48 -0
- package/skills/agentvfx/plates/terminalcore/textures.py +79 -0
- package/skills/agentvfx/plates/terminalcore/wall.py +103 -0
- package/skills/agentvfx/references/plates.md +22 -0
- package/skills/agentvfx/references/template-format.md +149 -0
- package/skills/agentvfx/references/web.md +63 -0
- package/skills/agentvfx/runtime/agentvfx.js +708 -0
- package/skills/agentvfx/schemas/fx-score.schema.json +98 -0
- package/skills/agentvfx/scripts/export-web.mjs +155 -0
- package/skills/agentvfx/scripts/loop.mjs +129 -0
- package/skills/agentvfx/scripts/make-beat.mjs +133 -0
- package/skills/agentvfx/scripts/plate.mjs +82 -0
- package/skills/agentvfx/scripts/vfx.mjs +173 -0
- package/skills/agentvfx/templates/_test/feedback-counter/fx.json +11 -0
- package/skills/agentvfx/templates/_test/feedback-counter/main.frag +4 -0
- package/skills/agentvfx/templates/_test/feedback-counter/pass0.frag +4 -0
- package/skills/agentvfx/templates/_test/gradient/fx.json +23 -0
- package/skills/agentvfx/templates/_test/gradient/main.frag +5 -0
- package/skills/agentvfx/templates/_test/identity/fx.json +10 -0
- package/skills/agentvfx/templates/_test/identity/main.frag +4 -0
- package/skills/agentvfx/templates/_test/strobe/fx.json +14 -0
- package/skills/agentvfx/templates/_test/strobe/main.frag +6 -0
- package/skills/agentvfx/templates/_test/text-probe/fx.json +15 -0
- package/skills/agentvfx/templates/_test/text-probe/main.frag +6 -0
- package/skills/agentvfx/templates/brutal/NOTES.md +14 -0
- package/skills/agentvfx/templates/brutal/_src/boot-log/def.mjs +57 -0
- package/skills/agentvfx/templates/brutal/_src/boot-log/main.src.frag +129 -0
- package/skills/agentvfx/templates/brutal/_src/build.mjs +33 -0
- package/skills/agentvfx/templates/brutal/_src/halftone-field/def.mjs +72 -0
- package/skills/agentvfx/templates/brutal/_src/halftone-field/main.src.frag +94 -0
- package/skills/agentvfx/templates/brutal/_src/hud-deck/deck-left.src.glsl +100 -0
- package/skills/agentvfx/templates/brutal/_src/hud-deck/deck-right.src.glsl +61 -0
- package/skills/agentvfx/templates/brutal/_src/hud-deck/deck-tiles.src.glsl +153 -0
- package/skills/agentvfx/templates/brutal/_src/hud-deck/def.mjs +82 -0
- package/skills/agentvfx/templates/brutal/_src/hud-deck/main.src.frag +110 -0
- package/skills/agentvfx/templates/brutal/_src/hud-deck/pass0.src.frag +38 -0
- package/skills/agentvfx/templates/brutal/_src/shared/defs.mjs +28 -0
- package/skills/agentvfx/templates/brutal/_src/shared/icons.glsl +72 -0
- package/skills/agentvfx/templates/brutal/_src/shared/lib.glsl +115 -0
- package/skills/agentvfx/templates/brutal/_src/shared/screen.glsl +43 -0
- package/skills/agentvfx/templates/brutal/boot-log/demo-acid.json +1 -0
- package/skills/agentvfx/templates/brutal/boot-log/demo-phosphor.json +1 -0
- package/skills/agentvfx/templates/brutal/boot-log/demo-ultramarine.json +1 -0
- package/skills/agentvfx/templates/brutal/boot-log/fx.json +257 -0
- package/skills/agentvfx/templates/brutal/boot-log/main.frag +242 -0
- package/skills/agentvfx/templates/brutal/collage/_src/00-lib.glsl +73 -0
- package/skills/agentvfx/templates/brutal/collage/_src/10-spectrum-scope.glsl +73 -0
- package/skills/agentvfx/templates/brutal/collage/_src/20-meter-readout-cross.glsl +87 -0
- package/skills/agentvfx/templates/brutal/collage/_src/30-footage-fillers.glsl +92 -0
- package/skills/agentvfx/templates/brutal/collage/_src/40-editorial.glsl +232 -0
- package/skills/agentvfx/templates/brutal/collage/_src/50-typefx.glsl +163 -0
- package/skills/agentvfx/templates/brutal/collage/_src/60-scene-lib.glsl +104 -0
- package/skills/agentvfx/templates/brutal/collage/_src/61-scene-specimen.glsl +71 -0
- package/skills/agentvfx/templates/brutal/collage/_src/62-scene-wiring.glsl +96 -0
- package/skills/agentvfx/templates/brutal/collage/_src/63-scene-fieldcut.glsl +119 -0
- package/skills/agentvfx/templates/brutal/collage/_src/64-scene-pattern.glsl +64 -0
- package/skills/agentvfx/templates/brutal/collage/_src/641-scene-anatomy.glsl +49 -0
- package/skills/agentvfx/templates/brutal/collage/_src/642-scene-deck.glsl +78 -0
- package/skills/agentvfx/templates/brutal/collage/_src/643-scene-bootlog.glsl +60 -0
- package/skills/agentvfx/templates/brutal/collage/_src/644-scene-tunnel.glsl +48 -0
- package/skills/agentvfx/templates/brutal/collage/_src/645-scene-runner.glsl +42 -0
- package/skills/agentvfx/templates/brutal/collage/_src/646-scene-ascii.glsl +66 -0
- package/skills/agentvfx/templates/brutal/collage/_src/647-scene-cubewall.glsl +80 -0
- package/skills/agentvfx/templates/brutal/collage/_src/648-scene-vortex.glsl +46 -0
- package/skills/agentvfx/templates/brutal/collage/_src/649-scene-sticker.glsl +72 -0
- package/skills/agentvfx/templates/brutal/collage/_src/65-scene-main.glsl +1 -0
- package/skills/agentvfx/templates/brutal/collage/_src/650-scene-ribbon.glsl +55 -0
- package/skills/agentvfx/templates/brutal/collage/_src/651-scene-slab.glsl +38 -0
- package/skills/agentvfx/templates/brutal/collage/_src/652-scene-framedial.glsl +79 -0
- package/skills/agentvfx/templates/brutal/collage/_src/653-scene-tilt.glsl +40 -0
- package/skills/agentvfx/templates/brutal/collage/_src/654-scene-marquee.glsl +45 -0
- package/skills/agentvfx/templates/brutal/collage/_src/655-scene-lens.glsl +57 -0
- package/skills/agentvfx/templates/brutal/collage/_src/656-scene-liquid.glsl +35 -0
- package/skills/agentvfx/templates/brutal/collage/_src/657-scene-panelgrid.glsl +75 -0
- package/skills/agentvfx/templates/brutal/collage/_src/658-scene-mirror.glsl +49 -0
- package/skills/agentvfx/templates/brutal/collage/_src/66-scene-main.glsl +27 -0
- package/skills/agentvfx/templates/brutal/collage/_src/90-main.glsl +120 -0
- package/skills/agentvfx/templates/brutal/collage/_src/build.mjs +24 -0
- package/skills/agentvfx/templates/brutal/collage/_src/sync-presets.mjs +16 -0
- package/skills/agentvfx/templates/brutal/collage/demo-bone-lime.json +1 -0
- package/skills/agentvfx/templates/brutal/collage/demo-lime-sparse.json +1 -0
- package/skills/agentvfx/templates/brutal/collage/demo-orange-dense.json +1 -0
- package/skills/agentvfx/templates/brutal/collage/demo-ultra-slow.json +1 -0
- package/skills/agentvfx/templates/brutal/collage/fx.json +4882 -0
- package/skills/agentvfx/templates/brutal/collage/layout.mjs +97 -0
- package/skills/agentvfx/templates/brutal/collage/layouts.json +366 -0
- package/skills/agentvfx/templates/brutal/collage/main.frag +2367 -0
- package/skills/agentvfx/templates/brutal/collage/pass0.frag +265 -0
- package/skills/agentvfx/templates/brutal/halftone-field/demo-acid.json +1 -0
- package/skills/agentvfx/templates/brutal/halftone-field/demo-ascii.json +1 -0
- package/skills/agentvfx/templates/brutal/halftone-field/demo-dither.json +1 -0
- package/skills/agentvfx/templates/brutal/halftone-field/demo-orange.json +1 -0
- package/skills/agentvfx/templates/brutal/halftone-field/demo-phosphor.json +1 -0
- package/skills/agentvfx/templates/brutal/halftone-field/demo-ultramarine.json +1 -0
- package/skills/agentvfx/templates/brutal/halftone-field/fx.json +474 -0
- package/skills/agentvfx/templates/brutal/halftone-field/main.frag +248 -0
- package/skills/agentvfx/templates/brutal/hud-deck/demo-acid.json +1 -0
- package/skills/agentvfx/templates/brutal/hud-deck/demo-night.json +1 -0
- package/skills/agentvfx/templates/brutal/hud-deck/demo-octagon.json +1 -0
- package/skills/agentvfx/templates/brutal/hud-deck/demo-ultramarine.json +1 -0
- package/skills/agentvfx/templates/brutal/hud-deck/fx.json +601 -0
- package/skills/agentvfx/templates/brutal/hud-deck/main.frag +645 -0
- package/skills/agentvfx/templates/brutal/hud-deck/pass0.frag +38 -0
- package/skills/agentvfx/templates/brutal/lattice/demo-cobalt-fine.json +1 -0
- package/skills/agentvfx/templates/brutal/lattice/demo-ink-yellow.json +1 -0
- package/skills/agentvfx/templates/brutal/lattice/demo-vermilion.json +1 -0
- package/skills/agentvfx/templates/brutal/lattice/demo-violet-slow.json +1 -0
- package/skills/agentvfx/templates/brutal/lattice/fx.json +130 -0
- package/skills/agentvfx/templates/brutal/lattice/main.frag +175 -0
- package/skills/agentvfx/templates/brutal/lattice/pass0.frag +29 -0
- package/skills/agentvfx/templates/glitch/block-glitch/demo-mosaic.json +1 -0
- package/skills/agentvfx/templates/glitch/block-glitch/demo-onset.json +1 -0
- package/skills/agentvfx/templates/glitch/block-glitch/demo-static.json +1 -0
- package/skills/agentvfx/templates/glitch/block-glitch/demo-tear.json +1 -0
- package/skills/agentvfx/templates/glitch/block-glitch/fx.json +54 -0
- package/skills/agentvfx/templates/glitch/block-glitch/main.frag +132 -0
- package/skills/agentvfx/templates/glitch/block-glitch/pass0.frag +12 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/NOTES.md +13 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/build-passes.mjs +162 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/demo-chunk.json +1 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/demo-hue.json +1 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/demo-kick.json +1 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/demo-streak.json +1 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/demo-vertical.json +1 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/fx.json +60 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/main.frag +83 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/pass0.frag +64 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/pass1.frag +66 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/pass2.frag +66 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/pass3.frag +66 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/pass4.frag +66 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/pass5.frag +66 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/pass6.frag +66 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/pass7.frag +66 -0
- package/skills/agentvfx/templates/glitch/pixel-sort/pass8.frag +66 -0
- package/skills/agentvfx/templates/glitch/rgb-split/demo-diagonal-stutter.json +1 -0
- package/skills/agentvfx/templates/glitch/rgb-split/demo-hard.json +1 -0
- package/skills/agentvfx/templates/glitch/rgb-split/demo-kick.json +1 -0
- package/skills/agentvfx/templates/glitch/rgb-split/demo-radial.json +1 -0
- package/skills/agentvfx/templates/glitch/rgb-split/fx.json +46 -0
- package/skills/agentvfx/templates/glitch/rgb-split/main.frag +76 -0
- package/skills/agentvfx/templates/glitch/vhs/demo-clean.json +1 -0
- package/skills/agentvfx/templates/glitch/vhs/demo-crash.json +1 -0
- package/skills/agentvfx/templates/glitch/vhs/demo-tape.json +1 -0
- package/skills/agentvfx/templates/glitch/vhs/demo-worn.json +1 -0
- package/skills/agentvfx/templates/glitch/vhs/fx.json +46 -0
- package/skills/agentvfx/templates/glitch/vhs/main.frag +96 -0
- package/skills/agentvfx/templates/impact/impact-1bit/demo-onebit-bayer.json +1 -0
- package/skills/agentvfx/templates/impact/impact-1bit/fx.json +45 -0
- package/skills/agentvfx/templates/impact/impact-1bit/main.frag +64 -0
- package/skills/agentvfx/templates/impact/impact-invert/demo-invert-snap.json +1 -0
- package/skills/agentvfx/templates/impact/impact-invert/fx.json +37 -0
- package/skills/agentvfx/templates/impact/impact-invert/main.frag +44 -0
- package/skills/agentvfx/templates/impact/punch-shake/demo-punch-hard.json +1 -0
- package/skills/agentvfx/templates/impact/punch-shake/fx.json +36 -0
- package/skills/agentvfx/templates/impact/punch-shake/main.frag +62 -0
- package/skills/agentvfx/templates/impact/rgb-hit/demo-rgb-slam.json +1 -0
- package/skills/agentvfx/templates/impact/rgb-hit/fx.json +39 -0
- package/skills/agentvfx/templates/impact/rgb-hit/main.frag +62 -0
- package/skills/agentvfx/templates/impact/signal-cut/demo-lime-hold.json +1 -0
- package/skills/agentvfx/templates/impact/signal-cut/demo-lime.json +1 -0
- package/skills/agentvfx/templates/impact/signal-cut/demo-orange.json +1 -0
- package/skills/agentvfx/templates/impact/signal-cut/demo-ultramarine.json +1 -0
- package/skills/agentvfx/templates/impact/signal-cut/fx.json +83 -0
- package/skills/agentvfx/templates/impact/signal-cut/main.frag +101 -0
- package/skills/agentvfx/templates/impact/signal-cut/pass0.frag +68 -0
- package/skills/agentvfx/templates/impact/speedline-burst/demo-speed-white.json +1 -0
- package/skills/agentvfx/templates/impact/speedline-burst/fx.json +44 -0
- package/skills/agentvfx/templates/impact/speedline-burst/main.frag +68 -0
- package/skills/agentvfx/templates/impact/strobe-burst/demo-strobe-white-16.json +1 -0
- package/skills/agentvfx/templates/impact/strobe-burst/fx.json +42 -0
- package/skills/agentvfx/templates/impact/strobe-burst/main.frag +43 -0
- package/skills/agentvfx/templates/light/anamorphic-streak/demo-anamorphic-cinema.json +10 -0
- package/skills/agentvfx/templates/light/anamorphic-streak/demo-data.json +10 -0
- package/skills/agentvfx/templates/light/anamorphic-streak/fx.json +47 -0
- package/skills/agentvfx/templates/light/anamorphic-streak/main.frag +45 -0
- package/skills/agentvfx/templates/light/anamorphic-streak/pass0.frag +22 -0
- package/skills/agentvfx/templates/light/anamorphic-streak/pass1.frag +16 -0
- package/skills/agentvfx/templates/light/anamorphic-streak/pass2.frag +16 -0
- package/skills/agentvfx/templates/light/anamorphic-streak/pass3.frag +16 -0
- package/skills/agentvfx/templates/light/bloom-glow/demo-clip01-low.json +11 -0
- package/skills/agentvfx/templates/light/bloom-glow/demo-neon-night.json +10 -0
- package/skills/agentvfx/templates/light/bloom-glow/demo-phosphor.json +11 -0
- package/skills/agentvfx/templates/light/bloom-glow/fx.json +53 -0
- package/skills/agentvfx/templates/light/bloom-glow/main.frag +85 -0
- package/skills/agentvfx/templates/light/bloom-glow/pass0.frag +21 -0
- package/skills/agentvfx/templates/light/bloom-glow/pass1.frag +50 -0
- package/skills/agentvfx/templates/light/bloom-glow/pass2.frag +44 -0
- package/skills/agentvfx/templates/light/bloom-glow/pass3.frag +32 -0
- package/skills/agentvfx/templates/light/bloom-glow/pass4.frag +48 -0
- package/skills/agentvfx/templates/light/bloom-glow/pass5.frag +46 -0
- package/skills/agentvfx/templates/light/god-rays/demo-golden-hour.json +10 -0
- package/skills/agentvfx/templates/light/god-rays/demo-point-lamp.json +10 -0
- package/skills/agentvfx/templates/light/god-rays/fx.json +39 -0
- package/skills/agentvfx/templates/light/god-rays/main.frag +54 -0
- package/skills/agentvfx/templates/light/lens-flare/demo-clip01-bar.json +11 -0
- package/skills/agentvfx/templates/light/lens-flare/demo-eye-bar.json +10 -0
- package/skills/agentvfx/templates/light/lens-flare/demo-sun-ghosts.json +10 -0
- package/skills/agentvfx/templates/light/lens-flare/fx.json +49 -0
- package/skills/agentvfx/templates/light/lens-flare/main.frag +86 -0
- package/skills/agentvfx/templates/light/lens-flare/pass0.frag +24 -0
- package/skills/agentvfx/templates/light/light-leak/demo-slit.json +10 -0
- package/skills/agentvfx/templates/light/light-leak/demo-vintage-burn.json +10 -0
- package/skills/agentvfx/templates/light/light-leak/fx.json +40 -0
- package/skills/agentvfx/templates/light/light-leak/main.frag +46 -0
- package/skills/agentvfx/templates/light/light-stage/fx.json +29 -0
- package/skills/agentvfx/templates/light/light-stage/main.frag +56 -0
- package/skills/agentvfx/templates/light/light-sweep/demo-hard-bar.json +12 -0
- package/skills/agentvfx/templates/light/light-sweep/demo-logo-sweep.json +10 -0
- package/skills/agentvfx/templates/light/light-sweep/demo-onset.json +11 -0
- package/skills/agentvfx/templates/light/light-sweep/fx.json +45 -0
- package/skills/agentvfx/templates/light/light-sweep/main.frag +29 -0
- package/skills/agentvfx/templates/light/light-sweep/pass0.frag +17 -0
- package/skills/agentvfx/templates/light/light-sweep/pass1.frag +15 -0
- package/skills/agentvfx/templates/light/neon-saber/demo-hairline.json +10 -0
- package/skills/agentvfx/templates/light/neon-saber/demo-saber-laser.json +10 -0
- package/skills/agentvfx/templates/light/neon-saber/fx.json +48 -0
- package/skills/agentvfx/templates/light/neon-saber/main.frag +27 -0
- package/skills/agentvfx/templates/light/neon-saber/pass0.frag +46 -0
- package/skills/agentvfx/templates/light/neon-saber/pass1.frag +15 -0
- package/skills/agentvfx/templates/psychedelic/echo-flow/demo-trail.json +1 -0
- package/skills/agentvfx/templates/psychedelic/echo-flow/fx.json +38 -0
- package/skills/agentvfx/templates/psychedelic/echo-flow/main.frag +19 -0
- package/skills/agentvfx/templates/psychedelic/echo-flow/pass0.frag +16 -0
- package/skills/agentvfx/templates/psychedelic/echo-flow/pass1.frag +20 -0
- package/skills/agentvfx/templates/psychedelic/echo-flow/pass2.frag +11 -0
- package/skills/agentvfx/templates/psychedelic/echo-flow/pass3.frag +4 -0
- package/skills/agentvfx/templates/psychedelic/hologram-scan/demo-cyan.json +1 -0
- package/skills/agentvfx/templates/psychedelic/hologram-scan/fx.json +36 -0
- package/skills/agentvfx/templates/psychedelic/hologram-scan/main.frag +30 -0
- package/skills/agentvfx/templates/psychedelic/kaleido-fold/demo-six.json +1 -0
- package/skills/agentvfx/templates/psychedelic/kaleido-fold/fx.json +37 -0
- package/skills/agentvfx/templates/psychedelic/kaleido-fold/main.frag +10 -0
- package/skills/agentvfx/templates/psychedelic/kaleido-fold/pass0.frag +34 -0
- package/skills/agentvfx/templates/psychedelic/mosh-melt/demo-classic.json +1 -0
- package/skills/agentvfx/templates/psychedelic/mosh-melt/fx.json +38 -0
- package/skills/agentvfx/templates/psychedelic/mosh-melt/main.frag +20 -0
- package/skills/agentvfx/templates/psychedelic/mosh-melt/pass0.frag +22 -0
- package/skills/agentvfx/templates/psychedelic/sacred/NOTES.md +13 -0
- package/skills/agentvfx/templates/psychedelic/sacred/demo-classic.json +1 -0
- package/skills/agentvfx/templates/psychedelic/sacred/demo-halo.json +1 -0
- package/skills/agentvfx/templates/psychedelic/sacred/demo-slow-tide.json +1 -0
- package/skills/agentvfx/templates/psychedelic/sacred/demo-thermal.json +1 -0
- package/skills/agentvfx/templates/psychedelic/sacred/fx.json +263 -0
- package/skills/agentvfx/templates/psychedelic/sacred/main.frag +109 -0
- package/skills/agentvfx/templates/psychedelic/sacred/pass0.frag +25 -0
- package/skills/agentvfx/templates/psychedelic/sacred/pass1.frag +23 -0
- package/skills/agentvfx/templates/psychedelic/tidal-bands/demo-classic.json +1 -0
- package/skills/agentvfx/templates/psychedelic/tidal-bands/fx.json +37 -0
- package/skills/agentvfx/templates/psychedelic/tidal-bands/main.frag +54 -0
- package/skills/agentvfx/templates/scope/_chrome.glsl +242 -0
- package/skills/agentvfx/templates/scope/goniometer/demo-boot-green.json +1 -0
- package/skills/agentvfx/templates/scope/goniometer/demo-field-lime.json +1 -0
- package/skills/agentvfx/templates/scope/goniometer/demo-field-ultramarine.json +1 -0
- package/skills/agentvfx/templates/scope/goniometer/demo-glow-phosphor.json +1 -0
- package/skills/agentvfx/templates/scope/goniometer/demo-hud-black.json +1 -0
- package/skills/agentvfx/templates/scope/goniometer/fx.json +635 -0
- package/skills/agentvfx/templates/scope/goniometer/main.frag +33 -0
- package/skills/agentvfx/templates/scope/goniometer/pass0.frag +58 -0
- package/skills/agentvfx/templates/scope/goniometer/pass1.frag +43 -0
- package/skills/agentvfx/templates/scope/goniometer/pass2.frag +12 -0
- package/skills/agentvfx/templates/scope/goniometer/pass3.frag +12 -0
- package/skills/agentvfx/templates/scope/goniometer/pass4.frag +12 -0
- package/skills/agentvfx/templates/scope/goniometer/pass5.frag +12 -0
- package/skills/agentvfx/templates/scope/goniometer/pass6.frag +251 -0
- package/skills/agentvfx/templates/scope/scope-polar/demo-boot-green.json +1 -0
- package/skills/agentvfx/templates/scope/scope-polar/demo-field-lime.json +1 -0
- package/skills/agentvfx/templates/scope/scope-polar/demo-field-ultramarine.json +1 -0
- package/skills/agentvfx/templates/scope/scope-polar/demo-glow-phosphor.json +1 -0
- package/skills/agentvfx/templates/scope/scope-polar/demo-hud-black.json +1 -0
- package/skills/agentvfx/templates/scope/scope-polar/fx.json +686 -0
- package/skills/agentvfx/templates/scope/scope-polar/main.frag +39 -0
- package/skills/agentvfx/templates/scope/scope-polar/pass0.frag +84 -0
- package/skills/agentvfx/templates/scope/scope-polar/pass1.frag +49 -0
- package/skills/agentvfx/templates/scope/scope-polar/pass2.frag +12 -0
- package/skills/agentvfx/templates/scope/scope-polar/pass3.frag +12 -0
- package/skills/agentvfx/templates/scope/scope-polar/pass4.frag +12 -0
- package/skills/agentvfx/templates/scope/scope-polar/pass5.frag +12 -0
- package/skills/agentvfx/templates/scope/scope-polar/pass6.frag +251 -0
- package/skills/agentvfx/templates/scope/scope-triggered/demo-boot-green.json +1 -0
- package/skills/agentvfx/templates/scope/scope-triggered/demo-field-lime.json +1 -0
- package/skills/agentvfx/templates/scope/scope-triggered/demo-field-ultramarine.json +1 -0
- package/skills/agentvfx/templates/scope/scope-triggered/demo-glow-phosphor.json +1 -0
- package/skills/agentvfx/templates/scope/scope-triggered/demo-hud-black.json +1 -0
- package/skills/agentvfx/templates/scope/scope-triggered/fx.json +712 -0
- package/skills/agentvfx/templates/scope/scope-triggered/main.frag +36 -0
- package/skills/agentvfx/templates/scope/scope-triggered/pass0.frag +78 -0
- package/skills/agentvfx/templates/scope/scope-triggered/pass1.frag +50 -0
- package/skills/agentvfx/templates/scope/scope-triggered/pass2.frag +12 -0
- package/skills/agentvfx/templates/scope/scope-triggered/pass3.frag +12 -0
- package/skills/agentvfx/templates/scope/scope-triggered/pass4.frag +12 -0
- package/skills/agentvfx/templates/scope/scope-triggered/pass5.frag +12 -0
- package/skills/agentvfx/templates/scope/scope-triggered/pass6.frag +251 -0
- package/skills/agentvfx/templates/scope/spectrogram-scroll/demo-boot-green.json +1 -0
- package/skills/agentvfx/templates/scope/spectrogram-scroll/demo-field-lime.json +1 -0
- package/skills/agentvfx/templates/scope/spectrogram-scroll/demo-field-ultramarine.json +1 -0
- package/skills/agentvfx/templates/scope/spectrogram-scroll/demo-glow-phosphor.json +1 -0
- package/skills/agentvfx/templates/scope/spectrogram-scroll/demo-hud-black.json +1 -0
- package/skills/agentvfx/templates/scope/spectrogram-scroll/fx.json +595 -0
- package/skills/agentvfx/templates/scope/spectrogram-scroll/main.frag +83 -0
- package/skills/agentvfx/templates/scope/spectrogram-scroll/pass0.frag +52 -0
- package/skills/agentvfx/templates/scope/spectrogram-scroll/pass1.frag +251 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/demo-boot-green.json +1 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/demo-field-lime.json +1 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/demo-field-ultramarine.json +1 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/demo-glow-phosphor.json +1 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/demo-hud-black.json +1 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/fx.json +642 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/main.frag +33 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/pass0.frag +56 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/pass1.frag +44 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/pass2.frag +12 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/pass3.frag +12 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/pass4.frag +12 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/pass5.frag +12 -0
- package/skills/agentvfx/templates/scope/xy-phosphor/pass6.frag +251 -0
- package/skills/agentvfx/templates/spectrum/_src/bars-linear/fx.src.json +61 -0
- package/skills/agentvfx/templates/spectrum/_src/bars-linear/main.src.frag +112 -0
- package/skills/agentvfx/templates/spectrum/_src/bars-linear/pass0.src.frag +2 -0
- package/skills/agentvfx/templates/spectrum/_src/bars-mirror/fx.src.json +51 -0
- package/skills/agentvfx/templates/spectrum/_src/bars-mirror/main.src.frag +72 -0
- package/skills/agentvfx/templates/spectrum/_src/bars-mirror/pass0.src.frag +2 -0
- package/skills/agentvfx/templates/spectrum/_src/bass-circle/fx.src.json +56 -0
- package/skills/agentvfx/templates/spectrum/_src/bass-circle/main.src.frag +136 -0
- package/skills/agentvfx/templates/spectrum/_src/bass-circle/pass0.src.frag +2 -0
- package/skills/agentvfx/templates/spectrum/_src/build.mjs +68 -0
- package/skills/agentvfx/templates/spectrum/_src/label-bars/fx.src.json +54 -0
- package/skills/agentvfx/templates/spectrum/_src/label-bars/main.src.frag +102 -0
- package/skills/agentvfx/templates/spectrum/_src/label-bars/pass0.src.frag +2 -0
- package/skills/agentvfx/templates/spectrum/_src/shared/bars-fn.glsl +64 -0
- package/skills/agentvfx/templates/spectrum/_src/shared/bars-pass.glsl +22 -0
- package/skills/agentvfx/templates/spectrum/_src/shared/clock.glsl +7 -0
- package/skills/agentvfx/templates/spectrum/_src/shared/hud.glsl +50 -0
- package/skills/agentvfx/templates/spectrum/_src/shared/stage.glsl +74 -0
- package/skills/agentvfx/templates/spectrum/_src/spectrum-particles/fx.src.json +58 -0
- package/skills/agentvfx/templates/spectrum/_src/spectrum-particles/main.src.frag +119 -0
- package/skills/agentvfx/templates/spectrum/_src/spectrum-particles/pass0.src.frag +33 -0
- package/skills/agentvfx/templates/spectrum/_src/spectrum-radial/fx.src.json +56 -0
- package/skills/agentvfx/templates/spectrum/_src/spectrum-radial/main.src.frag +95 -0
- package/skills/agentvfx/templates/spectrum/_src/spectrum-radial/pass0.src.frag +2 -0
- package/skills/agentvfx/templates/spectrum/_src/waveform-line/fx.src.json +60 -0
- package/skills/agentvfx/templates/spectrum/_src/waveform-line/main.src.frag +98 -0
- package/skills/agentvfx/templates/spectrum/_src/waveform-line/pass0.src.frag +43 -0
- package/skills/agentvfx/templates/spectrum/bars-linear/demo-graph-acid.json +1 -0
- package/skills/agentvfx/templates/spectrum/bars-linear/demo-graph-black.json +1 -0
- package/skills/agentvfx/templates/spectrum/bars-linear/fx.json +632 -0
- package/skills/agentvfx/templates/spectrum/bars-linear/main.frag +233 -0
- package/skills/agentvfx/templates/spectrum/bars-linear/pass0.frag +91 -0
- package/skills/agentvfx/templates/spectrum/bars-mirror/demo-field-acid.json +1 -0
- package/skills/agentvfx/templates/spectrum/bars-mirror/demo-field-ultramarine.json +1 -0
- package/skills/agentvfx/templates/spectrum/bars-mirror/fx.json +539 -0
- package/skills/agentvfx/templates/spectrum/bars-mirror/main.frag +193 -0
- package/skills/agentvfx/templates/spectrum/bars-mirror/pass0.frag +91 -0
- package/skills/agentvfx/templates/spectrum/bass-circle/demo-bracket-black.json +1 -0
- package/skills/agentvfx/templates/spectrum/bass-circle/demo-bracket-ultramarine.json +1 -0
- package/skills/agentvfx/templates/spectrum/bass-circle/fx.json +552 -0
- package/skills/agentvfx/templates/spectrum/bass-circle/main.frag +258 -0
- package/skills/agentvfx/templates/spectrum/bass-circle/pass0.frag +91 -0
- package/skills/agentvfx/templates/spectrum/label-bars/demo-deck-black.json +1 -0
- package/skills/agentvfx/templates/spectrum/label-bars/demo-deck-ultramarine.json +1 -0
- package/skills/agentvfx/templates/spectrum/label-bars/fx.json +552 -0
- package/skills/agentvfx/templates/spectrum/label-bars/main.frag +223 -0
- package/skills/agentvfx/templates/spectrum/label-bars/pass0.frag +91 -0
- package/skills/agentvfx/templates/spectrum/spectrum-particles/demo-cloud-black.json +1 -0
- package/skills/agentvfx/templates/spectrum/spectrum-particles/demo-cloud-ultramarine.json +1 -0
- package/skills/agentvfx/templates/spectrum/spectrum-particles/fx.json +584 -0
- package/skills/agentvfx/templates/spectrum/spectrum-particles/main.frag +240 -0
- package/skills/agentvfx/templates/spectrum/spectrum-particles/pass0.frag +101 -0
- package/skills/agentvfx/templates/spectrum/spectrum-radial/demo-starburst-black.json +1 -0
- package/skills/agentvfx/templates/spectrum/spectrum-radial/demo-starburst-ultramarine.json +1 -0
- package/skills/agentvfx/templates/spectrum/spectrum-radial/fx.json +566 -0
- package/skills/agentvfx/templates/spectrum/spectrum-radial/main.frag +217 -0
- package/skills/agentvfx/templates/spectrum/spectrum-radial/pass0.frag +91 -0
- package/skills/agentvfx/templates/spectrum/waveform-line/demo-strip-acid.json +1 -0
- package/skills/agentvfx/templates/spectrum/waveform-line/demo-strip-black.json +1 -0
- package/skills/agentvfx/templates/spectrum/waveform-line/fx.json +481 -0
- package/skills/agentvfx/templates/spectrum/waveform-line/main.frag +219 -0
- package/skills/agentvfx/templates/spectrum/waveform-line/pass0.frag +48 -0
- package/skills/agentvfx/templates/spectrum/waveform-line/pass1.frag +86 -0
- package/skills/agentvfx/test/_render_light.mjs +38 -0
- package/skills/agentvfx/test/audio-stereo.test.mjs +45 -0
- package/skills/agentvfx/test/audio.test.mjs +257 -0
- package/skills/agentvfx/test/brutal.test.mjs +190 -0
- package/skills/agentvfx/test/concept-collage-layout.test.mjs +236 -0
- package/skills/agentvfx/test/concept-collage-scenes.test.mjs +305 -0
- package/skills/agentvfx/test/concept-collage-typefx.test.mjs +153 -0
- package/skills/agentvfx/test/concept-collage.test.mjs +84 -0
- package/skills/agentvfx/test/concept-lattice.test.mjs +133 -0
- package/skills/agentvfx/test/concept-signal-cut.test.mjs +172 -0
- package/skills/agentvfx/test/credit-overlay.test.mjs +58 -0
- package/skills/agentvfx/test/credit.test.mjs +42 -0
- package/skills/agentvfx/test/doctor.test.mjs +31 -0
- package/skills/agentvfx/test/encode.test.mjs +22 -0
- package/skills/agentvfx/test/fixtures/r7-collage-LAYOUTS.json +5780 -0
- package/skills/agentvfx/test/fixtures/score-bad-duration.json +7 -0
- package/skills/agentvfx/test/fixtures/score-bad-safety.json +8 -0
- package/skills/agentvfx/test/fixtures/score-identity-footage.json +8 -0
- package/skills/agentvfx/test/fixtures/score-missing-template.json +7 -0
- package/skills/agentvfx/test/fixtures/score-ok.json +8 -0
- package/skills/agentvfx/test/fixtures/score-strobe-12hz.json +8 -0
- package/skills/agentvfx/test/fixtures/score-text-probe.json +1 -0
- package/skills/agentvfx/test/flash-audit.test.mjs +150 -0
- package/skills/agentvfx/test/flash.test.mjs +83 -0
- package/skills/agentvfx/test/footage.test.mjs +88 -0
- package/skills/agentvfx/test/glitch.test.mjs +272 -0
- package/skills/agentvfx/test/impact.test.mjs +231 -0
- package/skills/agentvfx/test/imports.test.mjs +39 -0
- package/skills/agentvfx/test/light.test.mjs +200 -0
- package/skills/agentvfx/test/loop.test.mjs +80 -0
- package/skills/agentvfx/test/psychedelic.test.mjs +99 -0
- package/skills/agentvfx/test/render.test.mjs +73 -0
- package/skills/agentvfx/test/sacred.test.mjs +175 -0
- package/skills/agentvfx/test/schema.test.mjs +103 -0
- package/skills/agentvfx/test/scope.test.mjs +306 -0
- package/skills/agentvfx/test/spectrum.test.mjs +165 -0
- package/skills/agentvfx/test/text.test.mjs +142 -0
- package/skills/agentvfx/test/web.test.mjs +397 -0
- package/skills/agentvfx/test-media/SOURCES.md +39 -0
- package/skills/agentvfx/test-media/beat-132.mp3 +0 -0
- package/skills/agentvfx/test-media/clip-01.mp4 +0 -0
- package/skills/agentvfx/test-media/clip-02.mp4 +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# agentvfx licence
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Woojin Go (wjgoarxiv)
|
|
4
|
+
|
|
5
|
+
Required Notice: Copyright (c) 2026 Woojin Go (https://github.com/wjgoarxiv/agentvfx)
|
|
6
|
+
|
|
7
|
+
The agentvfx licence has two parts that apply together: the Additional Terms in Part 1, and the licence text in Part 2,
|
|
8
|
+
which is the PolyForm Noncommercial License 1.0.0 reproduced unchanged. Part 1 adds a permission, a credit condition
|
|
9
|
+
and a restriction to Part 2; it does not change any wording of Part 2. "These terms" in Part 2 means Parts 1 and 2
|
|
10
|
+
together, so everything granted in Part 1 is one of "your licenses" and is subject to Acceptance, Patent Defense and
|
|
11
|
+
Violations. To meet "Notices" in Part 2, give each recipient of the software this whole file, or its URL
|
|
12
|
+
(https://github.com/wjgoarxiv/agentvfx/blob/main/LICENSE); the polyformproject.org URL alone is not enough.
|
|
13
|
+
|
|
14
|
+
## Part 1. Additional Terms
|
|
15
|
+
|
|
16
|
+
### 1. Creator permission
|
|
17
|
+
|
|
18
|
+
If you are an individual (a natural person), you may run the software to render video, images and audio ("output"),
|
|
19
|
+
and use that output in your own creative work for any purpose, including commercial purposes. For example, you may
|
|
20
|
+
release your own music video, earn advertising, subscription, sponsorship or tip income on your own channel, or play
|
|
21
|
+
the output in your own live or VJ performance.
|
|
22
|
+
|
|
23
|
+
For this permission:
|
|
24
|
+
|
|
25
|
+
- you count as an individual if you are a sole proprietor (for example a registered 개인사업자) or self-employed,
|
|
26
|
+
as long as the work is your own;
|
|
27
|
+
- several individuals making a work together under their own names, such as a band, count as individuals together,
|
|
28
|
+
as long as none of them acts for a company or other organisation in doing so;
|
|
29
|
+
- sponsored content on your own channel or in your own work is covered.
|
|
30
|
+
|
|
31
|
+
This permission does not cover:
|
|
32
|
+
|
|
33
|
+
- work for an employer, or on behalf of a company or other organisation (a noncommercial organisation keeps only the
|
|
34
|
+
permissions it already has in Part 2);
|
|
35
|
+
- output made for someone else to publish or use as theirs, such as a client's advertisement or a deliverable for a
|
|
36
|
+
label or a brand;
|
|
37
|
+
- selling, licensing or offering the software, its templates or presets, or rendering as a service, or offering output
|
|
38
|
+
on its own as a product (stock footage, loops, packs, NFTs); output may be sold only as part of a larger work of
|
|
39
|
+
your own.
|
|
40
|
+
|
|
41
|
+
Any other commercial use needs a commercial licence from the licensor. Ask at
|
|
42
|
+
https://github.com/wjgoarxiv/agentvfx/issues.
|
|
43
|
+
|
|
44
|
+
### 2. No AI training
|
|
45
|
+
|
|
46
|
+
Under any permission, you may not use the software, its source, shaders, templates or presets to train, fine-tune or
|
|
47
|
+
evaluate a machine-learning model, or to build a dataset for that purpose. Using an AI agent to operate the software
|
|
48
|
+
for your own use is not training and is allowed.
|
|
49
|
+
|
|
50
|
+
### 3. Output
|
|
51
|
+
|
|
52
|
+
As far as the law allows, you own the output you make. The licensor claims no rights in your output except in any part
|
|
53
|
+
of the software or templates that the output contains. People who only watch, host, stream or receive output need no
|
|
54
|
+
licence from the licensor, and they are not bound by these terms. You are, and you remain responsible for what you
|
|
55
|
+
publish or hand over.
|
|
56
|
+
|
|
57
|
+
### 4. Credit
|
|
58
|
+
|
|
59
|
+
If you publish, stream, publicly show or give anyone output made with agentvfx, under any permission, including
|
|
60
|
+
Part 2, you must credit agentvfx.
|
|
61
|
+
|
|
62
|
+
By default every render burns a small "agentvfx" credit into a corner of the frame. While that credit is visible in
|
|
63
|
+
what you publish, you need nothing more; do not crop, cover or edit it out.
|
|
64
|
+
|
|
65
|
+
If you switch it off in the score (`"credit": { "overlay": false }`), or the output carries no on-screen credit (for
|
|
66
|
+
example a web export), you must instead credit agentvfx in text where viewers can reasonably find it (the description,
|
|
67
|
+
caption, credits, or a page the output links to):
|
|
68
|
+
|
|
69
|
+
Made with agentvfx by Woojin Go - https://github.com/wjgoarxiv/agentvfx
|
|
70
|
+
|
|
71
|
+
Where space is short, `VFX: agentvfx (github.com/wjgoarxiv/agentvfx)` is enough. Every render writes the text credit
|
|
72
|
+
to CREDIT.txt next to the film and into the MP4 metadata; leave both in place.
|
|
73
|
+
|
|
74
|
+
When you give output to someone who will publish it, pass the credit on with it: leave the on-screen credit in the
|
|
75
|
+
frame, or give them the text line and CREDIT.txt. The credit is a condition of every licence under these terms. A
|
|
76
|
+
missing credit can be added within the period that "Violations" in Part 2 allows.
|
|
77
|
+
|
|
78
|
+
### 5. Web export
|
|
79
|
+
|
|
80
|
+
If you use scripts/export-web.mjs, keep the LICENSE file it writes with the exported folder.
|
|
81
|
+
|
|
82
|
+
### 6. Names
|
|
83
|
+
|
|
84
|
+
These terms give no right to use the name "agentvfx", the name "Woojin Go" or the agentvfx logo, except to give the
|
|
85
|
+
credit in section 4 and to say truthfully where a work comes from. If you share a changed copy of the software (a fork),
|
|
86
|
+
you must give it a name that does not contain "agentvfx", you must not present it as agentvfx or as made or endorsed by
|
|
87
|
+
the licensor, and you must say that it is changed from agentvfx, with a link to https://github.com/wjgoarxiv/agentvfx.
|
|
88
|
+
|
|
89
|
+
### 7. Earlier copies and third-party portions
|
|
90
|
+
|
|
91
|
+
Copies obtained under the MIT License before 5 November 2026 keep that licence for those copies only. Every version
|
|
92
|
+
this repository publishes is under these terms. Portions adapted from mexicat/pdoom-video remain under their own
|
|
93
|
+
MIT License, and the capture engine copied from lit-typographic-motion is MIT in its own repository; see
|
|
94
|
+
skills/agentvfx/NOTICE for the files and the notice.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
Part 2 follows, unchanged.
|
|
99
|
+
|
|
100
|
+
# PolyForm Noncommercial License 1.0.0
|
|
101
|
+
|
|
102
|
+
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
|
103
|
+
|
|
104
|
+
## Acceptance
|
|
105
|
+
|
|
106
|
+
In order to get any license under these terms, you must agree to them as both strict obligations and conditions to all your licenses.
|
|
107
|
+
|
|
108
|
+
## Copyright License
|
|
109
|
+
|
|
110
|
+
The licensor grants you a copyright license for the software to do everything you might do with the software that would otherwise infringe the licensor's copyright in it for any permitted purpose. However, you may only distribute the software according to [Distribution License](#distribution-license) and make changes or new works based on the software according to [Changes and New Works License](#changes-and-new-works-license).
|
|
111
|
+
|
|
112
|
+
## Distribution License
|
|
113
|
+
|
|
114
|
+
The licensor grants you an additional copyright license to distribute copies of the software. Your license to distribute covers distributing the software with changes and new works permitted by [Changes and New Works License](#changes-and-new-works-license).
|
|
115
|
+
|
|
116
|
+
## Notices
|
|
117
|
+
|
|
118
|
+
You must ensure that anyone who gets a copy of any part of the software from you also gets a copy of these terms or the URL for them above, as well as copies of any plain-text lines beginning with `Required Notice:` that the licensor provided with the software. For example:
|
|
119
|
+
|
|
120
|
+
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
|
|
121
|
+
|
|
122
|
+
## Changes and New Works License
|
|
123
|
+
|
|
124
|
+
The licensor grants you an additional copyright license to make changes and new works based on the software for any permitted purpose.
|
|
125
|
+
|
|
126
|
+
## Patent License
|
|
127
|
+
|
|
128
|
+
The licensor grants you a patent license for the software that covers patent claims the licensor can license, or becomes able to license, that you would infringe by using the software.
|
|
129
|
+
|
|
130
|
+
## Noncommercial Purposes
|
|
131
|
+
|
|
132
|
+
Any noncommercial purpose is a permitted purpose.
|
|
133
|
+
|
|
134
|
+
## Personal Uses
|
|
135
|
+
|
|
136
|
+
Personal use for research, experiment, and testing for the benefit of public knowledge, personal study, private entertainment, hobby projects, amateur pursuits, or religious observance, without any anticipated commercial application, is use for a permitted purpose.
|
|
137
|
+
|
|
138
|
+
## Noncommercial Organizations
|
|
139
|
+
|
|
140
|
+
Use by any charitable organization, educational institution, public research organization, public safety or health organization, environmental protection organization, or government institution is use for a permitted purpose regardless of the source of funding or obligations resulting from the funding.
|
|
141
|
+
|
|
142
|
+
## Fair Use
|
|
143
|
+
|
|
144
|
+
You may have "fair use" rights for the software under the law. These terms do not limit them.
|
|
145
|
+
|
|
146
|
+
## No Other Rights
|
|
147
|
+
|
|
148
|
+
These terms do not allow you to sublicense or transfer any of your licenses to anyone else, or prevent the licensor from granting licenses to anyone else. These terms do not imply any other licenses.
|
|
149
|
+
|
|
150
|
+
## Patent Defense
|
|
151
|
+
|
|
152
|
+
If you make any written claim that the software infringes or contributes to infringement of any patent, your patent license for the software granted under these terms ends immediately. If your company makes such a claim, your patent license ends immediately for work on behalf of your company.
|
|
153
|
+
|
|
154
|
+
## Violations
|
|
155
|
+
|
|
156
|
+
The first time you are notified in writing that you have violated any of these terms, or done anything with the software not covered by your licenses, your licenses can nonetheless continue if you come into full compliance with these terms, and take practical steps to correct past violations, within 32 days of receiving notice. Otherwise, all your licenses end immediately.
|
|
157
|
+
|
|
158
|
+
## No Liability
|
|
159
|
+
|
|
160
|
+
***As far as the law allows, the software comes as is, without any warranty or condition, and the licensor will not be liable to you for any damages arising out of these terms or the use or nature of the software, under any kind of legal claim.***
|
|
161
|
+
|
|
162
|
+
## Definitions
|
|
163
|
+
|
|
164
|
+
The **licensor** is the individual or entity offering these terms, and the **software** is the software the licensor makes available under these terms.
|
|
165
|
+
|
|
166
|
+
**You** refers to the individual or entity agreeing to these terms.
|
|
167
|
+
|
|
168
|
+
**Your company** is any legal entity, sole proprietorship, or other kind of organization that you work for, plus all organizations that have control over, are under the control of, or are under common control with that organization. **Control** means ownership of substantially all the assets of an entity, or the power to direct its management and policies by vote, contract, or otherwise. Control can be direct or indirect.
|
|
169
|
+
|
|
170
|
+
**Your licenses** are all the licenses granted to you for the software under these terms.
|
|
171
|
+
|
|
172
|
+
**Use** means anything you do with the software requiring one of your licenses.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
agentvfx is licensed under the agentvfx licence (see LICENSE), except for the portions adapted from mexicat/pdoom-video. Those stay under the MIT License printed below, and any of them may be taken out and reused under that licence, including for commercial use.
|
|
2
|
+
|
|
3
|
+
Adapted from mexicat/pdoom-video (MIT, Giacomo Magnanini), listed from the source-file header comments:
|
|
4
|
+
engine/core/util.mjs
|
|
5
|
+
engine/web/gl.mjs
|
|
6
|
+
engine/web/glsl-common.mjs
|
|
7
|
+
engine/web/scale.mjs
|
|
8
|
+
engine/node/chrome.mjs
|
|
9
|
+
|
|
10
|
+
Copied and adapted from LitClaude lit-typographic-motion 1.0.45 (MIT, (c) 2026 wjgoarxiv, the same author). It stays MIT in its own repository, its pdoom-video portions keep the notice below, and the copies here are offered under the agentvfx licence:
|
|
11
|
+
engine/core/constants.mjs
|
|
12
|
+
engine/core/flash.mjs
|
|
13
|
+
engine/node/board.mjs
|
|
14
|
+
engine/node/encode.mjs
|
|
15
|
+
engine/node/frame-worker.mjs
|
|
16
|
+
engine/node/stage-capture.mjs
|
|
17
|
+
engine/node/stage-serve.mjs
|
|
18
|
+
|
|
19
|
+
Anything adapted later may add to these lists; a file whose header says "MIT, see NOTICE" is covered by this notice.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
Portions of this engine are adapted from mexicat/pdoom-video
|
|
23
|
+
(https://github.com/mexicat/pdoom-video), commit
|
|
24
|
+
ca251e3dddda422b364385eb484b5a3593a0990d.
|
|
25
|
+
|
|
26
|
+
Copyright (c) 2026 Giacomo Magnanini
|
|
27
|
+
|
|
28
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
29
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
30
|
+
in the Software without restriction, including without limitation the rights
|
|
31
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
32
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
33
|
+
furnished to do so, subject to the following conditions:
|
|
34
|
+
|
|
35
|
+
The above copyright notice and this permission notice shall be included in all
|
|
36
|
+
copies or substantial portions of the Software.
|
|
37
|
+
|
|
38
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
39
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
40
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
41
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
42
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
43
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
44
|
+
SOFTWARE.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentvfx
|
|
3
|
+
description: Agent-directed, music-reactive VFX clips from an FX score. WebGL2 shader templates (psychedelic, spectrum, scope, impact, light, glitch, neo-brutalist collage and lattice), optional Blender background plates, a flash audit on every render, silent ping-pong loops, and a web export for live use in apps and sites. Use when someone asks for a VFX clip, a visualizer, a festival or stage loop, a music-reactive background, or a live shader effect for a web page.
|
|
4
|
+
license: LicenseRef-agentvfx. Noncommercial use; see LICENSE for the complete terms.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# agentvfx
|
|
8
|
+
|
|
9
|
+
You direct; the engine renders. You never write shader code for a clip. You pick a template, a preset and a few typed parameters, write them into an FX score (JSON), and the engine renders it in headless Chrome (WebGL2), encodes H.264 with ffmpeg, and audits it for flashes.
|
|
10
|
+
|
|
11
|
+
Run every command from this folder (the skill root). Paths inside a score resolve against the current directory.
|
|
12
|
+
|
|
13
|
+
## 1. Check the machine
|
|
14
|
+
|
|
15
|
+
node scripts/vfx.mjs doctor
|
|
16
|
+
|
|
17
|
+
`ok: true` means Chrome with GPU WebGL2 and ffmpeg were found. Otherwise read `blockers` and tell the user what to install (`CHROME_PATH`, `FFMPEG_PATH`). Blender 5.x is needed only for plates (`BLENDER_PATH`).
|
|
18
|
+
|
|
19
|
+
## 2. Pick a look
|
|
20
|
+
|
|
21
|
+
node scripts/vfx.mjs list # family, template id, input kind, presets
|
|
22
|
+
node scripts/vfx.mjs list --json # with descriptions
|
|
23
|
+
|
|
24
|
+
`input` says what a template needs: `generative` (nothing), `footage` (`input.video`), or `either`. Start from a preset; change two or three parameters at most per round. Show the user the result before inventing more.
|
|
25
|
+
|
|
26
|
+
## 3. Write the score
|
|
27
|
+
|
|
28
|
+
Schema: `schemas/fx-score.schema.json`. Minimal:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{ "version": 1, "template": "lattice", "preset": "vermilion-fine",
|
|
32
|
+
"input": { "video": "test-media/clip-01.mp4", "audio": "test-media/beat-132.mp3" },
|
|
33
|
+
"durationSec": 4, "seed": 47, "out": "my-lattice" }
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- `durationSec` is 3–5. `seed` makes the render repeatable.
|
|
37
|
+
- `params` override the preset (names and ranges come from the template's `fx.json`).
|
|
38
|
+
- `bindings` tie a parameter to an audio feature (`bass`, `onset`, `beat`, `bands.N`, …) with `gain`, `offset`, `attackMs`, `releaseMs`. Keep attack on the onset frame and release short (about 60 ms): snappy reads as professional, heavy smoothing reads as a demo.
|
|
39
|
+
- `hits` fire an extra template on an onset or beat; `cuts` hard-cut the stack on a beat; `stack` layers up to two templates over the base.
|
|
40
|
+
- `labels` and `textStyle` set the engine's text layer (installed fonts by name; generic fallback when missing).
|
|
41
|
+
|
|
42
|
+
Check it without rendering:
|
|
43
|
+
|
|
44
|
+
node scripts/vfx.mjs validate my-score.json
|
|
45
|
+
|
|
46
|
+
## 4. Render and look
|
|
47
|
+
|
|
48
|
+
node scripts/vfx.mjs render my-score.json --out out/my-lattice --width 640 --height 360
|
|
49
|
+
|
|
50
|
+
Preview small first (640x360), then raise the size for the final. The command prints JSON with the film path, the flash result and the stills. Open `stills/sheet.png` and every strip before you describe the clip to anyone. A render you have not looked at is not done.
|
|
51
|
+
|
|
52
|
+
Every render burns a small `agentvfx` credit into a corner of the frame (switch it off with `"credit": { "overlay": false }` in the score), writes `CREDIT.txt` and puts the credit line in the MP4 metadata. Crediting agentvfx is a condition of its licence for anything published: while the on-screen credit stays in the frame nothing more is needed; if the overlay is off, or the user hands the clip on without it, the text credit must go in the post, description or credits. When you report a finished clip, give the user the line to paste:
|
|
53
|
+
|
|
54
|
+
Made with agentvfx by Woojin Go - https://github.com/wjgoarxiv/agentvfx
|
|
55
|
+
|
|
56
|
+
The licence is the agentvfx licence: Additional Terms plus the PolyForm Noncommercial License 1.0.0 (see LICENSE). An individual (sole proprietors and a band of individuals included) may use the clips they render in their own work, also commercially: their own channel, sponsored content on it, music videos, their own VJ or live set. Employers, companies, client work, output made for someone else to publish, paid rendering services, selling clips or templates on their own, and AI training on the code or templates are not covered and need a commercial licence (or are not allowed). A changed copy shared with others (a fork) must carry a name without "agentvfx" and say it is changed from agentvfx. If the user's request is clearly one of those, say so before rendering. When you hand a clip over to be published, tell the user to keep the on-screen credit or pass the credit line along.
|
|
57
|
+
|
|
58
|
+
## 5. Flash safety
|
|
59
|
+
|
|
60
|
+
Every render carries a flash audit (general and red flashes per second, WCAG 2.3.1 style). Default mode `stage` keeps full intensity and writes `SAFETY.txt` when limits are exceeded. `"safety": { "mode": "broadcast-safe" }` enforces the limits; `"safeVariant": true` adds `film.safe.mp4` beside the full version. Tell the user plainly when a clip exceeds the limits.
|
|
61
|
+
|
|
62
|
+
## 6. Background plates (optional, Blender)
|
|
63
|
+
|
|
64
|
+
node scripts/plate.mjs --scene terminalcore --shot gallery --out out/plate --width 640 --height 360 --seconds 4
|
|
65
|
+
|
|
66
|
+
Procedural scenes, no downloaded assets. Use the plate's `film.mp4` as `input.video`. `--quality final` is slow (about 2 minutes per 1080p frame); ask before starting one. See `references/plates.md`.
|
|
67
|
+
|
|
68
|
+
## 7. Silent loops
|
|
69
|
+
|
|
70
|
+
node scripts/loop.mjs out/my-lattice/film.mp4 reels/my-lattice.mp4 --preview reels/preview/my-lattice.webp --audit out/my-lattice/loop-flash.json
|
|
71
|
+
|
|
72
|
+
Plays the clip forward then backward (no seam, no audio track) and flash-audits the loop played twice. Exit code 3 means the loop exceeds the flash limits. Reversing can double the flashes around a turn; `--hold 6` pauses six frames at each turn, which often brings such a loop back inside the limit. A red change that becomes a red flash when reversed cannot be fixed this way — say so and let the user decide.
|
|
73
|
+
|
|
74
|
+
## 8. Live on a web page
|
|
75
|
+
|
|
76
|
+
node scripts/export-web.mjs lattice collage --out out/web
|
|
77
|
+
|
|
78
|
+
Writes a self-contained runtime, the chosen templates and a demo page. Respects `prefers-reduced-motion`. See `references/web.md`.
|
|
79
|
+
|
|
80
|
+
## Rules
|
|
81
|
+
|
|
82
|
+
- Never ship or commit music you do not have the rights to redistribute. A render's motion may come from a track while the published loop stays silent.
|
|
83
|
+
- References inspire; they are not copied. Do not reproduce a frame, logo, mark or font file from someone else's work.
|
|
84
|
+
- Do not bundle font files. Name installed fonts; they fall back when absent.
|
|
85
|
+
|
|
86
|
+
## More
|
|
87
|
+
|
|
88
|
+
- `references/template-format.md` — how a template is built (`fx.json`, passes, presets, text layer).
|
|
89
|
+
- `references/plates.md` — Blender plates.
|
|
90
|
+
- `references/web.md` — web runtime API.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// agentvfx (agentvfx licence, see LICENSE). Adapted from lit-typographic-motion 1.0.45 engine/core/constants.mjs.
|
|
2
|
+
// Every number the agentvfx engine and its gate use, in one place.
|
|
3
|
+
|
|
4
|
+
export const ENGINE_COMMIT = "ca251e3dddda422b364385eb484b5a3593a0990d";
|
|
5
|
+
export const ENGINE_CREDIT = `mexicat/pdoom-video ${ENGINE_COMMIT} (MIT)`;
|
|
6
|
+
export const CREDIT_LINE = "Capture engine adapted from lit-typographic-motion 1.0.45, itself adapted from mexicat/pdoom-video (MIT, Giacomo Magnanini), commit `ca251e3`.";
|
|
7
|
+
|
|
8
|
+
// ---- frame geometry ----
|
|
9
|
+
export const FRAME = Object.freeze({ width: 1920, height: 1080, maxScale: 4 });
|
|
10
|
+
|
|
11
|
+
// ---- exit codes (numbers kept from the source family; never renumbered) ----
|
|
12
|
+
export const EXIT = Object.freeze({
|
|
13
|
+
OK: 0,
|
|
14
|
+
USAGE: 2,
|
|
15
|
+
BLOCKED_NO_CHROME: 10,
|
|
16
|
+
BLOCKED_NO_WEBGL2: 11,
|
|
17
|
+
BLOCKED_NO_FFMPEG_FOR_VIDEO: 12,
|
|
18
|
+
GATE_FAIL_QA: 13,
|
|
19
|
+
SCORE_INVALID: 16,
|
|
20
|
+
STAGE_CONTRACT_ERROR: 17,
|
|
21
|
+
STAGE_NONDETERMINISTIC: 18,
|
|
22
|
+
STAGE_NETWORK_REQUEST: 19,
|
|
23
|
+
BLOCKED_ASSET_MISSING: 22,
|
|
24
|
+
});
|
|
25
|
+
export const EXIT_NAME = Object.freeze(Object.fromEntries(Object.entries(EXIT).map(([name, code]) => [code, name])));
|
|
26
|
+
|
|
27
|
+
export const TIMELINE = Object.freeze({ defaultFps: 30, defaultSeed: 20260926, minDurationSec: 3, maxDurationSec: 5 });
|
|
28
|
+
|
|
29
|
+
/** Software-rasterizer match list (case-insensitive substrings). */
|
|
30
|
+
export const SOFTWARE_RENDERERS = Object.freeze([
|
|
31
|
+
"swiftshader", "llvmpipe", "softpipe", "lavapipe", "apple software renderer", "microsoft basic render driver",
|
|
32
|
+
]);
|
|
33
|
+
export const UNKNOWN_RENDERER = "unknown (debug-info extension unavailable)";
|
|
34
|
+
|
|
35
|
+
// ---- Chrome launch ladder ----
|
|
36
|
+
export const CHROME_ALWAYS = Object.freeze([
|
|
37
|
+
"--disable-background-timer-throttling", "--disable-renderer-backgrounding", "--disable-backgrounding-occluded-windows",
|
|
38
|
+
]);
|
|
39
|
+
export const CHROME_RUNGS = Object.freeze({
|
|
40
|
+
darwin: [["--use-angle=metal", "--enable-gpu-rasterization", "--ignore-gpu-blocklist"]],
|
|
41
|
+
linux: [["--use-angle=gl", "--enable-gpu-rasterization", "--ignore-gpu-blocklist"]],
|
|
42
|
+
win32: [["--use-angle=d3d11", "--enable-gpu-rasterization"]],
|
|
43
|
+
software: ["--use-angle=swiftshader", "--enable-unsafe-swiftshader"],
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// ---- gate: flash audit grid and thresholds (WCAG 2.2 excursion method) ----
|
|
47
|
+
export const GATE = Object.freeze({
|
|
48
|
+
flashGrid: [320, 180],
|
|
49
|
+
flashCellPx: 6,
|
|
50
|
+
flashDelta: 0.1,
|
|
51
|
+
flashDarkCeiling: 0.8,
|
|
52
|
+
flashWindowCells: [107, 60],
|
|
53
|
+
flashWindowArea: 0.25,
|
|
54
|
+
flashEdgeFrames: 3,
|
|
55
|
+
redRatio: 0.8,
|
|
56
|
+
redScale: 320,
|
|
57
|
+
redDelta: 20,
|
|
58
|
+
maxFlashesPerSecond: 3,
|
|
59
|
+
maxRedFlashesPerSecond: 3,
|
|
60
|
+
nearBlackPercentile: 0.995,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// ---- preview ladder ----
|
|
64
|
+
export const PREVIEW = Object.freeze({
|
|
65
|
+
rungs: [
|
|
66
|
+
{ width: 960, fps: 30 },
|
|
67
|
+
{ width: 720, fps: 24 },
|
|
68
|
+
{ width: 540, fps: 20 },
|
|
69
|
+
],
|
|
70
|
+
minWidth: 540,
|
|
71
|
+
webpQuality: 60,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// ---- encode: H.264 master, BT.709 matrix and tags, tv range ----
|
|
75
|
+
export const ENCODE_ARGS = Object.freeze([
|
|
76
|
+
// setparams tags the frames themselves: without it libx264 writes the matrix but leaves the
|
|
77
|
+
// primaries and transfer unspecified, whatever -color_primaries / -color_trc say.
|
|
78
|
+
"-vf", "scale=out_color_matrix=bt709:out_range=tv,format=yuv420p,setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709:range=tv",
|
|
79
|
+
"-c:v", "libx264", "-preset", "slow", "-crf", "16", "-tune", "grain", "-x264-params", "aq-mode=3",
|
|
80
|
+
"-colorspace", "bt709", "-color_primaries", "bt709", "-color_trc", "bt709", "-color_range", "tv",
|
|
81
|
+
"-movflags", "+faststart",
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
export const MAX_ROUNDS = 3;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Flash audit thresholds (WCAG 2.2 general/red flash, ITU-R BT.1702-3, IRIS-style extended rule).
|
|
2
|
+
export const FLASH = Object.freeze({
|
|
3
|
+
grid: [320, 180],
|
|
4
|
+
windowCells: [107, 60], // 1/3 x 1/3 of the grid
|
|
5
|
+
windowArea: 0.25,
|
|
6
|
+
edgeFrames: 1, // a window transition is judged on the single frame whose cells registered it
|
|
7
|
+
delta: 0.1,
|
|
8
|
+
darkCeiling: 0.8,
|
|
9
|
+
redRatio: 0.8,
|
|
10
|
+
redScale: 320,
|
|
11
|
+
redDelta: 20,
|
|
12
|
+
maxFlashesPerSecond: 3,
|
|
13
|
+
maxTransitionsPerSecond: 6, // BT.1702-3: more than 6 transitions (3 flashes) in any 1 s
|
|
14
|
+
extendedMinTransitions: 4,
|
|
15
|
+
extendedMaxTransitions: 6,
|
|
16
|
+
extendedSeconds: 4,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/** 8-bit sRGB code value to linear light. */
|
|
20
|
+
export const LINEAR_LUT = Float32Array.from({ length: 256 }, (_, v) => {
|
|
21
|
+
const s = v / 255;
|
|
22
|
+
return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
23
|
+
});
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
// Flash audit for agentvfx, adapted from lit-typographic-motion 1.0.45 engine/core/flash.mjs (MIT).
|
|
2
|
+
// Pure report: frames are read, never modified (spec Amendment A1: stage mode keeps full intensity).
|
|
3
|
+
//
|
|
4
|
+
// Method: each RGBA frame is area-averaged onto a 320x180 linear-light grid. A flash is a pair of
|
|
5
|
+
// OPPOSING luminance changes of the SAME area (WCAG 2.2 / BT.1702-3), so the test is per cell first:
|
|
6
|
+
// a cell registers a transition when its luminance moves at least 0.1 from the extreme it reached
|
|
7
|
+
// since its last transition, in the direction opposite to that last transition, while the darker of
|
|
8
|
+
// the two is below 0.8. Continued motion the same way is not a new transition. A frame-level
|
|
9
|
+
// transition exists when, on that one frame, the cells that registered a transition in one
|
|
10
|
+
// direction cover more than 25% of some 1/3 x 1/3 window of the grid. Cells that brighten and
|
|
11
|
+
// cells that darken in the same frame (a moving edge) never combine into a transition pair; a
|
|
12
|
+
// frame where both directions fill a window counts as a single alternating transition. Red uses
|
|
13
|
+
// the same method on (R-G-B)x320 over saturated-red cells (R/(R+G+B) >= 0.8). Verdicts: BT.1702-3
|
|
14
|
+
// (more than 6 transitions in any 1 s), any red flash, and the IRIS-style extended rule (at least 4
|
|
15
|
+
// transitions in each of 4 consecutive seconds, at any frame offset; reported alone, not folded
|
|
16
|
+
// into `exceeds`).
|
|
17
|
+
import { FLASH, LINEAR_LUT } from "./flash-constants.mjs";
|
|
18
|
+
|
|
19
|
+
export { LINEAR_LUT };
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The audit grid for a frame: 6x6 px cells and the 640x360 window, transposed for a portrait
|
|
23
|
+
* frame (180x320 cells, a 60x107 window) so the 10-degree field keeps its size in either format.
|
|
24
|
+
*/
|
|
25
|
+
export function gridFor(width = 1920, height = 1080) {
|
|
26
|
+
const [gw, gh] = FLASH.grid;
|
|
27
|
+
const [ww, wh] = FLASH.windowCells;
|
|
28
|
+
return width >= height ? { gw, gh, ww, wh } : { gw: gh, gh: gw, ww: wh, wh: ww };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Per-cell hysteresis. `hi`/`lo` are the extremes since the cell's last counted transition, `last`
|
|
33
|
+
* is that transition's direction (0 = none yet). A transition counts only against `last`.
|
|
34
|
+
*/
|
|
35
|
+
class CellTracker {
|
|
36
|
+
constructor(cells, delta, ceiling) {
|
|
37
|
+
this.delta = delta;
|
|
38
|
+
this.ceiling = ceiling;
|
|
39
|
+
this.hi = new Float32Array(cells);
|
|
40
|
+
this.lo = new Float32Array(cells);
|
|
41
|
+
this.last = new Int8Array(cells);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
start(values) {
|
|
45
|
+
this.hi.set(values);
|
|
46
|
+
this.lo.set(values);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Feed cell i's value; returns +1 / -1 when it counts a transition, else 0. */
|
|
50
|
+
update(i, v) {
|
|
51
|
+
const { hi, lo, last, delta, ceiling } = this;
|
|
52
|
+
let dir = 0;
|
|
53
|
+
if (last[i] !== 1 && v - lo[i] >= delta && Math.min(v, lo[i]) < ceiling) dir = 1;
|
|
54
|
+
else if (last[i] !== -1 && hi[i] - v >= delta && Math.min(v, hi[i]) < ceiling) dir = -1;
|
|
55
|
+
if (dir) {
|
|
56
|
+
hi[i] = v; lo[i] = v; last[i] = dir;
|
|
57
|
+
} else {
|
|
58
|
+
if (v > hi[i]) hi[i] = v;
|
|
59
|
+
if (v < lo[i]) lo[i] = v;
|
|
60
|
+
}
|
|
61
|
+
return dir;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Streaming detector. Each frame is { R, G, B }: linear 0..1 cell averages on the grid. */
|
|
66
|
+
export class FlashDetector {
|
|
67
|
+
constructor(grid = gridFor()) {
|
|
68
|
+
const { gw, gh, ww, wh } = grid;
|
|
69
|
+
this.grid = grid;
|
|
70
|
+
this.cells = gw * gh;
|
|
71
|
+
this.windowLimit = FLASH.windowArea * ww * wh;
|
|
72
|
+
this.frames = 0;
|
|
73
|
+
this.lum = new CellTracker(this.cells, FLASH.delta, FLASH.darkCeiling);
|
|
74
|
+
this.red = new CellTracker(this.cells, FLASH.redDelta, Infinity);
|
|
75
|
+
this.prevL = new Float32Array(this.cells);
|
|
76
|
+
this.sat = new Int32Array((gw + 1) * (gh + 1));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Feed one frame; returns { up, down, redUp, redDown, stepArea, edge }. The four flags say that,
|
|
81
|
+
* on this frame, the cells registering a transition that way cover a window; `edge` says this
|
|
82
|
+
* frame moved any cell that way.
|
|
83
|
+
*/
|
|
84
|
+
push({ R, G, B }) {
|
|
85
|
+
const CELLS = this.cells;
|
|
86
|
+
const L = new Float32Array(CELLS);
|
|
87
|
+
const V = new Float32Array(CELLS);
|
|
88
|
+
for (let i = 0; i < CELLS; i++) {
|
|
89
|
+
L[i] = 0.2126 * R[i] + 0.7152 * G[i] + 0.0722 * B[i];
|
|
90
|
+
const sum = R[i] + G[i] + B[i];
|
|
91
|
+
V[i] = sum > 0 && R[i] / sum >= FLASH.redRatio ? Math.max(0, R[i] - G[i] - B[i]) * FLASH.redScale : 0;
|
|
92
|
+
}
|
|
93
|
+
const maps = { up: new Uint8Array(CELLS), down: new Uint8Array(CELLS), redUp: new Uint8Array(CELLS), redDown: new Uint8Array(CELLS) };
|
|
94
|
+
const edge = { up: false, down: false, redUp: false, redDown: false };
|
|
95
|
+
let stepCells = 0;
|
|
96
|
+
if (this.frames === 0) {
|
|
97
|
+
this.lum.start(L);
|
|
98
|
+
this.red.start(V);
|
|
99
|
+
} else {
|
|
100
|
+
for (let i = 0; i < CELLS; i++) {
|
|
101
|
+
if (Math.abs(L[i] - this.prevL[i]) >= FLASH.delta) stepCells += 1;
|
|
102
|
+
const l = this.lum.update(i, L[i]);
|
|
103
|
+
if (l) { maps[l > 0 ? "up" : "down"][i] = 1; edge[l > 0 ? "up" : "down"] = true; }
|
|
104
|
+
const r = this.red.update(i, V[i]);
|
|
105
|
+
if (r) { maps[r > 0 ? "redUp" : "redDown"][i] = 1; edge[r > 0 ? "redUp" : "redDown"] = true; }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
this.prevL = L;
|
|
109
|
+
this.frames += 1;
|
|
110
|
+
const result = { stepArea: +(stepCells / CELLS).toFixed(4), edge };
|
|
111
|
+
for (const dir of ["up", "down", "redUp", "redDown"]) result[dir] = edge[dir] && this.windowHit(maps[dir]);
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Largest window count of this frame's transition map via a summed-area table.
|
|
116
|
+
windowHit(map) {
|
|
117
|
+
const { gw: GW, gh: GH, ww: WW, wh: WH } = this.grid;
|
|
118
|
+
const sat = this.sat;
|
|
119
|
+
const stride = GW + 1;
|
|
120
|
+
for (let y = 0; y < GH; y++) {
|
|
121
|
+
let row = 0;
|
|
122
|
+
for (let x = 0; x < GW; x++) {
|
|
123
|
+
row += map[y * GW + x];
|
|
124
|
+
sat[(y + 1) * stride + x + 1] = sat[y * stride + x + 1] + row;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (sat[GH * stride + GW] <= this.windowLimit) return false;
|
|
128
|
+
for (let y = 0; y + WH <= GH; y++) {
|
|
129
|
+
for (let x = 0; x + WW <= GW; x++) {
|
|
130
|
+
const count = sat[(y + WH) * stride + x + WW] - sat[y * stride + x + WW] - sat[(y + WH) * stride + x] + sat[y * stride + x];
|
|
131
|
+
if (count > this.windowLimit) return true;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Area-average an RGBA8 frame of any size onto its audit grid in linear light. */
|
|
139
|
+
export function cellsFromRgba(bytes, width, height, lut = LINEAR_LUT, { gw: GW, gh: GH } = gridFor(width, height)) {
|
|
140
|
+
const CELLS = GW * GH;
|
|
141
|
+
const R = new Float32Array(CELLS);
|
|
142
|
+
const G = new Float32Array(CELLS);
|
|
143
|
+
const B = new Float32Array(CELLS);
|
|
144
|
+
const count = new Float32Array(CELLS);
|
|
145
|
+
for (let y = 0; y < height; y++) {
|
|
146
|
+
const cy = Math.min(GH - 1, Math.floor((y * GH) / height)) * GW;
|
|
147
|
+
for (let x = 0; x < width; x++) {
|
|
148
|
+
const c = cy + Math.min(GW - 1, Math.floor((x * GW) / width));
|
|
149
|
+
const o = (y * width + x) * 4;
|
|
150
|
+
R[c] += lut[bytes[o]];
|
|
151
|
+
G[c] += lut[bytes[o + 1]];
|
|
152
|
+
B[c] += lut[bytes[o + 2]];
|
|
153
|
+
count[c] += 1;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (let i = 0; i < CELLS; i++) {
|
|
157
|
+
const n = count[i] || 1;
|
|
158
|
+
R[i] /= n; G[i] /= n; B[i] /= n;
|
|
159
|
+
}
|
|
160
|
+
return { R, G, B };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Consecutive same-direction transitions collapse into one edge; an edge is one "transition".
|
|
164
|
+
function edgesIn(events, start, span) {
|
|
165
|
+
let edges = 0;
|
|
166
|
+
let last = 0;
|
|
167
|
+
for (const t of events) {
|
|
168
|
+
if (t.frame < start || t.frame >= start + span || t.dir === last) continue;
|
|
169
|
+
edges += 1;
|
|
170
|
+
last = t.dir;
|
|
171
|
+
}
|
|
172
|
+
return edges;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function summarize(general, red, count, fps) {
|
|
176
|
+
const span = Math.round(fps);
|
|
177
|
+
let worst = { startFrame: 0, transitions: 0 };
|
|
178
|
+
for (const { frame } of general) {
|
|
179
|
+
const transitions = edgesIn(general, frame, span);
|
|
180
|
+
if (transitions > worst.transitions) worst = { startFrame: frame, transitions };
|
|
181
|
+
}
|
|
182
|
+
const perSecond = [];
|
|
183
|
+
for (let s = 0; s * span < count; s++) {
|
|
184
|
+
perSecond.push({ second: s, transitions: edgesIn(general, s * span, span), redTransitions: edgesIn(red, s * span, span) });
|
|
185
|
+
}
|
|
186
|
+
let extendedFlashing = false;
|
|
187
|
+
for (let s0 = 0; !extendedFlashing && s0 + FLASH.extendedSeconds * span <= count; s0++) {
|
|
188
|
+
extendedFlashing = Array.from({ length: FLASH.extendedSeconds }, (_, k) => edgesIn(general, s0 + k * span, span))
|
|
189
|
+
.every((n) => n >= FLASH.extendedMinTransitions);
|
|
190
|
+
}
|
|
191
|
+
const redFlashes = Math.floor(edgesIn(red, 0, count) / 2);
|
|
192
|
+
return {
|
|
193
|
+
exceeds: worst.transitions > FLASH.maxTransitionsPerSecond || redFlashes > 0,
|
|
194
|
+
worstWindow: { ...worst, startSec: +(worst.startFrame / fps).toFixed(3) },
|
|
195
|
+
flashesPerSecondMax: Math.floor(worst.transitions / 2),
|
|
196
|
+
redFlashes,
|
|
197
|
+
extendedFlashing,
|
|
198
|
+
perSecond,
|
|
199
|
+
limits: { ...FLASH, fps, frames: count },
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// One event per frame: a lone direction is that direction; both directions filling windows on the
|
|
204
|
+
// same frame (opposite areas moving against each other) is one transition, alternating with the last.
|
|
205
|
+
function frameDir(up, down, last) {
|
|
206
|
+
if (up && down) return last === 1 ? -1 : 1;
|
|
207
|
+
return up ? 1 : down ? -1 : 0;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Streaming auditor: push RGBA frames one at a time (only transition events are kept, never the
|
|
212
|
+
* frames), then finish() for the report. Reports only; the pushed bytes are not modified.
|
|
213
|
+
*/
|
|
214
|
+
export function createFlashAuditor({ fps, width, height }) {
|
|
215
|
+
if (!(Number.isFinite(fps) && fps > 0)) throw new TypeError("createFlashAuditor: fps must be a positive number");
|
|
216
|
+
const grid = gridFor(width, height);
|
|
217
|
+
const detector = new FlashDetector(grid);
|
|
218
|
+
const general = [];
|
|
219
|
+
const red = [];
|
|
220
|
+
return {
|
|
221
|
+
push(frame) {
|
|
222
|
+
const frameIndex = detector.frames;
|
|
223
|
+
const r = detector.push(cellsFromRgba(frame.data, frame.width, frame.height, LINEAR_LUT, grid));
|
|
224
|
+
const dir = frameDir(r.up, r.down, general.at(-1)?.dir ?? 0);
|
|
225
|
+
if (dir) general.push({ frame: frameIndex, dir });
|
|
226
|
+
const redDir = frameDir(r.redUp, r.redDown, red.at(-1)?.dir ?? 0);
|
|
227
|
+
if (redDir) red.push({ frame: frameIndex, dir: redDir });
|
|
228
|
+
},
|
|
229
|
+
finish: () => summarize(general, red, detector.frames, fps),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Audit a whole frame sequence ({ width, height, data } RGBA sRGB) at `fps`. */
|
|
234
|
+
export function auditFlash(frames, { fps }) {
|
|
235
|
+
if (!(Number.isFinite(fps) && fps > 0)) throw new TypeError("auditFlash: fps must be a positive number");
|
|
236
|
+
const first = frames[0] ?? { width: 1920, height: 1080 };
|
|
237
|
+
const auditor = createFlashAuditor({ fps, width: first.width, height: first.height });
|
|
238
|
+
for (const frame of frames) auditor.push(frame);
|
|
239
|
+
return auditor.finish();
|
|
240
|
+
}
|