From 5f1c03db3110c893fb1ffce65f9c43448facb7a7 Mon Sep 17 00:00:00 2001 From: Z User Date: Fri, 6 Nov 2026 01:14:43 +0000 Subject: [PATCH] e0315efb-ff50-4f97-ab76-b2f751e9b03b --- src/components/ava/help-panel.tsx | 32 +- src/lib/ava/blend-gpu.ts | 244 +++++++++ src/lib/ava/blend.ts | 507 ++++++++++++++++++ src/lib/ava/engine.ts | 364 ++++++++----- src/lib/ava/script.ts | 24 +- src/lib/ava/types.ts | 14 +- src/lib/release-notes.ts | 22 + src/lib/version.ts | 29 +- .../grep_1793922566950_a0822d8d9a9c.txt | 122 +++++ .../grep_1793924530808_9b7030ab1e59.txt | 62 +++ worklog.md | 38 ++ 11 files changed, 1309 insertions(+), 149 deletions(-) create mode 100644 src/lib/ava/blend-gpu.ts create mode 100644 src/lib/ava/blend.ts create mode 100644 tool-results/grep_1793922566950_a0822d8d9a9c.txt create mode 100644 tool-results/grep_1793924530808_9b7030ab1e59.txt diff --git a/src/components/ava/help-panel.tsx b/src/components/ava/help-panel.tsx index ae447c9..ae899fc 100755 --- a/src/components/ava/help-panel.tsx +++ b/src/components/ava/help-panel.tsx @@ -4,6 +4,7 @@ 'use client' import type { ReactNode } from 'react' +import { BLEND_SPECS, BLEND_GROUP_LABELS, type BlendGroup } from '@/lib/ava/blend' const FRAME_VARS: [string, string][] = [ ['n', 'point count (4–4096, default 400 -- set in [init] or [frame])'], @@ -23,6 +24,7 @@ const FRAME_VARS: [string, string][] = [ ['w / h', 'canvas size in pixels'], ['aspect', 'canvas width / height -- divide x by it for perfect circles'], ['persist', 'motion-trail persistence 0..1, writable per frame -- 1 = the framebuffer never fades (old content then leaves only through a bg* transform or a blend: replace repaint)'], + ['blend', 'per-frame override of the blend: header -- set it to a mode\'s number from the Blend modes table below (1 = normal, 2 = additive, 3 = replace, 6 = subtract, ...); read after [frame]/[beat], before drawing'], ['bgrot', 'background spin in radians per frame -- + clockwise, - counter-clockwise; 0 = off (set in [init] / [frame] / [beat]; persists like any variable)'], ['bgx / bgy', 'background drift per frame, the -1..1 screen convention (y is up) -- slide the whole picture up, down, left or right'], ['bgzoom', 'background scale per frame -- below 1 draw-in (shrinks toward the center), above 1 blow-out (expands); 1 = off'], @@ -157,6 +159,34 @@ export function HelpPanel() { + +

+ The blend: header picks how fresh strokes mix with what is + already on screen (base = the picture, blend = the stroke). Names are case- and separator-insensitive —{' '} + color burn = colorburn. The{' '} + blend variable can switch the mode per frame by its number. +

+
+ {( + ['core', 'darken', 'lighten', 'contrast', 'invert', 'component', 'mask'] as BlendGroup[] + ).map((g) => ( +
+

+ {BLEND_GROUP_LABELS[g]} +

+ [s, i] as const) + .filter(([s]) => s.group === g) + .map(([s, i]) => [ + `${i + 1} · ${s.key}`, + s.aliases?.length ? `${s.note} [also: ${s.aliases.join(', ')}]` : s.note, + ])} + /> +
+ ))} +
+
+

A plain-text file: optional header keys before the first section, then any of the four sections in any order. @@ -167,7 +197,7 @@ name: My Visualization author: you description: shown in the preset list mode: lines # lines | dots | solid -blend: additive # additive | alpha | multiply | screen | subtract | replace +blend: additive # any of the 41 keywords -- see the Blend modes table persist: 0.85 # trail persistence 0..1 (1 = never fades) linewidth: 2 diff --git a/src/lib/ava/blend-gpu.ts b/src/lib/ava/blend-gpu.ts new file mode 100644 index 0000000..34c4622 --- /dev/null +++ b/src/lib/ava/blend-gpu.ts @@ -0,0 +1,244 @@ +// AVA — WebGL blend compositor (v7.15). +// +// Implements the blend keywords Canvas2D has no composite operator for +// (21 of the 41): dissolve, linear burn, darker/lighter color, vivid / +// linear / pin light, hard mix, a TRUE clamped subtract, divide, average, +// negation, phoenix, grain extract/merge, reflect, glow, and the four +// After Effects masks (stencil / silhouette, luma + alpha). +// +// Per frame the engine draws the stroke passes onto a scratch canvas +// (source-over, so the two-pass glow keeps its usual tuning), then: +// 1. uploads the live canvas (backdrop) and the scratch (stroke layer) +// as premultiplied textures, +// 2. renders one fullscreen quad with the mode's formula, +// 3. the engine copies the result back with composite 'copy'. +// +// Per pixel: a = straight backdrop color, b = straight stroke color, +// c = the stroke's coverage (scratch alpha, AA included). The standard +// tail is out = mix(a, modeRGB, c) at opacity mix(dst.a, 1, c) — +// outside the strokes the backdrop passes through EXACTLY, so the +// 'copy' back is lossless. The four masks scale the backdrop instead, +// dissolve speckles at full intensity (re-seeded from uFrame so the +// grain animates), and everything is written premultiplied (the WebGL +// context is premultipliedAlpha: true). +// +// Formulas per the sources documented in blend.ts. Fallbacks: if WebGL +// is unavailable the engine composites each gpu mode with its nearest +// native operator (spec.fallbackOp) — see engine.ts gpuEnsure. + +const VERT_SRC = ` +attribute vec2 aPos; +varying vec2 vUV; +void main() { + // texture t=0 is the canvas's TOP row; flip so the quad renders upright + vUV = vec2(aPos.x * 0.5 + 0.5, 0.5 - aPos.y * 0.5); + gl_Position = vec4(aPos, 0.0, 1.0); +} +` + +const FRAG_SRC = ` +precision highp float; +varying vec2 vUV; +uniform sampler2D uDst; +uniform sampler2D uSrc; +uniform int uMode; +uniform float uFrame; + +float lum(vec3 c) { return dot(c, vec3(0.299, 0.587, 0.114)); } +float hash(vec2 p) { + // Hoskins-style hash: no large-argument sin (which skews badly on some + // GPU stacks -- measured in the v7.15 E2E: the classic sin-hash spent + // 95% of its values below 0.51, making dissolve nearly deterministic). + vec3 p3 = fract(vec3(p.xyx) * 0.1031); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.x + p3.y) * p3.z); +} +vec3 vivid(vec3 a, vec3 b) { + vec3 burn = max(vec3(1.0) - (vec3(1.0) - a) / max(vec3(2.0) * b, vec3(1e-3)), vec3(0.0)); + vec3 dodge = min(a / max(vec3(2.0) - vec3(2.0) * b, vec3(1e-3)), vec3(1.0)); + return mix(burn, dodge, step(vec3(0.5), b)); +} + +void main() { + vec4 D = texture2D(uDst, vUV); // backdrop, premultiplied upload + vec4 S = texture2D(uSrc, vUV); // stroke layer, premultiplied upload + float c = S.a; // stroke coverage 0..1 (AA included) + vec3 a = D.a > 0.0 ? D.rgb / max(D.a, 1e-4) : vec3(0.0); // straight backdrop + vec3 b = c > 0.0 ? S.rgb / max(c, 1e-4) : vec3(0.0); // straight stroke + + // -- special-tail modes ------------------------------------------------ + if (uMode == 1) { // dissolve: stochastic full-intensity speckle + // the +uFrame offset re-rolls the grain every frame (animated speckle) + gl_FragColor = hash(vUV * 997.0 + vec2(uFrame * 0.618, uFrame * 0.317)) < c ? vec4(b, 1.0) : D; + return; + } + if (uMode == 18) { // stencil luma: the stroke's brightness masks + float m = mix(1.0, lum(b), c); + gl_FragColor = vec4(D.rgb * m, D.a * m); + return; + } + if (uMode == 19) { // silhouette luma + float m = mix(1.0, 1.0 - lum(b), c); + gl_FragColor = vec4(D.rgb * m, D.a * m); + return; + } + if (uMode == 20) { // stencil alpha: the stroke's own opacity masks + float m = mix(1.0, S.a, c); + gl_FragColor = vec4(D.rgb * m, D.a * m); + return; + } + if (uMode == 21) { // silhouette alpha + float m = mix(1.0, 1.0 - S.a, c); + gl_FragColor = vec4(D.rgb * m, D.a * m); + return; + } + + // -- separable families -------------------------------------------------- + vec3 R = a; + if (uMode == 2) R = max(a + b - 1.0, 0.0); // linear burn + else if (uMode == 3) R = (lum(b) < lum(a)) ? b : a; // darker color + else if (uMode == 4) R = (lum(b) > lum(a)) ? b : a; // lighter color + else if (uMode == 5) R = vivid(a, b); // vivid light + else if (uMode == 6) R = clamp(a + 2.0 * b - 1.0, 0.0, 1.0); // linear light + else if (uMode == 7) { // pin light + vec3 lo = min(a, vec3(2.0) * b); + vec3 hi = max(a, vec3(2.0) * b - vec3(1.0)); + R = mix(lo, hi, step(vec3(0.5), b)); + } + else if (uMode == 8) R = step(vec3(0.5), vivid(a, b)); // hard mix + else if (uMode == 9) R = max(a - b, 0.0); // subtract (true) + else if (uMode == 10) R = min(a / max(b, vec3(1e-3)), vec3(1.0)); // divide + else if (uMode == 11) R = (a + b) * 0.5; // average + else if (uMode == 12) R = vec3(1.0) - abs(a - b); // negation + else if (uMode == 13) R = min(a * a / max(vec3(1.0) - b, vec3(1e-3)), vec3(1.0)); // reflect + else if (uMode == 14) R = min(b * b / max(vec3(1.0) - a, vec3(1e-3)), vec3(1.0)); // glow + else if (uMode == 15) R = min(a, b) - max(a, b) + vec3(1.0); // phoenix + else if (uMode == 16) R = clamp(a - b + 0.5, 0.0, 1.0); // grain extract + else if (uMode == 17) R = clamp(a + b - 0.5, 0.0, 1.0); // grain merge + + // -- standard tail: coverage-weighted, written premultiplied ---------------- + float outA = mix(D.a, 1.0, c); + gl_FragColor = vec4(mix(a, R, c) * outA, outA); +} +` + +function compileShader(gl: WebGLRenderingContext, kind: number, src: string): WebGLShader | null { + const sh = gl.createShader(kind) + if (!sh) return null + gl.shaderSource(sh, src) + gl.compileShader(sh) + if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) { + return null + } + return sh +} + +export class BlendCompositor { + readonly canvas: HTMLCanvasElement + /** true once WebGL is proven unavailable — callers fall back per mode */ + failed = false + + private gl: WebGLRenderingContext | null = null + private prog: WebGLProgram | null = null + private quad: WebGLBuffer | null = null + private texDst: WebGLTexture | null = null + private texSrc: WebGLTexture | null = null + private uDst = 0 + private uSrc = 0 + private uMode = 0 + private uFrame = 0 + + constructor() { + this.canvas = document.createElement('canvas') + } + + /** (Re)create the context/program if needed; false = give up (once). */ + ensure(w: number, h: number): boolean { + if (this.failed) return false + if (!this.gl) { + const gl = this.canvas.getContext('webgl', { + alpha: true, + premultipliedAlpha: true, + preserveDrawingBuffer: true, + }) as WebGLRenderingContext | null + if (!gl) { + this.failed = true + return false + } + this.gl = gl + if (!this.build(gl)) { + this.failed = true + return false + } + } + if (this.canvas.width !== w || this.canvas.height !== h) { + this.canvas.width = w + this.canvas.height = h + } + return true + } + + private build(gl: WebGLRenderingContext): boolean { + const vs = compileShader(gl, gl.VERTEX_SHADER, VERT_SRC) + const fs = compileShader(gl, gl.FRAGMENT_SHADER, FRAG_SRC) + if (!vs || !fs) return false + const prog = gl.createProgram() + if (!prog) return false + gl.attachShader(prog, vs) + gl.attachShader(prog, fs) + gl.linkProgram(prog) + if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) return false + this.prog = prog + + // fullscreen quad + this.quad = gl.createBuffer() + gl.bindBuffer(gl.ARRAY_BUFFER, this.quad) + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW) + const aPos = gl.getAttribLocation(prog, 'aPos') + gl.enableVertexAttribArray(aPos) + gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0) + + // textures (created once; texImage2D re-specifies them per frame) + for (const which of [0, 1]) { + const tex = gl.createTexture() + gl.activeTexture(which === 0 ? gl.TEXTURE0 : gl.TEXTURE1) + gl.bindTexture(gl.TEXTURE_2D, tex) + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) + if (which === 0) this.texDst = tex + else this.texSrc = tex + } + + // canvas uploads arrive premultiplied; do the un/premultiply math in the shader + gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true) + + this.uDst = gl.getUniformLocation(prog, 'uDst') + this.uSrc = gl.getUniformLocation(prog, 'uSrc') + this.uMode = gl.getUniformLocation(prog, 'uMode') + this.uFrame = gl.getUniformLocation(prog, 'uFrame') + return true + } + + /** Render one blended frame into this.canvas. The engine then copies it + * back onto the live canvas with composite 'copy'. */ + blend(dst: HTMLCanvasElement, src: HTMLCanvasElement, mode: number, frame: number): void { + const gl = this.gl + const prog = this.prog + if (!gl || !prog) return + gl.viewport(0, 0, this.canvas.width, this.canvas.height) + gl.useProgram(prog) + gl.activeTexture(gl.TEXTURE0) + gl.bindTexture(gl.TEXTURE_2D, this.texDst) + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, dst) + gl.uniform1i(this.uDst, 0) + gl.activeTexture(gl.TEXTURE1) + gl.bindTexture(gl.TEXTURE_2D, this.texSrc) + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, src) + gl.uniform1i(this.uSrc, 1) + gl.uniform1i(this.uMode, mode) + gl.uniform1f(this.uFrame, frame) + gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4) + } +} diff --git a/src/lib/ava/blend.ts b/src/lib/ava/blend.ts new file mode 100644 index 0000000..0337cb6 --- /dev/null +++ b/src/lib/ava/blend.ts @@ -0,0 +1,507 @@ +// AVA — blend mode registry (v7.15). +// +// The single source of truth for every `blend:` keyword. The v7.14.1 set +// (additive | alpha | multiply | screen | subtract | replace) grew into a +// 41-mode collection covering every compositing family in the request +// list: the full Photoshop set, the GIMP grain pair, the After Effects +// stencil/silhouette masks, Apple/CSS plus-lighter/plus-darker and the +// Pegtop exotica (negation, phoenix, reflect, glow). +// +// A mode is implemented one of two ways: +// 'native' — a direct Canvas2D composite operation. Canvas2D implements +// the W3C compositing formulas (soft light is the spec's +// piecewise D(x) version), so these are exact and cost one +// operator switch. 'replace' keeps its v7.14.1 semantics: +// source-over with the CORE pass at FULL alpha. +// 'gpu' — Canvas2D has no operator for it, so the engine draws the +// stroke passes onto a scratch canvas and the WebGL +// compositor (blend-gpu.ts) applies the per-pixel formula. +// On browsers without WebGL each mode falls back to its +// nearest native operator (fallbackOp). +// +// Formula sources: W3C Compositing and Blending Level 1 (the 12 separable +// + 4 HSL transfer modes), the glsl-blend collection / Pegtop blend modes +// (phoenix = min - max + 1, verified against four independent sources; +// hard mix = vivid light thresholded at 0.5; grain extract/merge from +// GIMP). Notable equivalence, kept as two keywords because applications +// list both: negation (Pegtop, "a softer Difference") and phoenix +// ("combines Darken and Lighten") are algebraically the same curve, +// 1 - |a - b| = min(a,b) - max(a,b) + 1. +// +// Name matching is case- and separator-insensitive: normalize() strips +// everything but a-z0-9, so 'Color Burn', 'color-burn', 'COLORBURN' and +// 'color_burn' all resolve to 'colorburn'. + +export type BlendImpl = 'native' | 'gpu' + +export type BlendGroup = + | 'core' + | 'darken' + | 'lighten' + | 'contrast' + | 'invert' + | 'component' + | 'mask' + +export const BLEND_GROUP_LABELS: Record = { + core: 'Core compositing', + darken: 'Darken family', + lighten: 'Lighten family', + contrast: 'Contrast family', + invert: 'Difference & arithmetic', + component: 'HSL component transfer', + mask: 'Dissolve & masks', +} + +export interface BlendSpec { + /** canonical keyword — lowercase, no separators */ + key: string + /** alternate spellings, normalized the same way */ + aliases?: string[] + impl: BlendImpl + /** native path: the Canvas2D composite operation */ + op?: GlobalCompositeOperation + /** native 'replace' quirk: the core pass runs at FULL alpha */ + fullAlphaCore?: boolean + /** gpu path: shader mode id (blend-gpu.ts) */ + gpuId?: number + /** gpu path: composite op used when WebGL is unavailable */ + fallbackOp: GlobalCompositeOperation + /** pretty name for docs */ + label: string + /** help-panel group */ + group: BlendGroup + /** one-line description (base = the picture, blend = the stroke) */ + note: string +} + +export const BLEND_SPECS: BlendSpec[] = [ + // ── core compositing ──────────────────────────────────────────────────── + { + key: 'normal', + aliases: ['alpha', 'standard', 'sourceover'], + impl: 'native', + op: 'source-over', + fallbackOp: 'source-over', + label: 'Normal', + group: 'core', + note: 'the top layer covers what is underneath; stroke opacity decides how much shows through', + }, + { + key: 'additive', + aliases: ['lineardodge', 'add', 'pluslighter'], + impl: 'native', + op: 'lighter', + fallbackOp: 'lighter', + label: 'Additive (Linear Dodge, Add)', + group: 'core', + note: 'base + blend, capped at white -- adds light directly; the classic glow mode (fire, lens flares, feedback blooms)', + }, + { + key: 'replace', + impl: 'native', + op: 'source-over', + fullAlphaCore: true, + fallbackOp: 'source-over', + label: 'Replace', + group: 'core', + note: 'fresh strokes overwrite the pixels they cover, no mixing -- with persist 1 the center repaints while bg* transforms carry the old color away', + }, + { + key: 'multiply', + impl: 'native', + op: 'multiply', + fallbackOp: 'multiply', + label: 'Multiply', + group: 'core', + note: 'stacked ink or transparencies: white leaves the picture untouched, black stays black', + }, + { + key: 'screen', + impl: 'native', + op: 'screen', + fallbackOp: 'screen', + label: 'Screen', + group: 'core', + note: 'overlapping projected light: black leaves the picture untouched, white stays white', + }, + { + key: 'subtract', + aliases: ['subtractive'], + impl: 'gpu', + gpuId: 9, + fallbackOp: 'difference', + label: 'Subtract', + group: 'core', + note: 'base - blend floored at black -- eats the picture where strokes pass (a true clamped subtract; until 7.14.1 this was approximated with difference)', + }, + { + key: 'behind', + aliases: ['destinationover', 'under'], + impl: 'native', + op: 'destination-over', + fallbackOp: 'destination-over', + label: 'Behind', + group: 'core', + note: 'paints only on transparent areas -- strokes slip UNDER existing art (pair it with clear)', + }, + { + key: 'clear', + aliases: ['erase'], + impl: 'native', + op: 'clear', + fallbackOp: 'clear', + label: 'Clear', + group: 'core', + note: 'erases pixels to transparent along the stroke -- an eraser pen; the hole can later be painted behind', + }, + + // ── darken family ─────────────────────────────────────────────────────── + { + key: 'darken', + impl: 'native', + op: 'darken', + fallbackOp: 'darken', + label: 'Darken', + group: 'darken', + note: 'keeps the darker of base and blend, channel by channel', + }, + { + key: 'colorburn', + aliases: ['burn'], + impl: 'native', + op: 'color-burn', + fallbackOp: 'color-burn', + label: 'Color Burn', + group: 'darken', + note: 'darkens the base by raising contrast -- rich, saturated darks', + }, + { + key: 'linearburn', + aliases: ['plusdarker'], + impl: 'gpu', + gpuId: 2, + fallbackOp: 'multiply', + label: 'Linear Burn', + group: 'darken', + note: 'base + blend - 1: darkens by lowering brightness; stronger than multiply', + }, + { + key: 'darkercolor', + impl: 'gpu', + gpuId: 3, + fallbackOp: 'darken', + label: 'Darker Color', + group: 'darken', + note: 'compares whole colors and keeps the darker one -- no channel cross-talk', + }, + + // ── lighten family ────────────────────────────────────────────────────── + { + key: 'lighten', + impl: 'native', + op: 'lighten', + fallbackOp: 'lighten', + label: 'Lighten', + group: 'lighten', + note: 'keeps the lighter of base and blend, channel by channel', + }, + { + key: 'colordodge', + impl: 'native', + op: 'color-dodge', + fallbackOp: 'color-dodge', + label: 'Color Dodge', + group: 'lighten', + note: 'brightens the base by lowering contrast -- intense highlights', + }, + { + key: 'lightercolor', + impl: 'gpu', + gpuId: 4, + fallbackOp: 'lighten', + label: 'Lighter Color', + group: 'lighten', + note: 'compares whole colors and keeps the lighter one', + }, + + // ── contrast family ───────────────────────────────────────────────────── + { + key: 'overlay', + impl: 'native', + op: 'overlay', + fallbackOp: 'overlay', + label: 'Overlay', + group: 'contrast', + note: 'multiplies the dark parts of the base, screens the light parts', + }, + { + key: 'softlight', + impl: 'native', + op: 'soft-light', + fallbackOp: 'soft-light', + label: 'Soft Light', + group: 'contrast', + note: 'a gentler overlay, like a diffused spotlight (the W3C formula)', + }, + { + key: 'hardlight', + impl: 'native', + op: 'hard-light', + fallbackOp: 'hard-light', + label: 'Hard Light', + group: 'contrast', + note: 'overlay with the layers swapped -- the top layer picks multiply or screen', + }, + { + key: 'vividlight', + impl: 'gpu', + gpuId: 5, + fallbackOp: 'color-burn', + label: 'Vivid Light', + group: 'contrast', + note: 'color burn for dark strokes, color dodge for light ones', + }, + { + key: 'linearlight', + impl: 'gpu', + gpuId: 6, + fallbackOp: 'overlay', + label: 'Linear Light', + group: 'contrast', + note: 'linear burn for dark strokes, linear dodge for light ones', + }, + { + key: 'pinlight', + impl: 'gpu', + gpuId: 7, + fallbackOp: 'hard-light', + label: 'Pin Light', + group: 'contrast', + note: 'darken for dark strokes, lighten for light ones', + }, + { + key: 'hardmix', + impl: 'gpu', + gpuId: 8, + fallbackOp: 'overlay', + label: 'Hard Mix', + group: 'contrast', + note: 'pushes every channel to 0 or 1 -- a posterized look (vivid light thresholded at 0.5)', + }, + + // ── difference & arithmetic ───────────────────────────────────────────── + { + key: 'difference', + aliases: ['diff'], + impl: 'native', + op: 'difference', + fallbackOp: 'difference', + label: 'Difference', + group: 'invert', + note: '|base - blend|: identical colors turn black -- useful for lining layers up', + }, + { + key: 'exclusion', + impl: 'native', + op: 'exclusion', + fallbackOp: 'exclusion', + label: 'Exclusion', + group: 'invert', + note: 'like difference but with lower contrast', + }, + { + key: 'negation', + impl: 'gpu', + gpuId: 12, + fallbackOp: 'difference', + label: 'Negation', + group: 'invert', + note: 'a softer, inverted difference (Pegtop) -- algebraically the same curve as phoenix', + }, + { + key: 'phoenix', + impl: 'gpu', + gpuId: 15, + fallbackOp: 'difference', + label: 'Phoenix', + group: 'invert', + note: 'min - max + 1: combines Darken and Lighten in one curve', + }, + { + key: 'divide', + impl: 'gpu', + gpuId: 10, + fallbackOp: 'screen', + label: 'Divide', + group: 'invert', + note: 'base / blend: brightens the image and lifts color casts', + }, + { + key: 'average', + impl: 'gpu', + gpuId: 11, + fallbackOp: 'source-over', + label: 'Average', + group: 'invert', + note: 'the mean of the two layers', + }, + { + key: 'grainextract', + impl: 'gpu', + gpuId: 16, + fallbackOp: 'difference', + label: 'Grain Extract', + group: 'invert', + note: 'GIMP: pulls texture out of a layer (base - blend + 0.5)', + }, + { + key: 'grainmerge', + impl: 'gpu', + gpuId: 17, + fallbackOp: 'screen', + label: 'Grain Merge', + group: 'invert', + note: 'GIMP: puts the texture back (base + blend - 0.5)', + }, + { + key: 'reflect', + impl: 'gpu', + gpuId: 13, + fallbackOp: 'screen', + label: 'Reflect', + group: 'invert', + note: 'strong lighting: base^2 / (1 - blend)', + }, + { + key: 'glow', + impl: 'gpu', + gpuId: 14, + fallbackOp: 'lighter', + label: 'Glow', + group: 'invert', + note: 'reflect with the layers swapped: blend^2 / (1 - base)', + }, + + // ── HSL component transfer ────────────────────────────────────────────── + { + key: 'hue', + impl: 'native', + op: 'hue', + fallbackOp: 'hue', + label: 'Hue', + group: 'component', + note: 'takes the hue from the stroke, saturation + luminosity from the picture', + }, + { + key: 'saturation', + impl: 'native', + op: 'saturation', + fallbackOp: 'saturation', + label: 'Saturation', + group: 'component', + note: 'takes the saturation from the stroke', + }, + { + key: 'color', + impl: 'native', + op: 'color', + fallbackOp: 'color', + label: 'Color', + group: 'component', + note: 'takes hue + saturation from the stroke, luminosity from the picture -- good for colorizing', + }, + { + key: 'luminosity', + impl: 'native', + op: 'luminosity', + fallbackOp: 'luminosity', + label: 'Luminosity', + group: 'component', + note: "takes the brightness from the stroke, keeps the picture's color", + }, + + // ── dissolve & masks ──────────────────────────────────────────────────── + { + key: 'dissolve', + impl: 'gpu', + gpuId: 1, + fallbackOp: 'source-over', + label: 'Dissolve', + group: 'mask', + note: 'randomly drops pixels based on opacity -- grainy, speckled; re-rolls every frame', + }, + { + key: 'stencil', + aliases: ['stencilluma'], + impl: 'gpu', + gpuId: 18, + fallbackOp: 'source-over', + label: 'Stencil Luma', + group: 'mask', + note: "the stroke's brightness masks the picture: bright reveals, dark hides", + }, + { + key: 'silhouette', + aliases: ['silhouetteluma'], + impl: 'gpu', + gpuId: 19, + fallbackOp: 'source-over', + label: 'Silhouette Luma', + group: 'mask', + note: 'the inverse stencil: bright hides, dark reveals', + }, + { + key: 'stencilalpha', + impl: 'gpu', + gpuId: 20, + fallbackOp: 'source-over', + label: 'Stencil Alpha', + group: 'mask', + note: "the stroke's own opacity masks the picture", + }, + { + key: 'silhouettealpha', + impl: 'gpu', + gpuId: 21, + fallbackOp: 'source-over', + label: 'Silhouette Alpha', + group: 'mask', + note: "the inverse: the stroke's opacity hides the picture", + }, +] + +/** lowercase + strip everything that isn't a-z0-9 */ +export function normalizeBlendName(s: string): string { + return s.trim().toLowerCase().replace(/[^a-z0-9]/g, '') +} + +const BLEND_INDEX = new Map() +for (const spec of BLEND_SPECS) { + BLEND_INDEX.set(spec.key, spec) + for (const alias of spec.aliases ?? []) BLEND_INDEX.set(alias, spec) +} + +/** Resolve any spelling to its spec (canonical or alias). */ +export function findBlend(name: string): BlendSpec | undefined { + return BLEND_INDEX.get(normalizeBlendName(name)) +} + +/** 1-based index of a canonical keyword in the registry (0 if unknown). + * The expression language is numeric-only (Env = Record), + * so the per-frame `blend` variable carries this index; the Help panel's + * table lists the number next to every keyword. */ +export function blendIndex(key: string): number { + return BLEND_SPECS.findIndex((s) => s.key === key) + 1 +} + +/** Resolve a 1-based registry index back to its spec. */ +export function blendByIndex(i: number): BlendSpec | undefined { + const k = Math.trunc(i) + return k >= 1 && k <= BLEND_SPECS.length ? BLEND_SPECS[k - 1] : undefined +} + +/** All canonical keywords, in registry order. */ +export function blendKeywords(): string[] { + return BLEND_SPECS.map((s) => s.key) +} diff --git a/src/lib/ava/engine.ts b/src/lib/ava/engine.ts index 79ccf5f..6d13711 100755 --- a/src/lib/ava/engine.ts +++ b/src/lib/ava/engine.ts @@ -3,16 +3,26 @@ // Owns the requestAnimationFrame loop: // audio bands -> beat tracker -> env -> [frame] -> [beat] -> [point]xN -> draw // -// Drawing supports three modes (lines | dots | solid), six blend composites -// (additive | alpha | multiply | screen | subtract | replace), per-point -// colors, a two-pass glow, and a persistence fade for motion trails -// (persist 1 = no fade at all -- v7.14.1). +// Drawing supports three render modes (lines | dots | solid). The blend +// header (v7.15) selects from the 41-mode registry in blend.ts: native +// keywords composite straight onto the live canvas, the rest run through +// the WebGL compositor (blend-gpu.ts) after a scratch pass. env.blend can +// override the header per frame (reset every frame, like persist). +// +// The framebuffer is alpha-capable (v7.15) -- behind and clear need real +// transparency. The persistence fade is therefore an alpha ERASE +// (destination-out) and the bg* wipe a clearRect; over the black stage +// both read pixel-identically to the old opaque fills, so existing +// presets render exactly as before. persist 1 skips the fade entirely +// (v7.14.1: a true zero-fade framebuffer). +import { blendByIndex, blendIndex, findBlend } from './blend' +import { BlendCompositor } from './blend-gpu' import { AudioEngine } from './audio' import { BeatTracker } from './beat' import { AVA_HOOKS, resetEelBuffers } from './expression' import type { AvaScript } from './script' -import type { BandConfig, BandLevels, BeatConfig, BeatFrame, BlendMode } from './types' +import type { BandConfig, BandLevels, BeatConfig, BeatFrame, RenderMode } from './types' import { DEFAULT_BAND_CONFIG, DEFAULT_BEAT_CONFIG } from './types' const MAX_POINTS = 8192 @@ -27,22 +37,20 @@ function bgNum(v: number | undefined, neutral: number): number { return Number.isFinite(x) ? x : neutral } -/** v7.14.1 -- blend header -> Canvas2D composite operation for the content - * pass. 'subtract' maps to canvas 'difference' (|dst - src|): Canvas2D has - * no clamped true-subtract op; difference is the classic approximation and - * shares the property the mode exists for -- it can never climb to white. - * 'replace' also composites source-over, but with the core pass at FULL - * alpha (see the draw section) so fresh strokes overwrite the pixels under - * them instead of stacking -- the pairing that makes a persist-1 feedback - * blow-out hold its color instead of saturating. */ -const BLEND_COMPOSITE: Record = { - additive: 'lighter', - alpha: 'source-over', - multiply: 'multiply', - screen: 'screen', - subtract: 'difference', - replace: 'source-over', +/** v7.15 stroke-pass gains. GAINS_STD is every mode's default two-pass + * glow tuning (unchanged since the original engine). GAINS_REPLACE is the + * v7.14.1 replace tuning: the CORE pass at FULL alpha, so the stroke owns + * its pixels outright (halo slightly stronger: it converges toward the + * source color, never past it). */ +interface DrawGains { + halo: number + core: number + dotsGlow: number + dotsCore: number + solid: number } +const GAINS_STD: DrawGains = { halo: 0.22, core: 0.9, dotsGlow: 0.18, dotsCore: 0.85, solid: 0.65 } +const GAINS_REPLACE: DrawGains = { halo: 0.25, core: 1, dotsGlow: 0.25, dotsCore: 1, solid: 1 } export interface EngineStats { fps: number @@ -88,6 +96,16 @@ export class AvaEngine { private bgBuffer: HTMLCanvasElement | null = null private bgBufCtx: CanvasRenderingContext2D | null = null + /** v7.15 scratch for gpu blend modes: the two stroke passes draw here + * (source-over), then the WebGL compositor blends it onto the live + * canvas in one per-pixel pass. Same lazy lifecycle as bgBuffer. */ + private blendBuffer: HTMLCanvasElement | null = null + private blendBufCtx: CanvasRenderingContext2D | null = null + private compositor: BlendCompositor | null = null + /** latched when WebGL proves unavailable -- gpu modes fall back to their + * nearest native operator (spec.fallbackOp). */ + private gpuBroken = false + constructor() { // AVS-eel compatibility hooks — the expression engine reads audio/time // through these (getspec/getosc/gettime). Headless tests can override. @@ -106,13 +124,15 @@ export class AvaEngine { start(canvas: HTMLCanvasElement): void { this.stop() this.canvas = canvas - const ctx = canvas.getContext('2d', { alpha: false }) + // v7.15: alpha-capable framebuffer (default { alpha: true }) -- behind + // and clear need real transparency. The stage behind the canvas is + // bg-black, so a transparent buffer displays identically to the old + // opaque black one; it starts clean (no fill). + const ctx = canvas.getContext('2d') if (!ctx) return this.ctx = ctx this.canFilter = typeof ctx.filter === 'string' this.transition = null - this.ctx.fillStyle = '#000' - this.ctx.fillRect(0, 0, canvas.width, canvas.height) this.clockStart = performance.now() this.lastNow = this.clockStart this.running = true @@ -214,10 +234,12 @@ export class AvaEngine { bctx.globalCompositeOperation = 'copy' bctx.drawImage(canvas, 0, 0) // 2. wipe — the transformed snapshot must REPLACE the old content, not - // double-expose over it + // double-expose over it. v7.15: clearRect (transparent) instead of a + // black fill — the framebuffer is alpha-capable now, and pixels with + // real transparency (behind / clear art) must keep it through the + // move. Over the black stage both read identically. ctx.globalCompositeOperation = 'source-over' - ctx.fillStyle = '#000' - ctx.fillRect(0, 0, w, h) + ctx.clearRect(0, 0, w, h) // 3. draw the snapshot back through this frame's transform. Screen y is // down; script y is up — bgy > 0 moves the picture UP. ctx.save() @@ -229,6 +251,134 @@ export class AvaEngine { ctx.restore() } + /** v7.15 — lazy scratch canvas for the gpu blend path (mirrors bgBuffer). */ + private scratchBuffer(w: number, h: number): boolean { + if (!this.blendBuffer || this.blendBuffer.width !== w || this.blendBuffer.height !== h) { + const buf = document.createElement('canvas') + buf.width = w + buf.height = h + this.blendBuffer = buf + this.blendBufCtx = buf.getContext('2d') + } + return this.blendBufCtx != null + } + + /** v7.15 — lazy WebGL compositor; latches gpuBroken when unavailable. */ + private gpuEnsure(w: number, h: number): boolean { + if (this.gpuBroken) return false + if (!this.compositor) this.compositor = new BlendCompositor() + if (this.compositor.failed || !this.compositor.ensure(w, h)) { + this.gpuBroken = true + return false + } + return true + } + + /** v7.15 — one place for the stroke/dot/polygon passes, target-agnostic: + * the native path draws onto the live canvas with the mode's composite + * op; the gpu path draws onto the scratch with source-over (the shader + * then blends the whole layer in one pass). */ + private drawContent( + ctx: CanvasRenderingContext2D, + n: number, + meta: { mode: RenderMode; linewidth: number }, + g: DrawGains, + ): void { + const canvas = this.canvas + if (!canvas) return + const w = canvas.width + const h = canvas.height + const pts = this.points + const scale = h / 480 // keeps geometry consistent across resolutions + + if (meta.mode === 'lines') { + ctx.lineCap = 'round' + ctx.lineJoin = 'round' + for (let pass = 0; pass < 2; pass++) { + const gain = pass === 0 ? g.halo : g.core + let pen = false + let pr = 0, pg = 0, pb = 0, pa = 0, pxp = 0, pyp = 0, plw = 0 + for (let k = 0; k < n; k++) { + const o = k * POINT_STRIDE + const skip = pts[o + 5] + const x = (pts[o] * 0.5 + 0.5) * w + const y = (0.5 - pts[o + 1] * 0.5) * h + const r = Math.max(0, Math.min(1, pts[o + 2])) + const gg = Math.max(0, Math.min(1, pts[o + 3])) + const b = Math.max(0, Math.min(1, pts[o + 4])) + const a = Math.max(0, Math.min(1, pts[o + 7])) + // per-point line width (AVS linesize) -- falls back to meta.linewidth + const lw = Math.max(0.3, pts[o + 6] > 0 ? pts[o + 6] : meta.linewidth) * (pass === 0 ? 3.2 : 1) * scale + if (skip) { + pen = false + pr = r; pg = gg; pb = b; pa = a; pxp = x; pyp = y; plw = lw + continue + } + if (pen) { + ctx.strokeStyle = `rgba(${(((pr + r) / 2) * 255) | 0},${(((pg + gg) / 2) * 255) | 0},${(((pb + b) / 2) * 255) | 0},${(((pa + a) / 2) * gain).toFixed(3)})` + ctx.lineWidth = (plw + lw) / 2 + ctx.beginPath() + ctx.moveTo(pxp, pyp) + ctx.lineTo(x, y) + ctx.stroke() + } + pr = r; pg = gg; pb = b; pa = a; pxp = x; pyp = y; plw = lw + pen = true + } + } + } else if (meta.mode === 'dots') { + for (let pass = 0; pass < 2; pass++) { + const sizeGain = pass === 0 ? 2.6 : 1 + const alphaGain = pass === 0 ? g.dotsGlow : g.dotsCore + for (let k = 0; k < n; k++) { + const o = k * POINT_STRIDE + if (pts[o + 5]) continue + const x = (pts[o] * 0.5 + 0.5) * w + const y = (0.5 - pts[o + 1] * 0.5) * h + const r = Math.max(0, Math.min(1, pts[o + 2])) + const gg = Math.max(0, Math.min(1, pts[o + 3])) + const b = Math.max(0, Math.min(1, pts[o + 4])) + const a = Math.max(0, Math.min(1, pts[o + 7])) + const rad = Math.max(0.6, pts[o + 6] * scale * sizeGain) + ctx.fillStyle = `rgba(${(r * 255) | 0},${(gg * 255) | 0},${(b * 255) | 0},${(a * alphaGain).toFixed(3)})` + ctx.beginPath() + ctx.arc(x, y, rad, 0, 6.28318) + ctx.fill() + } + } + } else { + // solid: filled polygon through all non-skipped points + let sr = 0, sg = 0, sb = 0, sa = 0, count = 0 + ctx.beginPath() + let pen = false + for (let k = 0; k < n; k++) { + const o = k * POINT_STRIDE + if (pts[o + 5]) { + pen = false + continue + } + const x = (pts[o] * 0.5 + 0.5) * w + const y = (0.5 - pts[o + 1] * 0.5) * h + if (!pen) { + ctx.moveTo(x, y) + pen = true + } else { + ctx.lineTo(x, y) + } + sr += pts[o + 2]; sg += pts[o + 3]; sb += pts[o + 4]; sa += pts[o + 7]; count++ + } + if (count > 2) { + ctx.closePath() + const r = Math.max(0, Math.min(1, sr / count)) + const gg = Math.max(0, Math.min(1, sg / count)) + const b = Math.max(0, Math.min(1, sb / count)) + const a = Math.max(0, Math.min(1, sa / count)) * g.solid + ctx.fillStyle = `rgba(${(r * 255) | 0},${(gg * 255) | 0},${(b * 255) | 0},${a.toFixed(3)})` + ctx.fill() + } + } + } + private resize(): void { if (!this.canvas) return const parent = this.canvas.parentElement @@ -238,12 +388,10 @@ export class AvaEngine { const w = Math.max(2, Math.round(cssW * dpr)) const h = Math.max(2, Math.round(cssH * dpr)) if (this.canvas.width !== w || this.canvas.height !== h) { + // assigning width/height also clears to transparent (v7.15: no + // opaque black fill -- behind/clear need the alpha channel) this.canvas.width = w this.canvas.height = h - if (this.ctx) { - this.ctx.fillStyle = '#000' - this.ctx.fillRect(0, 0, w, h) - } } } @@ -261,19 +409,25 @@ export class AvaEngine { const ctx = this.ctx // ---- persistence fade ------------------------------------------------- - // v7.14.1: persist may now reach 1.0 -- a true zero-fade framebuffer. - // At exactly 1 the fade fill is skipped entirely: old content leaves the - // screen only through a bg* transform carrying it off (or by being - // repainted, blend 'replace'). That is what makes "colors ride outward - // forever while the fresh drawing replaces the center" possible. + // v7.14.1: persist may reach 1.0 -- at exactly 1 the fade is skipped + // entirely: old content leaves the screen only through a bg* transform + // carrying it off (or by being repainted, blend 'replace'). That is + // what makes "colors ride outward forever while the fresh drawing + // replaces the center" possible. + // v7.15: the fade is an alpha ERASE (destination-out) instead of a + // black fill -- the framebuffer is alpha-capable, and scaling alpha by + // persist thins trails exactly like the old rgb scaling did over the + // black stage, while pixels that were painted behind / cleared keep + // fading honestly. const meta = this.script?.meta const persistBase = meta ? meta.persist : 0.85 const persist = Math.min(Math.max(this.env.persist ?? persistBase, 0), 1) - ctx.globalCompositeOperation = 'source-over' if (persist < 1) { + ctx.globalCompositeOperation = 'destination-out' ctx.fillStyle = `rgba(0,0,0,${(1 - persist).toFixed(4)})` ctx.fillRect(0, 0, w, h) } + ctx.globalCompositeOperation = 'source-over' // ---- audio + beat ----------------------------------------------------- const levels = this.audio.getBands(this.bandConfig, dt) @@ -314,6 +468,13 @@ export class AvaEngine { env.h = h env.aspect = w / Math.max(1, h) env.persist = persistBase // reset so the script can override each frame + // v7.15: same per-frame contract for the blend mode -- reset to the + // header mode's registry index so [frame]/[beat] can switch composites + // for THIS frame (the expression language is numeric-only, so the + // variable carries the mode's 1-based number; the Help table lists + // them). Read after the sections, before drawing; out-of-range values + // fall back to the header keyword. + env.blend = meta ? blendIndex(meta.blend) || 2 : (env.blend ?? 2) if (this.script) { try { @@ -377,103 +538,44 @@ export class AvaEngine { } // ---- draw --------------------------------------------------------------- - const scale = h / 480 // keeps geometry consistent across resolutions - const halfW = w / 2 - const halfH = h / 2 - if (n > 0 && meta) { - // v7.14.1: the blend header now selects any of the six composites; - // 'replace' additionally gets its core pass at full alpha below. - const replace = meta.blend === 'replace' - ctx.globalCompositeOperation = BLEND_COMPOSITE[meta.blend] - - if (meta.mode === 'lines') { - ctx.lineCap = 'round' - ctx.lineJoin = 'round' - for (let pass = 0; pass < 2; pass++) { - // replace: halo slightly stronger (it converges toward the source - // color, never past it), core at FULL alpha -- the stroke owns its - // pixels outright. Every other mode keeps the glow+core gains. - const gain = pass === 0 ? (replace ? 0.25 : 0.22) : replace ? 1 : 0.9 - let pen = false - let pr = 0, pg = 0, pb = 0, pa = 0, pxp = 0, pyp = 0, plw = 0 - for (let k = 0; k < n; k++) { - const o = k * POINT_STRIDE - const skip = pts[o + 5] - const x = (pts[o] * 0.5 + 0.5) * w - const y = (0.5 - pts[o + 1] * 0.5) * h - const r = Math.max(0, Math.min(1, pts[o + 2])) - const g = Math.max(0, Math.min(1, pts[o + 3])) - const b = Math.max(0, Math.min(1, pts[o + 4])) - const a = Math.max(0, Math.min(1, pts[o + 7])) - // per-point line width (AVS linesize) — falls back to meta.linewidth - const lw = Math.max(0.3, pts[o + 6] > 0 ? pts[o + 6] : meta.linewidth) * (pass === 0 ? 3.2 : 1) * scale - if (skip) { - pen = false - pr = r; pg = g; pb = b; pa = a; pxp = x; pyp = y; plw = lw - continue - } - if (pen) { - ctx.strokeStyle = `rgba(${(((pr + r) / 2) * 255) | 0},${(((pg + g) / 2) * 255) | 0},${(((pb + b) / 2) * 255) | 0},${(((pa + a) / 2) * gain).toFixed(3)})` - ctx.lineWidth = (plw + lw) / 2 - ctx.beginPath() - ctx.moveTo(pxp, pyp) - ctx.lineTo(x, y) - ctx.stroke() - } - pr = r; pg = g; pb = b; pa = a; pxp = x; pyp = y; plw = lw - pen = true + // v7.15 — the 41-mode registry (blend.ts). The blend variable (reset + // to the header mode's index every frame, so a script can switch per + // frame; the Help table lists each mode's number) picks the composite; + // an out-of-range value falls back to the header keyword. Native + // keywords composite straight onto the live canvas; gpu keywords draw + // the passes onto a scratch canvas and the WebGL compositor applies + // the formula (nearest native op when WebGL is unavailable). + // 'replace' keeps its v7.14.1 semantics: the core pass at FULL alpha, + // so the stroke owns its pixels outright. + const headerSpec = findBlend(meta.blend) + const spec = blendByIndex(env.blend ?? 0) ?? headerSpec ?? undefined + if (spec) { + const viaGpu = + spec.impl === 'gpu' && + !this.gpuBroken && + this.scratchBuffer(w, h) && + this.gpuEnsure(w, h) + if (viaGpu) { + const sctx = this.blendBufCtx! + sctx.globalCompositeOperation = 'source-over' + sctx.clearRect(0, 0, w, h) + this.drawContent(sctx, n, meta, GAINS_STD) + try { + this.compositor!.blend(this.canvas!, this.blendBuffer!, spec.gpuId ?? 0, env.frame ?? 0) + // replace the live canvas with the blended result wholesale + ctx.globalCompositeOperation = 'copy' + ctx.drawImage(this.compositor!.canvas, 0, 0) + ctx.globalCompositeOperation = 'source-over' + } catch { + this.gpuBroken = true // one bad frame never repeats; fallback next frame } - } - } else if (meta.mode === 'dots') { - for (let pass = 0; pass < 2; pass++) { - const sizeGain = pass === 0 ? 2.6 : 1 - const alphaGain = pass === 0 ? (replace ? 0.25 : 0.18) : replace ? 1 : 0.85 - for (let k = 0; k < n; k++) { - const o = k * POINT_STRIDE - if (pts[o + 5]) continue - const x = (pts[o] * 0.5 + 0.5) * w - const y = (0.5 - pts[o + 1] * 0.5) * h - const r = Math.max(0, Math.min(1, pts[o + 2])) - const g = Math.max(0, Math.min(1, pts[o + 3])) - const b = Math.max(0, Math.min(1, pts[o + 4])) - const a = Math.max(0, Math.min(1, pts[o + 7])) - const rad = Math.max(0.6, pts[o + 6] * scale * sizeGain) - ctx.fillStyle = `rgba(${(r * 255) | 0},${(g * 255) | 0},${(b * 255) | 0},${(a * alphaGain).toFixed(3)})` - ctx.beginPath() - ctx.arc(x, y, rad, 0, 6.28318) - ctx.fill() - } - } - } else { - // solid: filled polygon through all non-skipped points - let sr = 0, sg = 0, sb = 0, sa = 0, count = 0 - ctx.beginPath() - let pen = false - for (let k = 0; k < n; k++) { - const o = k * POINT_STRIDE - if (pts[o + 5]) { - pen = false - continue - } - const x = (pts[o] * 0.5 + 0.5) * w - const y = (0.5 - pts[o + 1] * 0.5) * h - if (!pen) { - ctx.moveTo(x, y) - pen = true - } else { - ctx.lineTo(x, y) - } - sr += pts[o + 2]; sg += pts[o + 3]; sb += pts[o + 4]; sa += pts[o + 7]; count++ - } - if (count > 2) { - ctx.closePath() - const r = Math.max(0, Math.min(1, sr / count)) - const g = Math.max(0, Math.min(1, sg / count)) - const b = Math.max(0, Math.min(1, sb / count)) - const a = Math.max(0, Math.min(1, sa / count)) * (replace ? 1 : 0.65) - ctx.fillStyle = `rgba(${(r * 255) | 0},${(g * 255) | 0},${(b * 255) | 0},${a.toFixed(3)})` - ctx.fill() + } else { + const op: GlobalCompositeOperation = + spec.impl === 'gpu' ? spec.fallbackOp : spec.op ?? 'source-over' + ctx.globalCompositeOperation = op + this.drawContent(ctx, n, meta, spec.fullAlphaCore ? GAINS_REPLACE : GAINS_STD) + ctx.globalCompositeOperation = 'source-over' } } } diff --git a/src/lib/ava/script.ts b/src/lib/ava/script.ts index a9d8676..0835272 100755 --- a/src/lib/ava/script.ts +++ b/src/lib/ava/script.ts @@ -6,7 +6,10 @@ // name: Gap The Mind <- header keys before the first [section] // author: synth-c (adapted) // mode: lines <- lines | dots | solid -// blend: additive <- additive | alpha | multiply | screen | subtract | replace +// blend: additive <- any of the 41 registry keywords (blend.ts); +// case/separator-insensitive, and switchable +// per frame through the blend variable +// (by its number in the Help table) // persist: 0.9 <- motion trail persistence 0..1 (1 = never fades) // linewidth: 2 // @@ -15,6 +18,7 @@ // [beat] runs on frames where a beat fired (after [frame]) // [point] runs once per point (n times per frame) +import { findBlend } from './blend' import { compileProgram, ExpressionError, type Env, type Program } from './expression' import type { BlendMode, RenderMode } from './types' @@ -58,11 +62,6 @@ export interface AvaScript { const SECTION_NAMES = new Set(['init', 'frame', 'beat', 'point']) const HEADER_KEYS = new Set(['name', 'author', 'description', 'mode', 'blend', 'persist', 'linewidth', 'ysign']) const MODES = new Set(['lines', 'dots', 'solid']) -// v7.14.1: the composite family. 'subtract' = canvas 'difference' -// (|dst - src|, the AVS subtract approximation); 'replace' = source-over -// with the core pass at full alpha (fresh strokes overwrite -- pairs with -// persist 1 for zero-fade feedback blow-outs). -const BLENDS = new Set(['additive', 'alpha', 'multiply', 'screen', 'subtract', 'replace']) const DEFAULT_META: ScriptMeta = { name: 'Untitled', @@ -161,12 +160,17 @@ function tryParse(text: string): { script: AvaScript | null; meta?: ScriptMeta; } meta.mode = value as RenderMode break - case 'blend': - if (!BLENDS.has(value)) { - return { script: null, meta: { ...meta }, error: { message: `blend must be one of: additive, alpha, multiply, screen, subtract, replace (got '${value}')`, section: 'header', line: lineNo } } + case 'blend': { + // v7.15: the 41-mode registry (blend.ts). Any spelling normalizes + // (Color Burn = color-burn = colorburn); the meta stores the + // CANONICAL key so the engine and every UI surface see one form. + const spec = findBlend(value) + if (!spec) { + return { script: null, meta: { ...meta }, error: { message: `unknown blend '${value}' -- the editor Help panel lists all 41 keywords (normal, additive, multiply, screen, subtract, replace, behind, clear, overlay, difference, hue, dissolve, phoenix, stencil, ...)`, section: 'header', line: lineNo } } } - meta.blend = value as BlendMode + meta.blend = spec.key break + } case 'persist': { const v = parseFloat(value) if (Number.isNaN(v)) { diff --git a/src/lib/ava/types.ts b/src/lib/ava/types.ts index 67dea78..cf42f95 100755 --- a/src/lib/ava/types.ts +++ b/src/lib/ava/types.ts @@ -1,12 +1,14 @@ // AVA — Advanced Visualization Agent · shared types export type RenderMode = 'lines' | 'dots' | 'solid' -/** v7.14.1 — the blend header grew from additive|alpha to the full composite - * family. 'subtract' is the AVS subtract approximation (canvas 'difference', - * |dst - src|); 'replace' draws source-over with the core pass at FULL alpha - * so fresh strokes overwrite the pixels under them (never accumulates to - * white, pairs with persist 1 for zero-fade feedback effects). */ -export type BlendMode = 'additive' | 'alpha' | 'multiply' | 'screen' | 'subtract' | 'replace' +/** v7.15 — blend is any keyword from the registry (src/lib/ava/blend.ts); + * the parser validates it via findBlend and canonicalizes to spec.key. + * All spellings are accepted (color burn = colorburn = ColorBurn). + * v7.15 notes: 'subtract' is now a TRUE clamped subtract (WebGL + * compositor) rather than 7.14.1's difference approximation; 'replace' + * keeps its v7.14.1 semantics (source-over with the core pass at FULL + * alpha); the blend variable can override the header per frame. */ +export type BlendMode = string export type AudioSourceKind = 'idle' | 'demo' | 'mic' | 'file' | 'link' /** Fine-tunable band detection configuration (Hz ranges + gains). */ diff --git a/src/lib/release-notes.ts b/src/lib/release-notes.ts index 3f8fc0a..d3f8c87 100755 --- a/src/lib/release-notes.ts +++ b/src/lib/release-notes.ts @@ -39,6 +39,28 @@ export interface ReleaseNote { } export const RELEASE_NOTES: ReleaseNote[] = [ + { + version: '7.15.0', + name: 'The complete blend mode collection', + changes: [ + { + kind: 'added', + text: 'blend: now takes 41 modes instead of six. The full Photoshop set is there (color burn, linear burn, darker color, color dodge, lighter color, overlay, soft light, hard light, vivid light, linear light, pin light, hard mix, difference, exclusion, divide, negation, phoenix, reflect, glow, hue, saturation, color, luminosity), plus GIMP\'s grain extract/merge, After Effects\' stencil and silhouette masks, a dissolve that re-rolls its speckle every frame, and plus-lighter / plus-darker. Any spelling works: color burn, color-burn and ColorBurn are the same keyword.', + }, + { + kind: 'added', + text: 'blend: subtract is now a true clamped subtract (base - blend, floored at black). Until 7.14.1 it was approximated with difference, which could never subtract downward past the stroke color.', + }, + { + kind: 'added', + text: 'The blend variable can switch modes per frame, like persist already could -- paint with replace (3), then sculpt with subtract (6) on the kick; every mode\'s number is in the Help panel\'s table. The framebuffer also keeps real transparency now, so behind (strokes slip under existing art) and clear (an eraser pen) work honestly.', + }, + { + kind: 'improved', + text: 'Every existing preset renders exactly as before -- the new transparency-aware fades and wipes read pixel-identically over the black stage. Modes without a Canvas2D operator run through a small WebGL pass; browsers without WebGL fall back to the nearest native operator.', + }, + ], + }, { version: '7.14.1', name: 'New blend modes + zero-fade trails', diff --git a/src/lib/version.ts b/src/lib/version.ts index a8cf2d7..b9f77f4 100755 --- a/src/lib/version.ts +++ b/src/lib/version.ts @@ -12,6 +12,33 @@ // warns in the console when the two drift apart. // // History: +// 7.15 — the complete blend mode collection (user request): the blend +// header grew from six keywords to a 41-mode registry +// (src/lib/ava/blend.ts) covering every compositing family in the +// request list -- the full Photoshop set, the GIMP grain pair, +// the After Effects stencil/silhouette masks, Apple/CSS plus- +// lighter/plus-darker and the Pegtop exotica (negation, phoenix, +// reflect, glow). Native keywords map straight to Canvas2D +// operators; the 21 modes Canvas2D lacks run through a new WebGL +// compositor (blend-gpu.ts) with per-pixel formulas from the W3C +// compositing spec, the glsl-blend collection and GIMP (phoenix = +// min - max + 1, verified against four independent sources; hard +// mix = vivid light thresholded at 0.5). 'subtract' is now a TRUE +// clamped subtract, replacing 7.14.1's difference approximation. +// The framebuffer went alpha-capable so behind and clear work +// honestly: the persistence fade is an alpha ERASE +// (destination-out) and the bg* wipe a clearRect -- over the +// black stage both read pixel-identically to the old opaque +// fills, so every existing preset renders as before. The blend +// variable can switch the mode per frame (same contract as +// persist; it carries the mode's 1-based registry number because +// the expression language is numeric-only -- the Help table lists +// every number). Names are case/separator-insensitive +// with aliases (color burn = colorburn = ColorBurn; plus-lighter +// = additive; plus-darker = linear burn). Help panel gained a +// grouped 41-row Blend modes table; parser errors point at it. +// WebGL-less browsers fall back to the nearest native operator +// per mode. // 7.14.1 — Script engine: blend modes + zero-fade persistence (user // request, Brainstorm preset session). The renderer's content // pass could only composite additively ('lighter') or plain @@ -473,4 +500,4 @@ export const APP_NAME = 'Open Visualization Engine' export const APP_SHORT = 'OVE' -export const APP_VERSION = '7.14.1' +export const APP_VERSION = '7.15.0' diff --git a/tool-results/grep_1793922566950_a0822d8d9a9c.txt b/tool-results/grep_1793922566950_a0822d8d9a9c.txt new file mode 100644 index 0000000..c966ae8 --- /dev/null +++ b/tool-results/grep_1793922566950_a0822d8d9a9c.txt @@ -0,0 +1,122 @@ +/home/z/my-project/src/lib/version.ts:15:// 7.14.1 — Script engine: blend modes + zero-fade persistence (user +/home/z/my-project/src/lib/version.ts:21:// by new color. Blend header extended to six values: multiply, +/home/z/my-project/src/lib/version.ts:31:// entirely (engine.ts). The pairing this was asked for: blend +/home/z/my-project/src/lib/version.ts:102:// persistence fade blends the moving trails: "speed accelerates +/home/z/my-project/src/lib/version.ts:119:// keeps the fade slow so colors blend. Help panel: bg* variable +/home/z/my-project/src/lib/version.ts:233:// blank-line+section skeletons, "linewidth: " / "blend: additive" +/home/z/my-project/src/lib/ava/types.ts:4:/** v7.14.1 — the blend header grew from additive|alpha to the full composite +/home/z/my-project/src/lib/ava/types.ts:9:export type BlendMode = 'additive' | 'alpha' | 'multiply' | 'screen' | 'subtract' | 'replace' +/home/z/my-project/src/lib/ava/blueprint.ts:95: 'Identical algorithm to the web edition, ported statement for statement into beat.rs. Detection: the smoothed bass must exceed threshold × the rolling 60-frame average, gated by a minimum interval and an absolute floor. Learning: consecutive beat intervals (200–2500 ms) build a median + spread estimate; when the spread is under 0.3 the period locks with an EMA (0.6/0.4 blend) and confidence rises. Prediction: a phase accumulator advances by dt/period every frame -- when the bass drops out for longer than period × 1.4, the predictor keeps firing beats on the learned grid (confidence-gated, slowly spending confidence at 0.02 per predicted beat and decaying at 0.06/s) so the visuals never lose the beat. Tap tempo: the Space bar taps into an 8-tap median, re-phasing the predictor and teaching the interval learner.', +/home/z/my-project/src/lib/ava/blueprint.ts:137: 'sections: [init] once, [frame] per frame, [beat] on beat frames, [point] n times per frame; headers name/author/description/mode/blend/persist/linewidth; errors report section + line', +/home/z/my-project/src/lib/ava/blueprint.ts:143: 'The Canvas2D renderer maps onto three wgpu pipelines sharing one uniform block (time, dt, bass/mid/treb + _att, vol + _att, beat flash, bpm, beatphase, aspect, resolution, persist): a fullscreen fade pass (persistence trails toward black, alpha = 1 − persist), an audio-reactive background pass (bass → warm amber center glow, treble → neon-green edge shimmer, beat → decaying flash), and the content pass -- a line-list or point-list point cloud with per-vertex color and additive blending, the equivalent of the web engine\'s \'lighter\' composite mode. Persistence v0 uses the fade pass; an offscreen feedback texture for true motion trails is the marked next step (TODO(avb) in render/mod.rs).', +/home/z/my-project/src/lib/ava/blueprint.ts:207: 'multi-scope composition -- AVS-style effect lists with per-effect blend/persist (the [point] scope becomes one effect type among several)', +/home/z/my-project/src/lib/ava/share-codec.ts:130: { key: 'blend: additive', symbol: '⼆' }, +/home/z/my-project/src/lib/ava/share-codec.ts:137: { key: 'blend', symbol: '♘' }, +/home/z/my-project/src/lib/ava/share-codec.ts:984: { key: 'blend', symbol: '♘' }, +/home/z/my-project/src/lib/ava/presets.ts:22:blend: additive +/home/z/my-project/src/lib/ava/presets.ts:63:blend: additive +/home/z/my-project/src/lib/ava/presets.ts:106:blend: additive +/home/z/my-project/src/lib/ava/presets.ts:153:blend: additive +/home/z/my-project/src/lib/ava/presets.ts:195:blend: additive +/home/z/my-project/src/lib/ava/presets.ts:237:blend: additive +/home/z/my-project/src/lib/ava/engine.ts:6:// Drawing supports three modes (lines | dots | solid), six blend composites +/home/z/my-project/src/lib/ava/engine.ts:15:import type { BandConfig, BandLevels, BeatConfig, BeatFrame, BlendMode } from './types' +/home/z/my-project/src/lib/ava/engine.ts:30:/** v7.14.1 -- blend header -> Canvas2D composite operation for the content +/home/z/my-project/src/lib/ava/engine.ts:38:const BLEND_COMPOSITE: Record = { +/home/z/my-project/src/lib/ava/engine.ts:194: * persistence fade (persist header / env.persist) blends the trails — +/home/z/my-project/src/lib/ava/engine.ts:267: // repainted, blend 'replace'). That is what makes "colors ride outward +/home/z/my-project/src/lib/ava/engine.ts:385: // v7.14.1: the blend header now selects any of the six composites; +/home/z/my-project/src/lib/ava/engine.ts:387: const replace = meta.blend === 'replace' +/home/z/my-project/src/lib/ava/engine.ts:388: ctx.globalCompositeOperation = BLEND_COMPOSITE[meta.blend] +/home/z/my-project/src/lib/ava/script.ts:9:// blend: additive <- additive | alpha | multiply | screen | subtract | replace +/home/z/my-project/src/lib/ava/script.ts:19:import type { BlendMode, RenderMode } from './types' +/home/z/my-project/src/lib/ava/script.ts:26: blend: BlendMode +/home/z/my-project/src/lib/ava/script.ts:59:const HEADER_KEYS = new Set(['name', 'author', 'description', 'mode', 'blend', 'persist', 'linewidth', 'ysign']) +/home/z/my-project/src/lib/ava/script.ts:65:const BLENDS = new Set(['additive', 'alpha', 'multiply', 'screen', 'subtract', 'replace']) +/home/z/my-project/src/lib/ava/script.ts:72: blend: 'additive', +/home/z/my-project/src/lib/ava/script.ts:145: return { script: null, meta: { ...meta }, error: { message: `Unknown header key '${key}' -- valid keys: name, author, description, mode, blend, persist, linewidth`, section: 'header', line: lineNo } } +/home/z/my-project/src/lib/ava/script.ts:164: case 'blend': +/home/z/my-project/src/lib/ava/script.ts:165: if (!BLENDS.has(value)) { +/home/z/my-project/src/lib/ava/script.ts:166: return { script: null, meta: { ...meta }, error: { message: `blend must be one of: additive, alpha, multiply, screen, subtract, replace (got '${value}')`, section: 'header', line: lineNo } } +/home/z/my-project/src/lib/ava/script.ts:168: meta.blend = value as BlendMode +/home/z/my-project/src/lib/release-notes.ts:44: name: 'New blend modes + zero-fade trails', +/home/z/my-project/src/lib/release-notes.ts:48: text: 'Scripts can now choose how fresh strokes mix with what is already on screen: blend: multiply, screen, subtract and replace join the old additive and alpha. replace is the interesting one -- new lines overwrite the color underneath instead of stacking on it, so a figure redrawn over its own trails keeps its color instead of blooming to white.', +/home/z/my-project/src/lib/release-notes.ts:96: text: 'Scripts can move the whole picture now: bgrot spins the background clockwise or counter-clockwise, bgx / bgy slide it up, down, left or right, and bgzoom draws it in or blows it out -- the movement family the classic Winamp AVS plugins were built on. The speed can ride the music: accelerate on every beat, flip the spin direction on a hard hit, and let a slow fade to black blend the colors. All four variables are documented in the script editor\'s help panel.', +/home/z/my-project/src/lib/release-notes.ts:100: text: 'I added an eleventh Zai-Magic preset: "osc-rotations" -- a stationary centered oscilloscope whose left and right points color-shift together while the center points hold their own hue, over a background that rotates clockwise and counter-clockwise to the music and temporarily accelerates with the beat. Hard hits flip the spin; the fade stays slow so the colors blend.', +/home/z/my-project/src/lib/ava/embedded-presets.ts:47: content: "# Auto-ported from \"D&L - Life Is Violated.avs\" (Winamp AVS / D&L)\n# SuperScope point program, 4 AVSTrans macros expanded.\nname: \"Life Is Violated\"\nauthor: \"D&L\"\nmode: lines\nblend: additive\npersist: 0.88\nlinewidth: 2\nysign: -1\n\n[init]\nn=800;xa=-0.5;ya=0.0;xb=-0.0;yb=0.75;c=200;f=0;\r\nnxa=(rnd(100)-50)*.02;nya=(rnd(100)-50)*.02;\r\nnxb=(rnd(100)-50)*.02;nyb=(rnd(100)-50)*.02;\n\n[frame]\nf=f+1;\r\nt=1-((cos((f*3.1415)/c)+1)*.5);\r\nxa=((nxa-lxa)*t)+lxa;\r\nya=((nya-lya)*t)+lya;\r\nxb=((nxb-lxb)*t)+lxb;\r\nyb=((nyb-lyb)*t)+lyb;\r\nex=(xb-xa);\r\ney=(yb-ya);\r\nd=sqrt(sqr(ex)+sqr(ey));\r\nr=atan(ey/ex)+(3.1415/2);\r\ndv=d*2\n\n[beat]\nc=f;\r\nf=0;\r\nlxa=nxa;\r\nlya=nya;\r\nlxb=nxb;\r\nlyb=nyb;\r\nnxa=(rnd(100)-50)*.02;\r\nnya=(rnd(100)-50)*.02;\r\nnxb=(rnd(100)-50)*.02;\r\nnyb=(rnd(100)-50)*.02\n\n[point]\n//primary render\r\nx=(ex*i)+xa;\r\ny=(ey*i)+ya;\r\n\r\n//volume offset\r\nx=x+ ( cos(r) * v * dv);\r\ny=y+ ( sin(r) * v * dv);\r\n\r\n//color values\r\nred=i;\r\ngreen=(1-i);\r\nblue=abs(v*6);\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:56: content: "name: \"Retrowall (Yathosho's Supermicrocosm)\"\nmode: dots\nblend: additive\npersist: 0.843\nlinewidth: 2.178\n\n[init]\nrings = 7\nn = rings * 103\n\n[frame]\nt = t + dt * (0.344 + bass_att * 0.6)\nhue = hue + dt * 0.112\nsquash = 0.315 + 0.25 * sin(t * 0.205)\n\n[point]\nring = floor(i * rings)\nri3 = frac(i * rings)\nr0 = 0.16 + ring * 0.142\na = ri3 * 6.28318 + t * (1.2 - ring * 0.18) + ring * 2.4\nx = sin(a) * r0 * (1 + bass * 0.18) / aspect\ny = cos(a) * r0 * squash\nsat = frac(ri3 * 5)\nsize = if(below(sat, 0.14), 3 + bass * 3, 1)\nred = 0.25 + bass * 0.5 + ring * 0.07 * (0.45 + 0.55 * sin(hue * 6.28318 + ring * 1.3))\ngreen = 0.25 + bass * 0.5 + ring * 0.07 * (0.45 + 0.55 * sin(hue * 6.28318 + ring * 1.3 + 2.09))\nblue = 0.25 + bass * 0.5 + ring * 0.07 * (0.45 + 0.55 * sin(hue * 6.28318 + ring * 1.3 + 4.19))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:65: content: "name: \"Adrealine rush\"\nmode: dots\nblend: additive\npersist: 0.826\nlinewidth: 1.803\n\n[init]\nn = 1287\n\n[frame]\nt = t + dt * 0.304\nhue = hue + dt * 0.11\n\n[point]\nu = rand(i * 1.7) * 2 - 1\nw = rand(i * 3.3 + 11) * 2 - 1\nm = sin((u * 2.681 + w * 5.047 + t) * 3.14159) * sin((u * 6.682 - w * 2.465 - t * 0.7) * 3.14159)\nx = u * 0.907 / aspect\ny = w * 0.875\nlum = max(0, m) * (0.3 + bass * 0.9) + 0.06\nred = lum * 0.3\ngreen = lum * 0.65\nblue = min(1, lum * 1.3)\nsize = 1 + abs(m) * 3.025\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:74: content: "name: \"Alien Heart\"\nmode: lines\nblend: additive\npersist: 0.897\nlinewidth: 1.95\n\n[init]\nn = 1015\n\n[frame]\nt = t + dt * (0.377 + bass_att * 1.5)\nhue = hue + dt * 0.038\n\n[point]\nring = floor(i * 29)\nri2 = frac(i * 29)\nz = frac(ring / 29 + t)\nrad = 0.05 + z * 0.917\na = ri2 * 6.28318 + ring * 0.423 + sin(t * 0.7) * 2\nx = sin(a) * rad * (0.55 + sv * 0.656) / aspect\ny = cos(a) * rad * (0.55 + sv * 0.656)\nred = (1 - z) * (0.3 + bass * 0.7) * abs(sin(z * 4.256))\ngreen = (1 - z) * (0.3 + bass * 0.7) * 0.22\nblue = (1 - z) * (0.3 + bass * 0.7) * abs(cos(z * 4.256))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:83: content: "name: \"Brainstorm\"\nmode: lines\nblend: additive\npersist: 0.859\nlinewidth: 2.309\n\n[init]\nsegs = 6\nn = 584\n\n[frame]\nrot = rot + dt * (0.093 + mid_att * 0.5)\nhue = hue + dt * 0.084\nflash = flash * 0.85\n\n[beat]\nflash = 1\n\n[point]\nseg = floor(i * segs)\nsi = frac(i * segs)\na0 = si * 6.28318 / segs + rot\namp = 0.1 + sv * 0.55 + bass * 0.25 + flash * 0.06\nrad = 0.15 + amp * (0.4 + 0.6 * sin(a0 * 9 + time * 2))\na = seg * 6.28318 / segs + a0 * if(below(seg % 2, 1), 1, -1)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + amp * 1.3 * 0.85\ngreen = 0.3 + amp * 1.3 * 0.92\nblue = 0.3 + amp * 1.3\nskip = if(above(si, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:92: content: "name: \"Molecules (S_KuPeRS Remix)\"\nmode: lines\nblend: additive\npersist: 0.88\nlinewidth: 1.388\n\n[init]\nn = 1119\n\n[frame]\nt = t + dt * (0.211 + bass_att * 1.8)\nhue = hue + dt * 0.042 + beat * 0.012\n\n[point]\narm = floor(i * 3)\nfa = frac(i * 3)\nd = fa\nang = arm * 1.551 + d * 1.047 * 3.14159 + t\nrad = (0.04 + pow(d, 1.714) * 1.15) * (0.7 + bass * 0.5)\nx = sin(ang) * rad / aspect\ny = cos(ang) * rad\nred = (0.3 + 0.7 * d) * (0.3 + mid) * abs(sin(d * 2.325))\ngreen = (0.3 + 0.7 * d) * (0.3 + mid) * 0.22\nblue = (0.3 + 0.7 * d) * (0.3 + mid) * abs(cos(d * 2.325))\nskip = if(below(fa, 0.04), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:101: content: "name: \"Take the Veil\"\nmode: lines\nblend: additive\npersist: 0.895\nlinewidth: 1.78\n\n[init]\nn = 674\n\n[frame]\nt = t + dt * 0.275\nhue = hue + dt * 0.052\n\n[point]\nph = i * 6.28318 * 1.521\nfa = 3 + mid * 0.35\nfb = 6 + bass * 0.45\nx = sin(ph * fa + t) * (0.5 + bass * 0.3) / aspect\ny = sin(ph * fb + t * 1.3 + 0.957) * (0.5 + treb * 0.35)\nred = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * (0.25 + bass * 0.95)\ngreen = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * (0.25 + mid * 0.95)\nblue = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * (0.25 + treb * 0.95)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:110: content: "# Auto-ported from \"Nic01 - Rototronik.avs\" (Winamp AVS / Nic01)\n# SuperScope point program, 4 AVSTrans macros expanded.\nname: \"Rototronik\"\nauthor: \"Nic01\"\nmode: lines\nblend: additive\npersist: 0.88\nlinewidth: 2\nysign: -1\n\n[init]\npi=acos(-1);n=1000;\n\n[frame]\nrx=rx+rdx;ry=ry+rdy;rz=rz+rdz;xs=sin(rx);ys=sin(ry);zs=sin(rz);xc=cos(rx);yc=cos(ry);zc=cos(rz);t=t+0.1;p=0;p1=0.;\n\n[beat]\nrdx=(getosc(0,0,0)*500-250)%250/2500;rdy=(getosc(0.05,0,0)*500-250)%250/2500;rdz=(getosc(0.1,0,0)*500-250)%250/2500;\n\n[point]\np=p+1;\r\np1=if(equal(p%20,1),p1+1,p1);\r\ns=(1-equal(p%20,1));\r\ns1=1-s1;\r\nx1=sin(i*pi*4)*s*s1;\r\ny1=cos(i*pi*4)*s*s1;\r\nx1=x1+getosc((p1%25)*0.04,0,0)*x1;\r\ny1=y1+getosc((p1%25)*0.04,0,0)*y1;\r\nz1=-below(p,500)*0.5+0.25;\r\nc=(2-x1*x1-y1*y1);\r\n;\r\ny2=y1*xc-z1*xs;z2=y1*xs+z1*xc;\r\nx2=z2*ys+x1*yc;z1=z2*yc-x1*ys;\r\nx1=x2*zc-y2*zs;y1=y2*zc+x2*zs;\r\nx=x1/(2+z1);y=y1/(2+z1);\r\nred=c;\r\ngreen=1-c;\r\nc=equal(p,500)*10;\r\nred=red-c;green=green-c;\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:119: content: "name: \"...hidden track...\"\nmode: lines\nblend: additive\npersist: 0.805\nlinewidth: 2.555\n\n[init]\nn = 205\n\n[frame]\nhue = hue + dt * 0.045 + beat * 0.01\ntravel = travel + dt * (0.253 + bass_att * 1.4)\nflash = flash * 0.86\n\n[beat]\nflash = 1\n\n[point]\ng = floor(i * 5)\ngi = frac(i * 5)\nph = frac(rand(g * 5.1 + 1) + travel * (0.55 + rand(g + 17) * 0.85))\na = gi * 6.28318\nrad = ph * (0.232 + bass * 0.659 + flash * 0.08)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nfade = sin(ph * 3.14159)\nred = min(1, fade * (0.35 + flash * 0.4) * 1.3)\ngreen = fade * (0.35 + flash * 0.4) * 0.5\nblue = fade * (0.35 + flash * 0.4) * 0.12\nskip = if(above(ph, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:128: content: "# Arctic Rainbow -- re-imagined (v7.14) as a music-driven water spray.\n# Droplets launch from below the bottom edge, rise slowly, hang at the top,\n# arch left or right and fall back down, like water sprayed skyward. The\n# NUMBER of airborne drops follows the music's intensity: silence runs dry,\n# loud passages spray hard. Every droplet owns a hue that shifts on each\n# bass hit, and only falling drops grow a tapered RGB tail -- rising drops\n# stay crisp dots.\n#\n# Slot layout (mode lines): each drop owns S consecutive points --\n# slot 0 separator (always skipped; breaks the pen between drops)\n# slot 1 the head (a crisp dot while rising)\n# slots 2..S-1 trail samples reaching 0.014s..0.44s back along the arc\n# Trail samples draw only once the drop is falling (vy < 0), so the tail\n# fades in exactly as the arch turns downward.\nname: \"Arctic Rainbow\"\nmode: lines\nblend: additive\npersist: 0.12\nlinewidth: 2\n\n[init]\ndrops = 120\ntailn = 12\nS = tailn + 2\nn = drops * S\ndtT = 0.042\nacts = 0\n\n[frame]\n# music intensity -> how many drops are airborne (fast attack, slow release)\nvolish = min(1, max(vol_att, bass_att * 0.9) * 1.25)\nwant = clamp((volish - 0.06) / 0.5, 0, 1)\nrate = if(above(want, acts), 6, 1.2)\nacts = acts + (want - acts) * (1 - exp(-dt * rate))\nactn = floor(acts * drops + 0.001)\n# brightness rides the volume; every bass hit flashes the spray brighter\nflash = exp(-beatage * 7)\nbright = 0.62 + 0.38 * min(1, vol_att * 1.6) + flash * 0.3\n\n[point]\n# slot map through cell centers (dust-proof floor; v7.13.1 lesson)\nq = i * (n - 1) + 0.5\nd = floor(q / S)\nslot = floor(q - d * S)\n\n# stable per-drop character: apex height, flight time, hue, per-beat shift\nhbase = 1.26 + rand(d * 7.13 + 3) * 0.62\ntf = 1.9 + rand(d * 5.31 + 11) * 1.5\nhue0 = rand(d * 3.7 + 23)\nhsh = 0.09 + rand(d * 9.17 + 31) * 0.17\n\n# flight clock: period P per drop, phase-staggered; every new splash\n# re-rolls its origin, drift and arch from the cycle index\nP = tf * 1.18\nct = time + rand(d * 1.7 + 43) * P\ncyc = floor(ct / P)\na = ct - cyc * P\nxr = d * 12.77 + cyc * 17.31\nx0 = rand(xr + 1) * 2 - 1\ndrift = (rand(xr + 2) * 2 - 1) * 0.16\narch = (rand(xr + 3) * 2 - 1) * 0.55\n\n# projectile parabola: y(u) = -1.06 + 4*h*u*(1-u), apex h above the launch\nvy0 = 4 * hbase / tf\ngrav = 8 * hbase / (tf * tf)\n\n# this slot's sample age: the head is \"now\", trail slots reach back in time\nlag = if(above(slot, 1.5), 0.014 + (slot - 2) * dtT, 0)\naj = a - lag\nuj = aj / tf\nyj = -1.06 + 4 * hbase * uj * (1 - uj)\nxj = x0 + drift * uj + arch * uj * uj\n\n# music gate + dead window + off-screen cull\nskip = if(above(slot, 0.5), if(above(d, actn - 0.5), 1, 0), 1)\nskip = if(above(a, tf * 1.15), 1, skip)\nskip = if(below(aj, 0), 1, skip)\nskip = if(above(abs(xj), 1.05), 1, skip)\n\n# tail gate: 0 the whole way up, fading in as the fall accelerates\nvy = vy0 - grav * a\ntgate = smoothstep(0, 0.35, -vy / vy0)\n\n# per-drop hue, shifted by every bass hit; older trail samples drift back\nhue = hue0 + beats * hsh + time * 0.012 - (slot - 1) * 0.008\nred = hsvr(hue, 1, bright)\ngreen = hsvg(hue, 1, bright)\nblue = hsvb(hue, 1, bright)\n\ndsz = 1.6 + rand(d * 2.9 + 51) * 1.1 + bass_att * 1.4\nu = (slot - 2) / tailn\nif(above(slot, 1.5),\n if(above(slot, 2.5),\n (alpha = tgate * pow(1 - u, 1.5) * 0.85;\n size = dsz * (1 - 0.72 * u);\n skip = if(below(tgate, 0.03), 1, skip)),\n (alpha = max(1 - tgate, tgate * 0.85); size = dsz)),\n (alpha = 1; size = dsz))\nx = xj\ny = yj\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:137: content: "name: \"Chinook\"\nmode: dots\nblend: additive\npersist: 0.831\nlinewidth: 2.299\n\n[init]\nbars = 30\nn = bars * 9\n\n[frame]\nrot = rot + dt * (0.07 + mid * 0.3)\nhue = hue + dt * 0.106\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.893\na = bar * 6.28318 / bars + rot\nrad = 0.142 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.25 + bi * 0.75 * 0.3\ngreen = 0.25 + bi * 0.75 * 0.65\nblue = min(1, 0.25 + bi * 0.75 * 1.3)\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:146: content: "name: \"Hexual Healing\"\nmode: dots\nblend: additive\npersist: 0.785\nlinewidth: 2.432\n\n[init]\ncols = 34\nn = cols * cols\n\n[frame]\nrot = rot + dt * (0.072 + mid * 0.4)\nhue = hue + dt * 0.062\n\n[point]\ncx = floor(i * cols) / (cols - 1)\ncy = frac(i * cols)\nh = sv * 0.506\nux = (cx - 0.5) * 1.674\nuy = (cy - 0.5) * 1.674\nrx = ux * cos(rot) - uy * sin(rot)\nry = ux * sin(rot) + uy * cos(rot)\nx = (rx / aspect) * (1 - h * 0.7)\ny = ry * (1 - h * 0.7)\nred = min(1, 0.22 + h * 2.2 * 1.3)\ngreen = 0.22 + h * 2.2 * 0.5\nblue = 0.22 + h * 2.2 * 0.12\nsize = 1.2 + h * 5\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:155: content: "name: \"Inverse Kinetics\"\nmode: dots\nblend: additive\npersist: 0.805\nlinewidth: 2.613\n\n[init]\nn = 817\n\n[frame]\ntt = tt + dt * (0.5 + bass_att * 1.1)\nhue = hue + dt * 0.103\nburst = burst * 0.9\n\n[beat]\nburst = 1\n\n[point]\njet = floor(i * 2)\nlife = frac(rand(i * 7.7 + jet) + tt * (0.35 + rand(i + 3) * 0.65))\na = jet * 6.28318 / 2 + rand(i * 5.1 + jet) * 0.736\nspd = 0.4 + rand(i * 9.2 + jet) * 0.8\npx = cos(a) * spd * life\npy = sin(a) * spd * life - 1.2 * life * life\nx = px * (0.85 + bass * 0.35) / aspect\ny = py\nred = max(0, 1 - life) * (0.35 + burst * 0.55) * abs(sin(life * 4))\ngreen = max(0, 1 - life) * (0.35 + burst * 0.55) * 0.22\nblue = max(0, 1 - life) * (0.35 + burst * 0.55) * abs(cos(life * 4))\nskip = if(above(life, 0.94), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:164: content: "name: \"Kingish\"\nmode: dots\nblend: additive\npersist: 0.813\nlinewidth: 2.025\n\n[init]\nspokes = 27\nn = spokes * 22\n\n[frame]\nrot = rot + dt * (0.102 + mid * 0.4)\nt = t + dt * 2.987\nhue = hue + dt * 0.075\n\n[point]\nsp = floor(i * spokes)\nsi = frac(i * spokes)\na = sp * 6.28318 / spokes + rot\nwave = sin(si * 2 * 3.14159 - t) * (0.03 + bass * 0.28)\nrad = 0.12 + si * 0.92 + wave\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = (1 - si) * 0.45 + 0.15 + sv * 0.55 * abs(sin(sp * 0.4))\ngreen = (1 - si) * 0.45 + 0.15 + sv * 0.55 * 0.22\nblue = (1 - si) * 0.45 + 0.15 + sv * 0.55 * abs(cos(sp * 0.4))\nskip = if(above(si, 0.985), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:173: content: "name: \"Spirit Realm (Degnic's Plasmoid RMX)\"\nmode: lines\nblend: additive\npersist: 0.885\nlinewidth: 2.389\n\n[init]\nn = 1199\n\n[frame]\nt = t + dt * (0.344 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.085\n\n[point]\na = i * 6.28318 * 2\nwob = sin(a * 3 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.422 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5))\ngreen = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5 + 2.09))\nblue = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5 + 4.19))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:182: content: "# Auto-ported from \"S_KuPeRS - Texering 002.avs\" (Winamp AVS / S_KuPeRS)\n# SuperScope point program, 4 AVSTrans macros expanded.\nname: \"Texering 002\"\nauthor: \"S_KuPeRS\"\nmode: dots\nblend: additive\npersist: 0.78\nlinewidth: 3\nysign: -1\n\n[init]\nn=100;pi=acos(-1);rx=1.57;ry=1.57;rx=0;ry=0;rz=0;rxo=0;ryo=0;rzo=0;rxt=0;ryt=0;rzt=0;\n\n[frame]\nredf=redf+redr;greenf=greenf+greenr;bluef=bluef+bluer;rx=rx+rxo;ry=ry+ryo;rz=rz+rzo;rzo=rzo*0.97;cx=cos(sin(rx));sx=sin(sin(rx));cy=cos(sin(ry));sy=sin(sin(ry));cz=cos(rz);sz=sin(rz);\n\n[beat]\nredr=rnd(10)/100-0.05;greenr=rnd(10)/100-0.05;bluer=rnd(10)/100-0.05;rxo=getosc(0.5,0.02,0)/12;ryo=getosc(0.3,0.02,0)/12;rzo=getosc(0.7,0.02,0)/8;\n\n[point]\nr=i*pi*2;r2=i*pi*99;\r\nx1=sin(r-bluef*1.53+.0776)*cos(r2+greenf);\r\ny1=cos(r+bluef);\r\nz1=sin(r2+redf);\r\n\r\nx1d=x1*cz-y1*sz;\r\ny1d=x1*sz+y1*cz;\r\ny2d=y1d*cx-z1*sx;\r\nz2d=y1d*sx+z1*cx;\r\nx3d=x1d*cy-z2d*sy;\r\nz3d=x1d*sy+z2d*cy;\r\nzi=1/(z3d+3);\r\nx=if(above(z3d+3,0.1),x3d*zi,x);\r\ny=if(above(z3d+3,0.1),y2d*zi,y);\r\n\r\nalpha=if(below(z3d+2.4,0),0,1);\r\nred=alpha*(1+sin(redf)/4-z3d/4)/7;\r\nblue=alpha*(1+sin(bluef)/4-z3d)/20;\r\ngreen=alpha*(1+sin(greenf)/3-z3d/2)/12;\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:191: content: "name: \"Upward Current\"\nmode: lines\nblend: additive\npersist: 0.914\nlinewidth: 1.629\n\n[init]\nn = 869\n\n[frame]\nt = t + dt * (0.134 + mid * 0.5)\nhue = hue + dt * 0.122\nflash = flash * 0.87\n\n[beat]\nflash = 1\n\n[point]\nth = i * 6.28318 * 2 + t\nr = abs(cos(2 * th + bass * 0.656))\nrad = r * (0.5 + bass * 0.3 + sv * 0.2 + flash * 0.08)\nx = sin(th) * rad / aspect\ny = cos(th) * rad\nred = 0.25 + 0.65 * r + v * 0.25 * abs(sin(th * 0.5))\ngreen = 0.25 + 0.65 * r + v * 0.25 * 0.22\nblue = 0.25 + 0.65 * r + v * 0.25 * abs(cos(th * 0.5))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:200: content: "name: \"Aqua-fumes\"\nmode: dots\nblend: additive\npersist: 0.787\nlinewidth: 2.043\n\n[init]\nn = 966\n\n[frame]\ntravel = travel + dt * (0.347 + vol_att * 1.816)\nhue = hue + dt * 0.076\n\n[point]\na = rand(i * 7.3) * 6.28318\nz = frac(rand(i * 3.1 + 5) + travel * (0.5 + rand(i + 9) * 0.7))\nrad = z * z * 1.075\nx = sin(a) * rad / aspect\ny = cos(a) * rad\ntw = 0.4 + 0.6 * sin(z * 40 + time * 3) * (0.5 + treb)\nred = tw * abs(sin(i * 3.959))\ngreen = tw * 0.22\nblue = tw * abs(cos(i * 3.959))\nsize = 1 + z * 3 * (0.5 + bass)\nskip = if(above(z, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:209: content: "name: \"Club Seizure (color enhanced mix)\"\nmode: lines\nblend: additive\npersist: 0.864\nlinewidth: 2.379\n\n[init]\nn = 946\n\n[frame]\nt = t + dt * (0.322 + bass_att * 0.9)\nhue = hue + dt * 0.089\nflash = flash * 0.86\n\n[beat]\nflash = 1\n\n[point]\nst = floor(i * 2)\nsi = frac(i * 2)\ns = si * 6 * 6.28318 + t\nph = st * 3.14159\nrad = (0.28 + bass * 0.32 + flash * 0.06) * (0.55 + 0.45 * (cos(s + ph) * 0.5 + 0.5))\nx = sin(s + ph) * rad / aspect\ny = (si - 0.5) * 1.8\nred = 0.25 + 0.55 * (cos(s + ph) * 0.5 + 0.5) + treb * 0.25 * (0.45 + 0.55 * sin(hue * 6.28318 + s * 0.3))\ngreen = 0.25 + 0.55 * (cos(s + ph) * 0.5 + 0.5) + treb * 0.25 * (0.45 + 0.55 * sin(hue * 6.28318 + s * 0.3 + 2.09))\nblue = 0.25 + 0.55 * (cos(s + ph) * 0.5 + 0.5) + treb * 0.25 * (0.45 + 0.55 * sin(hue * 6.28318 + s * 0.3 + 4.19))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:218: content: "name: \"Electro blobs\"\nmode: lines\nblend: additive\npersist: 0.866\nlinewidth: 1.536\n\n[init]\nsegs = 12\nn = 616\n\n[frame]\nrot = rot + dt * (0.085 + mid_att * 0.5)\nhue = hue + dt * 0.131\nflash = flash * 0.85\n\n[beat]\nflash = 1\n\n[point]\nseg = floor(i * segs)\nsi = frac(i * segs)\na0 = si * 6.28318 / segs + rot\namp = 0.1 + sv * 0.55 + bass * 0.25 + flash * 0.06\nrad = 0.15 + amp * (0.4 + 0.6 * sin(a0 * 5 + time * 2))\na = seg * 6.28318 / segs + a0 * if(below(seg % 2, 1), 1, -1)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + amp * 1.3 * 0.85\ngreen = 0.3 + amp * 1.3 * 0.92\nblue = 0.3 + amp * 1.3\nskip = if(above(si, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:227: content: "name: \"Kaleidofied\"\nmode: lines\nblend: additive\npersist: 0.885\nlinewidth: 1.542\n\n[init]\nn = 1126\n\n[frame]\nt = t + dt * (0.589 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.1\n\n[point]\na = i * 6.28318 * 1\nwob = sin(a * 3 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.232 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5))\ngreen = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5 + 2.09))\nblue = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5 + 4.19))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:236: content: "name: \"Magma Flow II\"\nmode: dots\nblend: additive\npersist: 0.804\nlinewidth: 2.633\n\n[init]\nrings = 3\nn = rings * 104\n\n[frame]\nt = t + dt * (0.258 + bass_att * 0.6)\nhue = hue + dt * 0.036\nsquash = 0.387 + 0.25 * sin(t * 0.203)\n\n[point]\nring = floor(i * rings)\nri3 = frac(i * rings)\nr0 = 0.16 + ring * 0.148\na = ri3 * 6.28318 + t * (1.2 - ring * 0.18) + ring * 2.4\nx = sin(a) * r0 * (1 + bass * 0.18) / aspect\ny = cos(a) * r0 * squash\nsat = frac(ri3 * 5)\nsize = if(below(sat, 0.14), 3 + bass * 3, 1)\nred = 0.25 + bass * 0.5 + ring * 0.07 * abs(sin(ring * 1.3))\ngreen = 0.25 + bass * 0.5 + ring * 0.07 * 0.22\nblue = 0.25 + bass * 0.5 + ring * 0.07 * abs(cos(ring * 1.3))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:245: content: "name: \"Multiple Orgasms\"\nmode: lines\nblend: additive\npersist: 0.873\nlinewidth: 1.6\n\n[init]\nspokes = 30\nn = spokes * 33\n\n[frame]\nrot = rot + dt * (0.106 + mid * 0.4)\nt = t + dt * 2.164\nhue = hue + dt * 0.106\n\n[point]\nsp = floor(i * spokes)\nsi = frac(i * spokes)\na = sp * 6.28318 / spokes + rot\nwave = sin(si * 4 * 3.14159 - t) * (0.03 + bass * 0.28)\nrad = 0.12 + si * 0.919 + wave\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = (1 - si) * 0.45 + 0.15 + sv * 0.55 * (0.45 + 0.55 * sin(hue * 6.28318 + sp * 0.4))\ngreen = (1 - si) * 0.45 + 0.15 + sv * 0.55 * (0.45 + 0.55 * sin(hue * 6.28318 + sp * 0.4 + 2.09))\nblue = (1 - si) * 0.45 + 0.15 + sv * 0.55 * (0.45 + 0.55 * sin(hue * 6.28318 + sp * 0.4 + 4.19))\nskip = if(above(si, 0.985), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:254: content: "name: \"Pina Colada\"\nmode: lines\nblend: additive\npersist: 0.887\nlinewidth: 1.779\n\n[init]\nn = 943\n\n[frame]\nt = t + dt * (0.219 + bass_att * 1.8)\nhue = hue + dt * 0.098 + beat * 0.012\n\n[point]\narm = floor(i * 8)\nfa = frac(i * 8)\nd = fa\nang = arm * 1.519 + d * 1.263 * 3.14159 + t\nrad = (0.04 + pow(d, 2.354) * 1.15) * (0.7 + bass * 0.5)\nx = sin(ang) * rad / aspect\ny = cos(ang) * rad\nred = (0.3 + 0.7 * d) * (0.3 + mid) * (0.25 + bass * 0.95)\ngreen = (0.3 + 0.7 * d) * (0.3 + mid) * (0.25 + mid * 0.95)\nblue = (0.3 + 0.7 * d) * (0.3 + mid) * (0.25 + treb * 0.95)\nskip = if(below(fa, 0.04), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:263: content: "name: \"Scope in Spotlight II\"\nmode: lines\nblend: additive\npersist: 0.854\nlinewidth: 2.056\n\n[init]\nsegs = 7\nn = 462\n\n[frame]\nrot = rot + dt * (0.107 + mid_att * 0.5)\nhue = hue + dt * 0.035\nflash = flash * 0.85\n\n[beat]\nflash = 1\n\n[point]\nseg = floor(i * segs)\nsi = frac(i * segs)\na0 = si * 6.28318 / segs + rot\namp = 0.1 + sv * 0.55 + bass * 0.25 + flash * 0.06\nrad = 0.15 + amp * (0.4 + 0.6 * sin(a0 * 4 + time * 2))\na = seg * 6.28318 / segs + a0 * if(below(seg % 2, 1), 1, -1)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = min(1, 0.3 + amp * 1.3 * 1.3)\ngreen = 0.3 + amp * 1.3 * 0.5\nblue = 0.3 + amp * 1.3 * 0.12\nskip = if(above(si, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:272: content: "name: \"Solero Shots\"\nmode: lines\nblend: additive\npersist: 0.878\nlinewidth: 2.226\n\n[init]\nbars = 40\nn = bars * 12\n\n[frame]\nrot = rot + dt * (0.078 + mid * 0.3)\nhue = hue + dt * 0.032\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.813\na = bar * 6.28318 / bars + rot\nrad = 0.218 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.25 + bi * 0.75 * 0.3\ngreen = 0.25 + bi * 0.75 * 0.65\nblue = min(1, 0.25 + bi * 0.75 * 1.3)\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:281: content: "name: \"Square Minded\"\nmode: dots\nblend: additive\npersist: 0.783\nlinewidth: 2.696\n\n[init]\nn = 1492\n\n[frame]\nt = t + dt * 0.656\nhue = hue + dt * 0.13\n\n[point]\nu = rand(i * 1.7) * 2 - 1\nw = rand(i * 3.3 + 11) * 2 - 1\nm = sin((u * 3.356 + w * 3.959 + t) * 3.14159) * sin((u * 3.01 - w * 6.626 - t * 0.7) * 3.14159)\nx = u * 0.994 / aspect\ny = w * 0.856\nlum = max(0, m) * (0.3 + bass * 0.9) + 0.06\nred = lum * 0.85\ngreen = lum * 0.92\nblue = lum\nsize = 1 + abs(m) * 3.211\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:290: content: "name: \"Worm-O-Rama (Raz Remix)\"\nmode: lines\nblend: additive\npersist: 0.894\nlinewidth: 1.933\n\n[init]\nn = 1189\n\n[frame]\nt = t + dt * (0.418 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.102\n\n[point]\na = i * 6.28318 * 3\nwob = sin(a * 3 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.282 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + abs(v) * 1.2 * (0.25 + bass * 0.95)\ngreen = 0.3 + abs(v) * 1.2 * (0.25 + mid * 0.95)\nblue = 0.3 + abs(v) * 1.2 * (0.25 + treb * 0.95)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:299: content: "# Auto-ported from \"UnConeD - Zero-G Maze.avs\" (Winamp AVS / UnConeD)\n# SuperScope point program, 4 AVSTrans macros expanded.\nname: \"Zero-G Maze\"\nauthor: \"UnConeD\"\nmode: lines\nblend: additive\npersist: 0.88\nlinewidth: 2\nysign: -1\n\n[init]\nn=50;ro=0;go=2.0;bo=4.0\n\n[frame]\nt=t-0.05;aa=aa*0.7;\n\n[beat]\naa=0.0;ro=rnd(100)/100*6.28;go=rnd(100)/100*6.28;bo=rnd(100)/100*6.28\n\n[point]\ny=0;x=i*.5-.1;\r\nred=sin(t+ro+i*2)*.5+.5;\r\ngreen=sin(t+go+i*2)*.5+.5;\r\nblue=sin(t+bo+i*2)*.5+.5;\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:308: content: "name: \"Cartoon Trip\"\nmode: lines\nblend: additive\npersist: 0.831\nlinewidth: 2.55\n\n[init]\nbars = 39\nn = bars * 9\n\n[frame]\nrot = rot + dt * (0.116 + mid * 0.3)\nhue = hue + dt * 0.112\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.83\na = bar * 6.28318 / bars + rot\nrad = 0.189 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.25 + bi * 0.75 * 0.85\ngreen = 0.25 + bi * 0.75 * 0.92\nblue = 0.25 + bi * 0.75\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:317: content: "name: \"Containment\"\nmode: lines\nblend: additive\npersist: 0.935\nlinewidth: 1.8\n\n[init]\nn = 847\n\n[frame]\nt = t + dt * (0.436 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.071\n\n[point]\na = i * 6.28318 * 2\nwob = sin(a * 2 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.25 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = min(1, 0.3 + abs(v) * 1.2 * 1.3)\ngreen = 0.3 + abs(v) * 1.2 * 0.5\nblue = 0.3 + abs(v) * 1.2 * 0.12\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:326: content: "# Auto-ported from \"UnConeD - Cubic Flower.avs\" (Winamp AVS / UnConeD)\n# SuperScope point program, 4 AVSTrans macros expanded.\nname: \"Cubic Flower\"\nauthor: \"UnConeD\"\nmode: lines\nblend: additive\npersist: 0.88\nlinewidth: 2\nysign: -1\n\n[init]\nn=40;ro=0;go=2.0;bo=4.0\n\n[frame]\nt=t-0.05;aa=aa*0.7;\n\n[beat]\naa=1;ro=rnd(100)/100*6.28;go=rnd(100)/100*6.28;bo=rnd(100)/100*6.28\n\n[point]\nx=i*.8-.4;y=0;\r\nred=sin(t+ro+i*2)/2+.5+aa;\r\ngreen=sin(t+go+i*2)/2+.5+aa;\r\nblue=sin(t+bo+i*2)/2+.5+aa;\r\nblue=blue+1-min(red+green+blue,1)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:335: content: "name: \"Jello Cube\"\nmode: lines\nblend: additive\npersist: 0.813\nlinewidth: 2.201\n\n[init]\nn = 620\n\n[frame]\nhue = hue + dt * 0.073 + beat * 0.01\ntravel = travel + dt * (0.196 + bass_att * 1.4)\nflash = flash * 0.86\n\n[beat]\nflash = 1\n\n[point]\ng = floor(i * 10)\ngi = frac(i * 10)\nph = frac(rand(g * 5.1 + 1) + travel * (0.55 + rand(g + 17) * 0.85))\na = gi * 6.28318\nrad = ph * (0.226 + bass * 0.743 + flash * 0.08)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nfade = sin(ph * 3.14159)\nred = fade * (0.35 + flash * 0.4) * abs(sin(g * 0.7))\ngreen = fade * (0.35 + flash * 0.4) * 0.22\nblue = fade * (0.35 + flash * 0.4) * abs(cos(g * 0.7))\nskip = if(above(ph, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:344: content: "name: \"Mercury\"\nmode: lines\nblend: additive\npersist: 0.888\nlinewidth: 1.97\n\n[init]\nn = 1109\n\n[frame]\nt = t + dt * (0.329 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.097\n\n[point]\na = i * 6.28318 * 3\nwob = sin(a * 6 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.31 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + abs(v) * 1.2 * 0.3\ngreen = 0.3 + abs(v) * 1.2 * 0.65\nblue = min(1, 0.3 + abs(v) * 1.2 * 1.3)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:353: content: "name: \"Neon Coaster\"\nmode: dots\nblend: additive\npersist: 0.897\nlinewidth: 2.488\n\n[init]\nbars = 33\nn = bars * 12\n\n[frame]\nrot = rot + dt * (0.092 + mid * 0.3)\nhue = hue + dt * 0.066\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.765\na = bar * 6.28318 / bars + rot\nrad = 0.193 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = min(1, 0.25 + bi * 0.75 * 1.3)\ngreen = 0.25 + bi * 0.75 * 0.5\nblue = 0.25 + bi * 0.75 * 0.12\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:362: content: "name: \"Plankton\"\nmode: dots\nblend: additive\npersist: 0.83\nlinewidth: 2.37\n\n[init]\nn = 627\n\n[frame]\nhue = hue + dt * 0.033 + beat * 0.01\ntravel = travel + dt * (0.435 + bass_att * 1.4)\nflash = flash * 0.86\n\n[beat]\nflash = 1\n\n[point]\ng = floor(i * 11)\ngi = frac(i * 11)\nph = frac(rand(g * 5.1 + 1) + travel * (0.55 + rand(g + 17) * 0.85))\na = gi * 6.28318\nrad = ph * (0.194 + bass * 0.352 + flash * 0.08)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nfade = sin(ph * 3.14159)\nred = min(1, fade * (0.35 + flash * 0.4) * 1.3)\ngreen = fade * (0.35 + flash * 0.4) * 0.5\nblue = fade * (0.35 + flash * 0.4) * 0.12\nskip = if(above(ph, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:371: content: "name: \"Reflectocube\"\nmode: lines\nblend: additive\npersist: 0.91\nlinewidth: 1.419\n\n[init]\nn = 1235\n\n[frame]\nt = t + dt * (0.31 + bass_att * 1.8)\nhue = hue + dt * 0.065 + beat * 0.012\n\n[point]\narm = floor(i * 4)\nfa = frac(i * 4)\nd = fa\nang = arm * 1.405 + d * 0.906 * 3.14159 + t\nrad = (0.04 + pow(d, 1.825) * 1.15) * (0.7 + bass * 0.5)\nx = sin(ang) * rad / aspect\ny = cos(ang) * rad\nred = (0.3 + 0.7 * d) * (0.3 + mid) * (0.45 + 0.55 * sin(hue * 6.28318 + d * 4.537))\ngreen = (0.3 + 0.7 * d) * (0.3 + mid) * (0.45 + 0.55 * sin(hue * 6.28318 + d * 4.537 + 2.09))\nblue = (0.3 + 0.7 * d) * (0.3 + mid) * (0.45 + 0.55 * sin(hue * 6.28318 + d * 4.537 + 4.19))\nskip = if(below(fa, 0.04), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:380: content: "name: \"Speeder 3K\"\nmode: dots\nblend: additive\npersist: 0.831\nlinewidth: 2.272\n\n[init]\nn = 949\n\n[frame]\ntravel = travel + dt * (0.156 + vol_att * 1.231)\nhue = hue + dt * 0.04\n\n[point]\na = rand(i * 7.3) * 6.28318\nz = frac(rand(i * 3.1 + 5) + travel * (0.5 + rand(i + 9) * 0.7))\nrad = z * z * 1.206\nx = sin(a) * rad / aspect\ny = cos(a) * rad\ntw = 0.4 + 0.6 * sin(z * 40 + time * 3) * (0.5 + treb)\nred = min(1, tw * 1.3)\ngreen = tw * 0.5\nblue = tw * 0.12\nsize = 1 + z * 3 * (0.5 + bass)\nskip = if(above(z, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:389: content: "name: \"TC Plasma\"\nmode: lines\nblend: additive\npersist: 0.932\nlinewidth: 1.976\n\n[init]\nn = 1072\n\n[frame]\nt = t + dt * (0.432 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.076\n\n[point]\na = i * 6.28318 * 3\nwob = sin(a * 4 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.223 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5))\ngreen = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5 + 2.09))\nblue = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5 + 4.19))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:398: content: "name: \"Tie Tunnel SSC\"\nmode: lines\nblend: additive\npersist: 0.851\nlinewidth: 2.021\n\n[init]\nn = 1179\n\n[frame]\nt = t + dt * (0.17 + bass_att * 0.9)\nhue = hue + dt * 0.129\nflash = flash * 0.86\n\n[beat]\nflash = 1\n\n[point]\nst = floor(i * 2)\nsi = frac(i * 2)\ns = si * 6 * 6.28318 + t\nph = st * 3.14159\nrad = (0.28 + bass * 0.32 + flash * 0.06) * (0.55 + 0.45 * (cos(s + ph) * 0.5 + 0.5))\nx = sin(s + ph) * rad / aspect\ny = (si - 0.5) * 1.8\nred = min(1, 0.25 + 0.55 * (cos(s + ph) * 0.5 + 0.5) + treb * 0.25 * 1.3)\ngreen = 0.25 + 0.55 * (cos(s + ph) * 0.5 + 0.5) + treb * 0.25 * 0.5\nblue = 0.25 + 0.55 * (cos(s + ph) * 0.5 + 0.5) + treb * 0.25 * 0.12\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:407: content: "name: \"Zero-G Maze II\"\nmode: lines\nblend: additive\npersist: 0.916\nlinewidth: 1.457\n\n[init]\nn = 1049\n\n[frame]\nt = t + dt * (0.267 + bass_att * 1.8)\nhue = hue + dt * 0.038 + beat * 0.012\n\n[point]\narm = floor(i * 7)\nfa = frac(i * 7)\nd = fa\nang = arm * 1.253 + d * 0.88 * 3.14159 + t\nrad = (0.04 + pow(d, 2.401) * 1.15) * (0.7 + bass * 0.5)\nx = sin(ang) * rad / aspect\ny = cos(ang) * rad\nred = (0.3 + 0.7 * d) * (0.3 + mid) * (0.45 + 0.55 * sin(hue * 6.28318 + d * 2.064))\ngreen = (0.3 + 0.7 * d) * (0.3 + mid) * (0.45 + 0.55 * sin(hue * 6.28318 + d * 2.064 + 2.09))\nblue = (0.3 + 0.7 * d) * (0.3 + mid) * (0.45 + 0.55 * sin(hue * 6.28318 + d * 2.064 + 4.19))\nskip = if(below(fa, 0.04), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:416: content: "name: \"UnConeD -Zero-G Maze III\"\nmode: lines\nblend: additive\npersist: 0.853\nlinewidth: 1.507\n\n[init]\nn = 722\n\n[frame]\nt = t + dt * (0.243 + bass_att * 1.5)\nhue = hue + dt * 0.093\n\n[point]\nring = floor(i * 19)\nri2 = frac(i * 19)\nz = frac(ring / 19 + t)\nrad = 0.05 + z * 0.881\na = ri2 * 6.28318 + ring * 0.16 + sin(t * 0.7) * 2\nx = sin(a) * rad * (0.55 + sv * 0.901) / aspect\ny = cos(a) * rad * (0.55 + sv * 0.901)\nred = (1 - z) * (0.3 + bass * 0.7) * 0.3\ngreen = (1 - z) * (0.3 + bass * 0.7) * 0.65\nblue = min(1, (1 - z) * (0.3 + bass * 0.7) * 1.3)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:425: content: "name: \"nebulous (skupers remix)\"\nmode: dots\nblend: additive\npersist: 0.833\nlinewidth: 2.862\n\n[init]\ncols = 28\nn = cols * cols\n\n[frame]\nrot = rot + dt * (0.104 + mid * 0.4)\nhue = hue + dt * 0.08\n\n[point]\ncx = floor(i * cols) / (cols - 1)\ncy = frac(i * cols)\nh = sv * 0.235\nux = (cx - 0.5) * 1.448\nuy = (cy - 0.5) * 1.448\nrx = ux * cos(rot) - uy * sin(rot)\nry = ux * sin(rot) + uy * cos(rot)\nx = (rx / aspect) * (1 - h * 0.7)\ny = ry * (1 - h * 0.7)\nred = 0.22 + h * 2.2 * (0.45 + 0.55 * sin(hue * 6.28318 + cx * 3.774))\ngreen = 0.22 + h * 2.2 * (0.45 + 0.55 * sin(hue * 6.28318 + cx * 3.774 + 2.09))\nblue = 0.22 + h * 2.2 * (0.45 + 0.55 * sin(hue * 6.28318 + cx * 3.774 + 4.19))\nsize = 1.2 + h * 5\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:434: content: "name: \"soundscape III (skupers remix)\"\nmode: lines\nblend: additive\npersist: 0.851\nlinewidth: 1.939\n\n[init]\nsegs = 14\nn = 582\n\n[frame]\nrot = rot + dt * (0.13 + mid_att * 0.5)\nhue = hue + dt * 0.073\nflash = flash * 0.85\n\n[beat]\nflash = 1\n\n[point]\nseg = floor(i * segs)\nsi = frac(i * segs)\na0 = si * 6.28318 / segs + rot\namp = 0.1 + sv * 0.55 + bass * 0.25 + flash * 0.06\nrad = 0.15 + amp * (0.4 + 0.6 * sin(a0 * 4 + time * 2))\na = seg * 6.28318 / segs + a0 * if(below(seg % 2, 1), 1, -1)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + amp * 1.3 * abs(sin(seg * 0.8))\ngreen = 0.3 + amp * 1.3 * 0.22\nblue = 0.3 + amp * 1.3 * abs(cos(seg * 0.8))\nskip = if(above(si, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:443: content: "# Auto-ported from \"fck - checkers with metaballs (skupers remix).avs\" (Winamp AVS / fck)\n# SuperScope point program, 4 AVSTrans macros expanded.\nname: \"checkers with metaballs (skupers remix)\"\nauthor: \"fck\"\nmode: lines\nblend: additive\npersist: 0.88\nlinewidth: 2\nysign: -1\n\n[init]\nn=500;p=3.14159\n\n[frame]\nk=h/w*1.05;mxs=mxs+g;mys=mys+g2;mx=sin(mxs)*.8;my=sin(mys)*.8;t=t+.1\n\n[beat]\ng=getosc(.2,0,0)/3;g2=getosc(.8,0,0)/3\n\n[point]\nd=i/6+getosc(0,0,0)/5*i; \r\nr=i*p*44; \r\nx=(cos(r)*d+mx)*k; \r\ny=sin(r)*d+my;\r\nlig=sin(r)*above(sin(r),0)/2;\r\nblue=(1-i)-lig;\r\ngreen=blue;\r\nred=sqrt(blue)*2-lig\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:452: content: "name: \"jinx (skupers remix)\"\nmode: dots\nblend: additive\npersist: 0.814\nlinewidth: 1.769\n\n[init]\nbars = 46\nn = bars * 12\n\n[frame]\nrot = rot + dt * (0.046 + mid * 0.3)\nhue = hue + dt * 0.043\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.65\na = bar * 6.28318 / bars + rot\nrad = 0.246 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.25 + bi * 0.75 * abs(sin(bar * 6.28318 / bars))\ngreen = 0.25 + bi * 0.75 * 0.22\nblue = 0.25 + bi * 0.75 * abs(cos(bar * 6.28318 / bars))\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:461: content: "name: \"not quite a bendy tunnel (skupers remix)\"\nmode: lines\nblend: additive\npersist: 0.862\nlinewidth: 1.443\n\n[init]\nn = 806\n\n[frame]\nt = t + dt * 0.276\nhue = hue + dt * 0.055\n\n[point]\nph = i * 6.28318 * 1.699\nfa = 2 + mid * 0.35\nfb = 3 + bass * 0.45\nx = sin(ph * fa + t) * (0.5 + bass * 0.3) / aspect\ny = sin(ph * fb + t * 1.3 + 2.216) * (0.5 + treb * 0.35)\nred = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * 0.3\ngreen = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * 0.65\nblue = min(1, 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * 1.3)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:470: content: "name: \"newpoop (for wa5)\"\nmode: dots\nblend: additive\npersist: 0.796\nlinewidth: 2.44\n\n[init]\nrings = 4\nn = rings * 98\n\n[frame]\nt = t + dt * (0.176 + bass_att * 0.6)\nhue = hue + dt * 0.135\nsquash = 0.549 + 0.25 * sin(t * 0.439)\n\n[point]\nring = floor(i * rings)\nri3 = frac(i * rings)\nr0 = 0.16 + ring * 0.12\na = ri3 * 6.28318 + t * (1.2 - ring * 0.18) + ring * 2.4\nx = sin(a) * r0 * (1 + bass * 0.18) / aspect\ny = cos(a) * r0 * squash\nsat = frac(ri3 * 5)\nsize = if(below(sat, 0.14), 3 + bass * 3, 1)\nred = min(1, 0.25 + bass * 0.5 + ring * 0.07 * 1.3)\ngreen = 0.25 + bass * 0.5 + ring * 0.07 * 0.5\nblue = 0.25 + bass * 0.5 + ring * 0.07 * 0.12\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:479: content: "name: \"the landscape is killing me (wa5remix)\"\nmode: dots\nblend: additive\npersist: 0.704\nlinewidth: 2.586\n\n[init]\ncols = 54\nn = 1193\n\n[frame]\nfall = fall + dt * (0.514 + vol_att * 0.841)\nhue = hue + dt * 0.071\n\n[point]\ncol = floor(i * cols)\nci = frac(i * cols)\nxx = (col / cols - 0.5) * 1.9\nyf = frac(rand(col * 3.7 + 1) + fall * (0.55 + rand(col + 5) * 0.5))\ntail = rand(col * 1.3 + 9) * 0.31 + 0.04\nyy = (yf * 2 - 1) * 1.05 + ci * tail\nx = xx / aspect\ny = yy\nred = (1 - ci) * (0.2 + treb * 0.85) + 0.04 * (0.45 + 0.55 * sin(hue * 6.28318 + col * 0.3))\ngreen = (1 - ci) * (0.2 + treb * 0.85) + 0.04 * (0.45 + 0.55 * sin(hue * 6.28318 + col * 0.3 + 2.09))\nblue = (1 - ci) * (0.2 + treb * 0.85) + 0.04 * (0.45 + 0.55 * sin(hue * 6.28318 + col * 0.3 + 4.19))\nskip = if(above(abs(yy), 1.02), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:488: content: "name: \"Dragonscales\"\nmode: lines\nblend: additive\npersist: 0.885\nlinewidth: 2.375\n\n[init]\nn = 938\n\n[frame]\nt = t + dt * 0.353\nhue = hue + dt * 0.094\n\n[point]\nph = i * 6.28318 * 2.096\nfa = 2 + mid * 0.35\nfb = 3 + bass * 0.45\nx = sin(ph * fa + t) * (0.5 + bass * 0.3) / aspect\ny = sin(ph * fb + t * 1.3 + 2.866) * (0.5 + treb * 0.35)\nred = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * (0.25 + bass * 0.95)\ngreen = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * (0.25 + mid * 0.95)\nblue = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * (0.25 + treb * 0.95)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:497: content: "name: \"Encapsulade\"\nmode: lines\nblend: additive\npersist: 0.814\nlinewidth: 2.058\n\n[init]\nbars = 64\nn = bars * 9\n\n[frame]\nrot = rot + dt * (0.103 + mid * 0.3)\nhue = hue + dt * 0.072\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.85\na = bar * 6.28318 / bars + rot\nrad = 0.262 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.25 + bi * 0.75 * (0.45 + 0.55 * sin(hue * 6.28318 + bar * 6.28318 / bars))\ngreen = 0.25 + bi * 0.75 * (0.45 + 0.55 * sin(hue * 6.28318 + bar * 6.28318 / bars + 2.09))\nblue = 0.25 + bi * 0.75 * (0.45 + 0.55 * sin(hue * 6.28318 + bar * 6.28318 / bars + 4.19))\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:506: content: "name: \"Freekwyrms\"\nmode: dots\nblend: additive\npersist: 0.864\nlinewidth: 1.436\n\n[init]\nbars = 46\nn = bars * 12\n\n[frame]\nrot = rot + dt * (0.09 + mid * 0.3)\nhue = hue + dt * 0.063\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.722\na = bar * 6.28318 / bars + rot\nrad = 0.216 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = min(1, 0.25 + bi * 0.75 * 1.3)\ngreen = 0.25 + bi * 0.75 * 0.5\nblue = 0.25 + bi * 0.75 * 0.12\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:515: content: "name: \"Lilypod\"\nmode: dots\nblend: additive\npersist: 0.787\nlinewidth: 1.928\n\n[init]\nn = 885\n\n[frame]\ntt = tt + dt * (0.5 + bass_att * 1.1)\nhue = hue + dt * 0.04\nburst = burst * 0.9\n\n[beat]\nburst = 1\n\n[point]\njet = floor(i * 4)\nlife = frac(rand(i * 7.7 + jet) + tt * (0.35 + rand(i + 3) * 0.65))\na = jet * 6.28318 / 4 + rand(i * 5.1 + jet) * 0.722\nspd = 0.4 + rand(i * 9.2 + jet) * 0.8\npx = cos(a) * spd * life\npy = sin(a) * spd * life - 0.744 * life * life\nx = px * (0.85 + bass * 0.35) / aspect\ny = py\nred = max(0, 1 - life) * (0.35 + burst * 0.55) * abs(sin(life * 4))\ngreen = max(0, 1 - life) * (0.35 + burst * 0.55) * 0.22\nblue = max(0, 1 - life) * (0.35 + burst * 0.55) * abs(cos(life * 4))\nskip = if(above(life, 0.94), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:524: content: "name: \"Mist Wisps\"\nmode: dots\nblend: additive\npersist: 0.758\nlinewidth: 2.24\n\n[init]\nn = 1297\n\n[frame]\nt = t + dt * 0.323\nhue = hue + dt * 0.1\n\n[point]\nu = rand(i * 1.7) * 2 - 1\nw = rand(i * 3.3 + 11) * 2 - 1\nm = sin((u * 2.207 + w * 6.547 + t) * 3.14159) * sin((u * 5.739 - w * 2.319 - t * 0.7) * 3.14159)\nx = u * 0.85 / aspect\ny = w * 0.957\nlum = max(0, m) * (0.3 + bass * 0.9) + 0.06\nred = lum * (0.25 + bass * 0.95)\ngreen = lum * (0.25 + mid * 0.95)\nblue = lum * (0.25 + treb * 0.95)\nsize = 1 + abs(m) * 3.505\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:533: content: "name: \"Nebulating - Hypercolorspace\"\nmode: dots\nblend: additive\npersist: 0.792\nlinewidth: 2.678\n\n[init]\nn = 1374\n\n[frame]\nt = t + dt * 0.423\nhue = hue + dt * 0.123\n\n[point]\nu = rand(i * 1.7) * 2 - 1\nw = rand(i * 3.3 + 11) * 2 - 1\nm = sin((u * 3.51 + w * 2.666 + t) * 3.14159) * sin((u * 6.323 - w * 6.393 - t * 0.7) * 3.14159)\nx = u * 0.959 / aspect\ny = w * 0.871\nlum = max(0, m) * (0.3 + bass * 0.9) + 0.06\nred = min(1, lum * 1.3)\ngreen = lum * 0.5\nblue = lum * 0.12\nsize = 1 + abs(m) * 3.799\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:542: content: "name: \"Reverb - Deep Net\"\nmode: dots\nblend: additive\npersist: 0.818\nlinewidth: 2.394\n\n[init]\ncols = 29\nn = cols * cols\n\n[frame]\nrot = rot + dt * (0.041 + mid * 0.4)\nhue = hue + dt * 0.089\n\n[point]\ncx = floor(i * cols) / (cols - 1)\ncy = frac(i * cols)\nh = sv * 0.525\nux = (cx - 0.5) * 1.845\nuy = (cy - 0.5) * 1.845\nrx = ux * cos(rot) - uy * sin(rot)\nry = ux * sin(rot) + uy * cos(rot)\nx = (rx / aspect) * (1 - h * 0.7)\ny = ry * (1 - h * 0.7)\nred = 0.22 + h * 2.2 * abs(sin(cx * 2.712))\ngreen = 0.22 + h * 2.2 * 0.22\nblue = 0.22 + h * 2.2 * abs(cos(cx * 2.712))\nsize = 1.2 + h * 5\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:551: content: "name: \"Slyde - Tri\"\nmode: lines\nblend: additive\npersist: 0.863\nlinewidth: 1.626\n\n[init]\nn = 938\n\n[frame]\nt = t + dt * 0.483\nhue = hue + dt * 0.076\n\n[point]\nph = i * 6.28318 * 2.841\nfa = 6 + mid * 0.35\nfb = 2 + bass * 0.45\nx = sin(ph * fa + t) * (0.5 + bass * 0.3) / aspect\ny = sin(ph * fb + t * 1.3 + 1.909) * (0.5 + treb * 0.35)\nred = min(1, 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * 1.3)\ngreen = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * 0.5\nblue = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * 0.12\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:560: content: "name: \"Solar Flaire\"\nmode: lines\nblend: additive\npersist: 0.866\nlinewidth: 1.678\n\n[init]\nbars = 59\nn = bars * 11\n\n[frame]\nrot = rot + dt * (0.076 + mid * 0.3)\nhue = hue + dt * 0.107\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.607\na = bar * 6.28318 / bars + rot\nrad = 0.241 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.25 + bi * 0.75 * (0.45 + 0.55 * sin(hue * 6.28318 + bar * 6.28318 / bars))\ngreen = 0.25 + bi * 0.75 * (0.45 + 0.55 * sin(hue * 6.28318 + bar * 6.28318 / bars + 2.09))\nblue = 0.25 + bi * 0.75 * (0.45 + 0.55 * sin(hue * 6.28318 + bar * 6.28318 / bars + 4.19))\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:569: content: "name: \"Spintronics - Backspin\"\nmode: dots\nblend: additive\npersist: 0.804\nlinewidth: 2.037\n\n[init]\nn = 1157\n\n[frame]\ntt = tt + dt * (0.5 + bass_att * 1.1)\nhue = hue + dt * 0.12\nburst = burst * 0.9\n\n[beat]\nburst = 1\n\n[point]\njet = floor(i * 4)\nlife = frac(rand(i * 7.7 + jet) + tt * (0.35 + rand(i + 3) * 0.65))\na = jet * 6.28318 / 4 + rand(i * 5.1 + jet) * 0.547\nspd = 0.4 + rand(i * 9.2 + jet) * 0.8\npx = cos(a) * spd * life\npy = sin(a) * spd * life - 0.712 * life * life\nx = px * (0.85 + bass * 0.35) / aspect\ny = py\nred = min(1, max(0, 1 - life) * (0.35 + burst * 0.55) * 1.3)\ngreen = max(0, 1 - life) * (0.35 + burst * 0.55) * 0.5\nblue = max(0, 1 - life) * (0.35 + burst * 0.55) * 0.12\nskip = if(above(life, 0.94), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:578: content: "name: \"Starslappin\"\nmode: lines\nblend: additive\npersist: 0.842\nlinewidth: 2.148\n\n[init]\nsegs = 7\nn = 545\n\n[frame]\nrot = rot + dt * (0.087 + mid_att * 0.5)\nhue = hue + dt * 0.125\nflash = flash * 0.85\n\n[beat]\nflash = 1\n\n[point]\nseg = floor(i * segs)\nsi = frac(i * segs)\na0 = si * 6.28318 / segs + rot\namp = 0.1 + sv * 0.55 + bass * 0.25 + flash * 0.06\nrad = 0.15 + amp * (0.4 + 0.6 * sin(a0 * 6 + time * 2))\na = seg * 6.28318 / segs + a0 * if(below(seg % 2, 1), 1, -1)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + amp * 1.3 * (0.25 + bass * 0.95)\ngreen = 0.3 + amp * 1.3 * (0.25 + mid * 0.95)\nblue = 0.3 + amp * 1.3 * (0.25 + treb * 0.95)\nskip = if(above(si, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:587: content: "name: \"Street Art - Fire Inside\"\nmode: dots\nblend: additive\npersist: 0.757\nlinewidth: 2.052\n\n[init]\nn = 1065\n\n[frame]\ntt = tt + dt * (0.5 + bass_att * 1.1)\nhue = hue + dt * 0.108\nburst = burst * 0.9\n\n[beat]\nburst = 1\n\n[point]\njet = floor(i * 4)\nlife = frac(rand(i * 7.7 + jet) + tt * (0.35 + rand(i + 3) * 0.65))\na = jet * 6.28318 / 4 + rand(i * 5.1 + jet) * 1.184\nspd = 0.4 + rand(i * 9.2 + jet) * 0.8\npx = cos(a) * spd * life\npy = sin(a) * spd * life - 1.383 * life * life\nx = px * (0.85 + bass * 0.35) / aspect\ny = py\nred = max(0, 1 - life) * (0.35 + burst * 0.55) * 0.3\ngreen = max(0, 1 - life) * (0.35 + burst * 0.55) * 0.65\nblue = min(1, max(0, 1 - life) * (0.35 + burst * 0.55) * 1.3)\nskip = if(above(life, 0.94), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:596: content: "name: \"Swoo - Slow\"\nmode: lines\nblend: additive\npersist: 0.919\nlinewidth: 1.852\n\n[init]\nn = 1159\n\n[frame]\nt = t + dt * (0.461 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.046\n\n[point]\na = i * 6.28318 * 3\nwob = sin(a * 3 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.199 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + abs(v) * 1.2 * 0.3\ngreen = 0.3 + abs(v) * 1.2 * 0.65\nblue = min(1, 0.3 + abs(v) * 1.2 * 1.3)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:605: content: "name: \"smell of music (skupers remix)\"\nmode: lines\nblend: additive\npersist: 0.805\nlinewidth: 1.342\n\n[init]\nspokes = 31\nn = spokes * 34\n\n[frame]\nrot = rot + dt * (0.118 + mid * 0.4)\nt = t + dt * 2.453\nhue = hue + dt * 0.113\n\n[point]\nsp = floor(i * spokes)\nsi = frac(i * spokes)\na = sp * 6.28318 / spokes + rot\nwave = sin(si * 3 * 3.14159 - t) * (0.03 + bass * 0.28)\nrad = 0.12 + si * 0.868 + wave\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = (1 - si) * 0.45 + 0.15 + sv * 0.55 * 0.3\ngreen = (1 - si) * 0.45 + 0.15 + sv * 0.55 * 0.65\nblue = min(1, (1 - si) * 0.45 + 0.15 + sv * 0.55 * 1.3)\nskip = if(above(si, 0.985), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:614: content: "name: \"bumpy\"\nmode: dots\nblend: additive\npersist: 0.798\nlinewidth: 1.642\n\n[init]\nn = 640\n\n[frame]\nhue = hue + dt * 0.119 + beat * 0.01\ntravel = travel + dt * (0.394 + bass_att * 1.4)\nflash = flash * 0.86\n\n[beat]\nflash = 1\n\n[point]\ng = floor(i * 10)\ngi = frac(i * 10)\nph = frac(rand(g * 5.1 + 1) + travel * (0.55 + rand(g + 17) * 0.85))\na = gi * 6.28318\nrad = ph * (0.28 + bass * 0.544 + flash * 0.08)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nfade = sin(ph * 3.14159)\nred = fade * (0.35 + flash * 0.4) * 0.3\ngreen = fade * (0.35 + flash * 0.4) * 0.65\nblue = min(1, fade * (0.35 + flash * 0.4) * 1.3)\nskip = if(above(ph, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:623: content: "name: \"splendora\"\nmode: lines\nblend: additive\npersist: 0.867\nlinewidth: 1.513\n\n[init]\nn = 974\n\n[frame]\nt = t + dt * (0.211 + bass_att * 1.8)\nhue = hue + dt * 0.068 + beat * 0.012\n\n[point]\narm = floor(i * 9)\nfa = frac(i * 9)\nd = fa\nang = arm * 1.515 + d * 1.922 * 3.14159 + t\nrad = (0.04 + pow(d, 1.746) * 1.15) * (0.7 + bass * 0.5)\nx = sin(ang) * rad / aspect\ny = cos(ang) * rad\nred = (0.3 + 0.7 * d) * (0.3 + mid) * abs(sin(d * 2.585))\ngreen = (0.3 + 0.7 * d) * (0.3 + mid) * 0.22\nblue = (0.3 + 0.7 * d) * (0.3 + mid) * abs(cos(d * 2.585))\nskip = if(below(fa, 0.04), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:632: content: "name: \"Urantia\"\nmode: dots\nblend: additive\npersist: 0.862\nlinewidth: 2.9\n\n[init]\nrings = 4\nn = rings * 101\n\n[frame]\nt = t + dt * (0.393 + bass_att * 0.6)\nhue = hue + dt * 0.094\nsquash = 0.387 + 0.25 * sin(t * 0.454)\n\n[point]\nring = floor(i * rings)\nri3 = frac(i * rings)\nr0 = 0.16 + ring * 0.141\na = ri3 * 6.28318 + t * (1.2 - ring * 0.18) + ring * 2.4\nx = sin(a) * r0 * (1 + bass * 0.18) / aspect\ny = cos(a) * r0 * squash\nsat = frac(ri3 * 2)\nsize = if(below(sat, 0.14), 3 + bass * 3, 1)\nred = 0.25 + bass * 0.5 + ring * 0.07 * (0.25 + bass * 0.95)\ngreen = 0.25 + bass * 0.5 + ring * 0.07 * (0.25 + mid * 0.95)\nblue = 0.25 + bass * 0.5 + ring * 0.07 * (0.25 + treb * 0.95)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:641: content: "name: \"tentaclism (fake hboy rmx)\"\nmode: dots\nblend: additive\npersist: 0.833\nlinewidth: 2.485\n\n[init]\nn = 952\n\n[frame]\ntravel = travel + dt * (0.231 + vol_att * 1.898)\nhue = hue + dt * 0.056\n\n[point]\na = rand(i * 7.3) * 6.28318\nz = frac(rand(i * 3.1 + 5) + travel * (0.5 + rand(i + 9) * 0.7))\nrad = z * z * 0.992\nx = sin(a) * rad / aspect\ny = cos(a) * rad\ntw = 0.4 + 0.6 * sin(z * 40 + time * 3) * (0.5 + treb)\nred = min(1, tw * 1.3)\ngreen = tw * 0.5\nblue = tw * 0.12\nsize = 1 + z * 3 * (0.5 + bass)\nskip = if(above(z, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:650: content: "name: \"tentaclism (sky of contempt mix by drew)\"\nmode: dots\nblend: additive\npersist: 0.83\nlinewidth: 2.652\n\n[init]\nrings = 3\nn = rings * 87\n\n[frame]\nt = t + dt * (0.201 + bass_att * 0.6)\nhue = hue + dt * 0.06\nsquash = 0.564 + 0.25 * sin(t * 0.401)\n\n[point]\nring = floor(i * rings)\nri3 = frac(i * rings)\nr0 = 0.16 + ring * 0.108\na = ri3 * 6.28318 + t * (1.2 - ring * 0.18) + ring * 2.4\nx = sin(a) * r0 * (1 + bass * 0.18) / aspect\ny = cos(a) * r0 * squash\nsat = frac(ri3 * 4)\nsize = if(below(sat, 0.14), 3 + bass * 3, 1)\nred = 0.25 + bass * 0.5 + ring * 0.07 * abs(sin(ring * 1.3))\ngreen = 0.25 + bass * 0.5 + ring * 0.07 * 0.22\nblue = 0.25 + bass * 0.5 + ring * 0.07 * abs(cos(ring * 1.3))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:659: content: "# Auto-ported from \"03 dynamic duo - tentaclism (microdee's grandpa was a tentaclist).avs\" (Winamp AVS / dynamic duo)\n# SuperScope point program, 4 AVSTrans macros expanded.\nname: \"tentaclism (microdee's grandpa was a tentaclist)\"\nauthor: \"dynamic duo\"\nmode: dots\nblend: additive\npersist: 0.78\nlinewidth: 3\nysign: -1\n\n[init]\nn=40; ln1=1; ln=ln1+2;\r\ncns=.6; chs2=200; chs1=35; mrab=rnd(10)/20;\n\n[frame]\nt=t-0.05; pc=0; sw=-1; sm=sm+rnd(20)/200;\r\nsrm=.9*(srm+rnd(100)*.0004);\r\nssm=sin(sm)*srm+rnd(100)*.0003;\n\n[beat]\nflash = 1\n\n[point]\nsw=sw*-1;\r\nx=if(above(pc,ln),rnd(100)/50-1,rnd(100)/2000+.27+ssm);y=if(above(pc,ln),rnd(100)/50-1,sw);\r\nred=rnd(100)/100; green=red; blue=red; pc=pc+1;\r\ndrawmode=below(pc,ln); skip=band(below(pc,ln),equal(sw,1))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:668: content: "name: \"tentaclism (cathode ray mix by onionring of doom)\"\nmode: lines\nblend: additive\npersist: 0.873\nlinewidth: 1.987\n\n[init]\nspokes = 26\nn = spokes * 38\n\n[frame]\nrot = rot + dt * (0.076 + mid * 0.4)\nt = t + dt * 1.652\nhue = hue + dt * 0.062\n\n[point]\nsp = floor(i * spokes)\nsi = frac(i * spokes)\na = sp * 6.28318 / spokes + rot\nwave = sin(si * 5 * 3.14159 - t) * (0.03 + bass * 0.28)\nrad = 0.12 + si * 0.882 + wave\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = (1 - si) * 0.45 + 0.15 + sv * 0.55 * 0.3\ngreen = (1 - si) * 0.45 + 0.15 + sv * 0.55 * 0.65\nblue = min(1, (1 - si) * 0.45 + 0.15 + sv * 0.55 * 1.3)\nskip = if(above(si, 0.985), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:677: content: "name: \"chromatics (glowy mix by meaningless-existance)\"\nmode: lines\nblend: additive\npersist: 0.857\nlinewidth: 1.543\n\n[init]\nn = 731\n\n[frame]\nt = t + dt * (0.338 + bass_att * 1.5)\nhue = hue + dt * 0.042\n\n[point]\nring = floor(i * 17)\nri2 = frac(i * 17)\nz = frac(ring / 17 + t)\nrad = 0.05 + z * 0.805\na = ri2 * 6.28318 + ring * 0.411 + sin(t * 0.7) * 2\nx = sin(a) * rad * (0.55 + sv * 1.073) / aspect\ny = cos(a) * rad * (0.55 + sv * 1.073)\nred = (1 - z) * (0.3 + bass * 0.7) * abs(sin(z * 2.074))\ngreen = (1 - z) * (0.3 + bass * 0.7) * 0.22\nblue = (1 - z) * (0.3 + bass * 0.7) * abs(cos(z * 2.074))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:686: content: "name: \"tentaclism (midas remix)\"\nmode: dots\nblend: additive\npersist: 0.848\nlinewidth: 2.168\n\n[init]\nn = 757\n\n[frame]\ntt = tt + dt * (0.5 + bass_att * 1.1)\nhue = hue + dt * 0.053\nburst = burst * 0.9\n\n[beat]\nburst = 1\n\n[point]\njet = floor(i * 2)\nlife = frac(rand(i * 7.7 + jet) + tt * (0.35 + rand(i + 3) * 0.65))\na = jet * 6.28318 / 2 + rand(i * 5.1 + jet) * 1.14\nspd = 0.4 + rand(i * 9.2 + jet) * 0.8\npx = cos(a) * spd * life\npy = sin(a) * spd * life - 1.009 * life * life\nx = px * (0.85 + bass * 0.35) / aspect\ny = py\nred = min(1, max(0, 1 - life) * (0.35 + burst * 0.55) * 1.3)\ngreen = max(0, 1 - life) * (0.35 + burst * 0.55) * 0.5\nblue = max(0, 1 - life) * (0.35 + burst * 0.55) * 0.12\nskip = if(above(life, 0.94), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:695: content: "name: \"tentaclism (raz remix - ugly edit)\"\nmode: lines\nblend: additive\npersist: 0.873\nlinewidth: 1.756\n\n[init]\nbars = 44\nn = bars * 11\n\n[frame]\nrot = rot + dt * (0.118 + mid * 0.3)\nhue = hue + dt * 0.119\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.767\na = bar * 6.28318 / bars + rot\nrad = 0.145 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.25 + bi * 0.75 * (0.45 + 0.55 * sin(hue * 6.28318 + bar * 6.28318 / bars))\ngreen = 0.25 + bi * 0.75 * (0.45 + 0.55 * sin(hue * 6.28318 + bar * 6.28318 / bars + 2.09))\nblue = 0.25 + bi * 0.75 * (0.45 + 0.55 * sin(hue * 6.28318 + bar * 6.28318 / bars + 4.19))\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:704: content: "name: \"tentaclism (the y.m.o. rework #1)\"\nmode: dots\nblend: additive\npersist: 0.831\nlinewidth: 1.694\n\n[init]\nspokes = 32\nn = spokes * 27\n\n[frame]\nrot = rot + dt * (0.073 + mid * 0.4)\nt = t + dt * 1.807\nhue = hue + dt * 0.131\n\n[point]\nsp = floor(i * spokes)\nsi = frac(i * spokes)\na = sp * 6.28318 / spokes + rot\nwave = sin(si * 2 * 3.14159 - t) * (0.03 + bass * 0.28)\nrad = 0.12 + si * 0.758 + wave\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = (1 - si) * 0.45 + 0.15 + sv * 0.55 * abs(sin(sp * 0.4))\ngreen = (1 - si) * 0.45 + 0.15 + sv * 0.55 * 0.22\nblue = (1 - si) * 0.45 + 0.15 + sv * 0.55 * abs(cos(sp * 0.4))\nskip = if(above(si, 0.985), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:713: content: "name: \"tentaclism (kans of kansis mix by drew - edit)\"\nmode: dots\nblend: additive\npersist: 0.827\nlinewidth: 2.039\n\n[init]\nn = 1449\n\n[frame]\nt = t + dt * 0.447\nhue = hue + dt * 0.034\n\n[point]\nu = rand(i * 1.7) * 2 - 1\nw = rand(i * 3.3 + 11) * 2 - 1\nm = sin((u * 6.164 + w * 5.725 + t) * 3.14159) * sin((u * 2.761 - w * 2.167 - t * 0.7) * 3.14159)\nx = u * 0.936 / aspect\ny = w * 0.903\nlum = max(0, m) * (0.3 + bass * 0.9) + 0.06\nred = min(1, lum * 1.3)\ngreen = lum * 0.5\nblue = lum * 0.12\nsize = 1 + abs(m) * 3.26\n", + +[Showing results with pagination = limit: 120] \ No newline at end of file diff --git a/tool-results/grep_1793924530808_9b7030ab1e59.txt b/tool-results/grep_1793924530808_9b7030ab1e59.txt new file mode 100644 index 0000000..a2efe2e --- /dev/null +++ b/tool-results/grep_1793924530808_9b7030ab1e59.txt @@ -0,0 +1,62 @@ +/home/z/my-project/src/lib/version.ts:233:// blank-line+section skeletons, "linewidth: " / "blend: additive" +/home/z/my-project/src/lib/ava/types.ts:9:export type BlendMode = 'additive' | 'alpha' | 'multiply' | 'screen' | 'subtract' | 'replace' +/home/z/my-project/src/lib/ava/share-codec.ts:130: { key: 'blend: additive', symbol: '⼆' }, +/home/z/my-project/src/lib/ava/presets.ts:22:blend: additive +/home/z/my-project/src/lib/ava/presets.ts:63:blend: additive +/home/z/my-project/src/lib/ava/presets.ts:106:blend: additive +/home/z/my-project/src/lib/ava/presets.ts:153:blend: additive +/home/z/my-project/src/lib/ava/presets.ts:195:blend: additive +/home/z/my-project/src/lib/ava/presets.ts:237:blend: additive +/home/z/my-project/src/lib/ava/engine.ts:15:import type { BandConfig, BandLevels, BeatConfig, BeatFrame, BlendMode } from './types' +/home/z/my-project/src/lib/ava/engine.ts:38:const BLEND_COMPOSITE: Record = { +/home/z/my-project/src/lib/ava/engine.ts:387: const replace = meta.blend === 'replace' +/home/z/my-project/src/lib/ava/script.ts:9:// blend: additive <- additive | alpha | multiply | screen | subtract | replace +/home/z/my-project/src/lib/ava/script.ts:19:import type { BlendMode, RenderMode } from './types' +/home/z/my-project/src/lib/ava/script.ts:26: blend: BlendMode +/home/z/my-project/src/lib/ava/script.ts:72: blend: 'additive', +/home/z/my-project/src/lib/ava/script.ts:168: meta.blend = value as BlendMode +/home/z/my-project/src/lib/ava/embedded-presets.ts:47: content: "# Auto-ported from \"D&L - Life Is Violated.avs\" (Winamp AVS / D&L)\n# SuperScope point program, 4 AVSTrans macros expanded.\nname: \"Life Is Violated\"\nauthor: \"D&L\"\nmode: lines\nblend: additive\npersist: 0.88\nlinewidth: 2\nysign: -1\n\n[init]\nn=800;xa=-0.5;ya=0.0;xb=-0.0;yb=0.75;c=200;f=0;\r\nnxa=(rnd(100)-50)*.02;nya=(rnd(100)-50)*.02;\r\nnxb=(rnd(100)-50)*.02;nyb=(rnd(100)-50)*.02;\n\n[frame]\nf=f+1;\r\nt=1-((cos((f*3.1415)/c)+1)*.5);\r\nxa=((nxa-lxa)*t)+lxa;\r\nya=((nya-lya)*t)+lya;\r\nxb=((nxb-lxb)*t)+lxb;\r\nyb=((nyb-lyb)*t)+lyb;\r\nex=(xb-xa);\r\ney=(yb-ya);\r\nd=sqrt(sqr(ex)+sqr(ey));\r\nr=atan(ey/ex)+(3.1415/2);\r\ndv=d*2\n\n[beat]\nc=f;\r\nf=0;\r\nlxa=nxa;\r\nlya=nya;\r\nlxb=nxb;\r\nlyb=nyb;\r\nnxa=(rnd(100)-50)*.02;\r\nnya=(rnd(100)-50)*.02;\r\nnxb=(rnd(100)-50)*.02;\r\nnyb=(rnd(100)-50)*.02\n\n[point]\n//primary render\r\nx=(ex*i)+xa;\r\ny=(ey*i)+ya;\r\n\r\n//volume offset\r\nx=x+ ( cos(r) * v * dv);\r\ny=y+ ( sin(r) * v * dv);\r\n\r\n//color values\r\nred=i;\r\ngreen=(1-i);\r\nblue=abs(v*6);\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:56: content: "name: \"Retrowall (Yathosho's Supermicrocosm)\"\nmode: dots\nblend: additive\npersist: 0.843\nlinewidth: 2.178\n\n[init]\nrings = 7\nn = rings * 103\n\n[frame]\nt = t + dt * (0.344 + bass_att * 0.6)\nhue = hue + dt * 0.112\nsquash = 0.315 + 0.25 * sin(t * 0.205)\n\n[point]\nring = floor(i * rings)\nri3 = frac(i * rings)\nr0 = 0.16 + ring * 0.142\na = ri3 * 6.28318 + t * (1.2 - ring * 0.18) + ring * 2.4\nx = sin(a) * r0 * (1 + bass * 0.18) / aspect\ny = cos(a) * r0 * squash\nsat = frac(ri3 * 5)\nsize = if(below(sat, 0.14), 3 + bass * 3, 1)\nred = 0.25 + bass * 0.5 + ring * 0.07 * (0.45 + 0.55 * sin(hue * 6.28318 + ring * 1.3))\ngreen = 0.25 + bass * 0.5 + ring * 0.07 * (0.45 + 0.55 * sin(hue * 6.28318 + ring * 1.3 + 2.09))\nblue = 0.25 + bass * 0.5 + ring * 0.07 * (0.45 + 0.55 * sin(hue * 6.28318 + ring * 1.3 + 4.19))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:65: content: "name: \"Adrealine rush\"\nmode: dots\nblend: additive\npersist: 0.826\nlinewidth: 1.803\n\n[init]\nn = 1287\n\n[frame]\nt = t + dt * 0.304\nhue = hue + dt * 0.11\n\n[point]\nu = rand(i * 1.7) * 2 - 1\nw = rand(i * 3.3 + 11) * 2 - 1\nm = sin((u * 2.681 + w * 5.047 + t) * 3.14159) * sin((u * 6.682 - w * 2.465 - t * 0.7) * 3.14159)\nx = u * 0.907 / aspect\ny = w * 0.875\nlum = max(0, m) * (0.3 + bass * 0.9) + 0.06\nred = lum * 0.3\ngreen = lum * 0.65\nblue = min(1, lum * 1.3)\nsize = 1 + abs(m) * 3.025\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:74: content: "name: \"Alien Heart\"\nmode: lines\nblend: additive\npersist: 0.897\nlinewidth: 1.95\n\n[init]\nn = 1015\n\n[frame]\nt = t + dt * (0.377 + bass_att * 1.5)\nhue = hue + dt * 0.038\n\n[point]\nring = floor(i * 29)\nri2 = frac(i * 29)\nz = frac(ring / 29 + t)\nrad = 0.05 + z * 0.917\na = ri2 * 6.28318 + ring * 0.423 + sin(t * 0.7) * 2\nx = sin(a) * rad * (0.55 + sv * 0.656) / aspect\ny = cos(a) * rad * (0.55 + sv * 0.656)\nred = (1 - z) * (0.3 + bass * 0.7) * abs(sin(z * 4.256))\ngreen = (1 - z) * (0.3 + bass * 0.7) * 0.22\nblue = (1 - z) * (0.3 + bass * 0.7) * abs(cos(z * 4.256))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:83: content: "name: \"Brainstorm\"\nmode: lines\nblend: additive\npersist: 0.859\nlinewidth: 2.309\n\n[init]\nsegs = 6\nn = 584\n\n[frame]\nrot = rot + dt * (0.093 + mid_att * 0.5)\nhue = hue + dt * 0.084\nflash = flash * 0.85\n\n[beat]\nflash = 1\n\n[point]\nseg = floor(i * segs)\nsi = frac(i * segs)\na0 = si * 6.28318 / segs + rot\namp = 0.1 + sv * 0.55 + bass * 0.25 + flash * 0.06\nrad = 0.15 + amp * (0.4 + 0.6 * sin(a0 * 9 + time * 2))\na = seg * 6.28318 / segs + a0 * if(below(seg % 2, 1), 1, -1)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + amp * 1.3 * 0.85\ngreen = 0.3 + amp * 1.3 * 0.92\nblue = 0.3 + amp * 1.3\nskip = if(above(si, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:92: content: "name: \"Molecules (S_KuPeRS Remix)\"\nmode: lines\nblend: additive\npersist: 0.88\nlinewidth: 1.388\n\n[init]\nn = 1119\n\n[frame]\nt = t + dt * (0.211 + bass_att * 1.8)\nhue = hue + dt * 0.042 + beat * 0.012\n\n[point]\narm = floor(i * 3)\nfa = frac(i * 3)\nd = fa\nang = arm * 1.551 + d * 1.047 * 3.14159 + t\nrad = (0.04 + pow(d, 1.714) * 1.15) * (0.7 + bass * 0.5)\nx = sin(ang) * rad / aspect\ny = cos(ang) * rad\nred = (0.3 + 0.7 * d) * (0.3 + mid) * abs(sin(d * 2.325))\ngreen = (0.3 + 0.7 * d) * (0.3 + mid) * 0.22\nblue = (0.3 + 0.7 * d) * (0.3 + mid) * abs(cos(d * 2.325))\nskip = if(below(fa, 0.04), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:101: content: "name: \"Take the Veil\"\nmode: lines\nblend: additive\npersist: 0.895\nlinewidth: 1.78\n\n[init]\nn = 674\n\n[frame]\nt = t + dt * 0.275\nhue = hue + dt * 0.052\n\n[point]\nph = i * 6.28318 * 1.521\nfa = 3 + mid * 0.35\nfb = 6 + bass * 0.45\nx = sin(ph * fa + t) * (0.5 + bass * 0.3) / aspect\ny = sin(ph * fb + t * 1.3 + 0.957) * (0.5 + treb * 0.35)\nred = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * (0.25 + bass * 0.95)\ngreen = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * (0.25 + mid * 0.95)\nblue = 0.3 + 0.45 * sin(ph * 2 + t) + abs(v) * 0.6 * (0.25 + treb * 0.95)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:110: content: "# Auto-ported from \"Nic01 - Rototronik.avs\" (Winamp AVS / Nic01)\n# SuperScope point program, 4 AVSTrans macros expanded.\nname: \"Rototronik\"\nauthor: \"Nic01\"\nmode: lines\nblend: additive\npersist: 0.88\nlinewidth: 2\nysign: -1\n\n[init]\npi=acos(-1);n=1000;\n\n[frame]\nrx=rx+rdx;ry=ry+rdy;rz=rz+rdz;xs=sin(rx);ys=sin(ry);zs=sin(rz);xc=cos(rx);yc=cos(ry);zc=cos(rz);t=t+0.1;p=0;p1=0.;\n\n[beat]\nrdx=(getosc(0,0,0)*500-250)%250/2500;rdy=(getosc(0.05,0,0)*500-250)%250/2500;rdz=(getosc(0.1,0,0)*500-250)%250/2500;\n\n[point]\np=p+1;\r\np1=if(equal(p%20,1),p1+1,p1);\r\ns=(1-equal(p%20,1));\r\ns1=1-s1;\r\nx1=sin(i*pi*4)*s*s1;\r\ny1=cos(i*pi*4)*s*s1;\r\nx1=x1+getosc((p1%25)*0.04,0,0)*x1;\r\ny1=y1+getosc((p1%25)*0.04,0,0)*y1;\r\nz1=-below(p,500)*0.5+0.25;\r\nc=(2-x1*x1-y1*y1);\r\n;\r\ny2=y1*xc-z1*xs;z2=y1*xs+z1*xc;\r\nx2=z2*ys+x1*yc;z1=z2*yc-x1*ys;\r\nx1=x2*zc-y2*zs;y1=y2*zc+x2*zs;\r\nx=x1/(2+z1);y=y1/(2+z1);\r\nred=c;\r\ngreen=1-c;\r\nc=equal(p,500)*10;\r\nred=red-c;green=green-c;\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:119: content: "name: \"...hidden track...\"\nmode: lines\nblend: additive\npersist: 0.805\nlinewidth: 2.555\n\n[init]\nn = 205\n\n[frame]\nhue = hue + dt * 0.045 + beat * 0.01\ntravel = travel + dt * (0.253 + bass_att * 1.4)\nflash = flash * 0.86\n\n[beat]\nflash = 1\n\n[point]\ng = floor(i * 5)\ngi = frac(i * 5)\nph = frac(rand(g * 5.1 + 1) + travel * (0.55 + rand(g + 17) * 0.85))\na = gi * 6.28318\nrad = ph * (0.232 + bass * 0.659 + flash * 0.08)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nfade = sin(ph * 3.14159)\nred = min(1, fade * (0.35 + flash * 0.4) * 1.3)\ngreen = fade * (0.35 + flash * 0.4) * 0.5\nblue = fade * (0.35 + flash * 0.4) * 0.12\nskip = if(above(ph, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:128: content: "# Arctic Rainbow -- re-imagined (v7.14) as a music-driven water spray.\n# Droplets launch from below the bottom edge, rise slowly, hang at the top,\n# arch left or right and fall back down, like water sprayed skyward. The\n# NUMBER of airborne drops follows the music's intensity: silence runs dry,\n# loud passages spray hard. Every droplet owns a hue that shifts on each\n# bass hit, and only falling drops grow a tapered RGB tail -- rising drops\n# stay crisp dots.\n#\n# Slot layout (mode lines): each drop owns S consecutive points --\n# slot 0 separator (always skipped; breaks the pen between drops)\n# slot 1 the head (a crisp dot while rising)\n# slots 2..S-1 trail samples reaching 0.014s..0.44s back along the arc\n# Trail samples draw only once the drop is falling (vy < 0), so the tail\n# fades in exactly as the arch turns downward.\nname: \"Arctic Rainbow\"\nmode: lines\nblend: additive\npersist: 0.12\nlinewidth: 2\n\n[init]\ndrops = 120\ntailn = 12\nS = tailn + 2\nn = drops * S\ndtT = 0.042\nacts = 0\n\n[frame]\n# music intensity -> how many drops are airborne (fast attack, slow release)\nvolish = min(1, max(vol_att, bass_att * 0.9) * 1.25)\nwant = clamp((volish - 0.06) / 0.5, 0, 1)\nrate = if(above(want, acts), 6, 1.2)\nacts = acts + (want - acts) * (1 - exp(-dt * rate))\nactn = floor(acts * drops + 0.001)\n# brightness rides the volume; every bass hit flashes the spray brighter\nflash = exp(-beatage * 7)\nbright = 0.62 + 0.38 * min(1, vol_att * 1.6) + flash * 0.3\n\n[point]\n# slot map through cell centers (dust-proof floor; v7.13.1 lesson)\nq = i * (n - 1) + 0.5\nd = floor(q / S)\nslot = floor(q - d * S)\n\n# stable per-drop character: apex height, flight time, hue, per-beat shift\nhbase = 1.26 + rand(d * 7.13 + 3) * 0.62\ntf = 1.9 + rand(d * 5.31 + 11) * 1.5\nhue0 = rand(d * 3.7 + 23)\nhsh = 0.09 + rand(d * 9.17 + 31) * 0.17\n\n# flight clock: period P per drop, phase-staggered; every new splash\n# re-rolls its origin, drift and arch from the cycle index\nP = tf * 1.18\nct = time + rand(d * 1.7 + 43) * P\ncyc = floor(ct / P)\na = ct - cyc * P\nxr = d * 12.77 + cyc * 17.31\nx0 = rand(xr + 1) * 2 - 1\ndrift = (rand(xr + 2) * 2 - 1) * 0.16\narch = (rand(xr + 3) * 2 - 1) * 0.55\n\n# projectile parabola: y(u) = -1.06 + 4*h*u*(1-u), apex h above the launch\nvy0 = 4 * hbase / tf\ngrav = 8 * hbase / (tf * tf)\n\n# this slot's sample age: the head is \"now\", trail slots reach back in time\nlag = if(above(slot, 1.5), 0.014 + (slot - 2) * dtT, 0)\naj = a - lag\nuj = aj / tf\nyj = -1.06 + 4 * hbase * uj * (1 - uj)\nxj = x0 + drift * uj + arch * uj * uj\n\n# music gate + dead window + off-screen cull\nskip = if(above(slot, 0.5), if(above(d, actn - 0.5), 1, 0), 1)\nskip = if(above(a, tf * 1.15), 1, skip)\nskip = if(below(aj, 0), 1, skip)\nskip = if(above(abs(xj), 1.05), 1, skip)\n\n# tail gate: 0 the whole way up, fading in as the fall accelerates\nvy = vy0 - grav * a\ntgate = smoothstep(0, 0.35, -vy / vy0)\n\n# per-drop hue, shifted by every bass hit; older trail samples drift back\nhue = hue0 + beats * hsh + time * 0.012 - (slot - 1) * 0.008\nred = hsvr(hue, 1, bright)\ngreen = hsvg(hue, 1, bright)\nblue = hsvb(hue, 1, bright)\n\ndsz = 1.6 + rand(d * 2.9 + 51) * 1.1 + bass_att * 1.4\nu = (slot - 2) / tailn\nif(above(slot, 1.5),\n if(above(slot, 2.5),\n (alpha = tgate * pow(1 - u, 1.5) * 0.85;\n size = dsz * (1 - 0.72 * u);\n skip = if(below(tgate, 0.03), 1, skip)),\n (alpha = max(1 - tgate, tgate * 0.85); size = dsz)),\n (alpha = 1; size = dsz))\nx = xj\ny = yj\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:137: content: "name: \"Chinook\"\nmode: dots\nblend: additive\npersist: 0.831\nlinewidth: 2.299\n\n[init]\nbars = 30\nn = bars * 9\n\n[frame]\nrot = rot + dt * (0.07 + mid * 0.3)\nhue = hue + dt * 0.106\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.893\na = bar * 6.28318 / bars + rot\nrad = 0.142 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.25 + bi * 0.75 * 0.3\ngreen = 0.25 + bi * 0.75 * 0.65\nblue = min(1, 0.25 + bi * 0.75 * 1.3)\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:146: content: "name: \"Hexual Healing\"\nmode: dots\nblend: additive\npersist: 0.785\nlinewidth: 2.432\n\n[init]\ncols = 34\nn = cols * cols\n\n[frame]\nrot = rot + dt * (0.072 + mid * 0.4)\nhue = hue + dt * 0.062\n\n[point]\ncx = floor(i * cols) / (cols - 1)\ncy = frac(i * cols)\nh = sv * 0.506\nux = (cx - 0.5) * 1.674\nuy = (cy - 0.5) * 1.674\nrx = ux * cos(rot) - uy * sin(rot)\nry = ux * sin(rot) + uy * cos(rot)\nx = (rx / aspect) * (1 - h * 0.7)\ny = ry * (1 - h * 0.7)\nred = min(1, 0.22 + h * 2.2 * 1.3)\ngreen = 0.22 + h * 2.2 * 0.5\nblue = 0.22 + h * 2.2 * 0.12\nsize = 1.2 + h * 5\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:155: content: "name: \"Inverse Kinetics\"\nmode: dots\nblend: additive\npersist: 0.805\nlinewidth: 2.613\n\n[init]\nn = 817\n\n[frame]\ntt = tt + dt * (0.5 + bass_att * 1.1)\nhue = hue + dt * 0.103\nburst = burst * 0.9\n\n[beat]\nburst = 1\n\n[point]\njet = floor(i * 2)\nlife = frac(rand(i * 7.7 + jet) + tt * (0.35 + rand(i + 3) * 0.65))\na = jet * 6.28318 / 2 + rand(i * 5.1 + jet) * 0.736\nspd = 0.4 + rand(i * 9.2 + jet) * 0.8\npx = cos(a) * spd * life\npy = sin(a) * spd * life - 1.2 * life * life\nx = px * (0.85 + bass * 0.35) / aspect\ny = py\nred = max(0, 1 - life) * (0.35 + burst * 0.55) * abs(sin(life * 4))\ngreen = max(0, 1 - life) * (0.35 + burst * 0.55) * 0.22\nblue = max(0, 1 - life) * (0.35 + burst * 0.55) * abs(cos(life * 4))\nskip = if(above(life, 0.94), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:164: content: "name: \"Kingish\"\nmode: dots\nblend: additive\npersist: 0.813\nlinewidth: 2.025\n\n[init]\nspokes = 27\nn = spokes * 22\n\n[frame]\nrot = rot + dt * (0.102 + mid * 0.4)\nt = t + dt * 2.987\nhue = hue + dt * 0.075\n\n[point]\nsp = floor(i * spokes)\nsi = frac(i * spokes)\na = sp * 6.28318 / spokes + rot\nwave = sin(si * 2 * 3.14159 - t) * (0.03 + bass * 0.28)\nrad = 0.12 + si * 0.92 + wave\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = (1 - si) * 0.45 + 0.15 + sv * 0.55 * abs(sin(sp * 0.4))\ngreen = (1 - si) * 0.45 + 0.15 + sv * 0.55 * 0.22\nblue = (1 - si) * 0.45 + 0.15 + sv * 0.55 * abs(cos(sp * 0.4))\nskip = if(above(si, 0.985), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:173: content: "name: \"Spirit Realm (Degnic's Plasmoid RMX)\"\nmode: lines\nblend: additive\npersist: 0.885\nlinewidth: 2.389\n\n[init]\nn = 1199\n\n[frame]\nt = t + dt * (0.344 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.085\n\n[point]\na = i * 6.28318 * 2\nwob = sin(a * 3 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.422 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5))\ngreen = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5 + 2.09))\nblue = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5 + 4.19))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:182: content: "# Auto-ported from \"S_KuPeRS - Texering 002.avs\" (Winamp AVS / S_KuPeRS)\n# SuperScope point program, 4 AVSTrans macros expanded.\nname: \"Texering 002\"\nauthor: \"S_KuPeRS\"\nmode: dots\nblend: additive\npersist: 0.78\nlinewidth: 3\nysign: -1\n\n[init]\nn=100;pi=acos(-1);rx=1.57;ry=1.57;rx=0;ry=0;rz=0;rxo=0;ryo=0;rzo=0;rxt=0;ryt=0;rzt=0;\n\n[frame]\nredf=redf+redr;greenf=greenf+greenr;bluef=bluef+bluer;rx=rx+rxo;ry=ry+ryo;rz=rz+rzo;rzo=rzo*0.97;cx=cos(sin(rx));sx=sin(sin(rx));cy=cos(sin(ry));sy=sin(sin(ry));cz=cos(rz);sz=sin(rz);\n\n[beat]\nredr=rnd(10)/100-0.05;greenr=rnd(10)/100-0.05;bluer=rnd(10)/100-0.05;rxo=getosc(0.5,0.02,0)/12;ryo=getosc(0.3,0.02,0)/12;rzo=getosc(0.7,0.02,0)/8;\n\n[point]\nr=i*pi*2;r2=i*pi*99;\r\nx1=sin(r-bluef*1.53+.0776)*cos(r2+greenf);\r\ny1=cos(r+bluef);\r\nz1=sin(r2+redf);\r\n\r\nx1d=x1*cz-y1*sz;\r\ny1d=x1*sz+y1*cz;\r\ny2d=y1d*cx-z1*sx;\r\nz2d=y1d*sx+z1*cx;\r\nx3d=x1d*cy-z2d*sy;\r\nz3d=x1d*sy+z2d*cy;\r\nzi=1/(z3d+3);\r\nx=if(above(z3d+3,0.1),x3d*zi,x);\r\ny=if(above(z3d+3,0.1),y2d*zi,y);\r\n\r\nalpha=if(below(z3d+2.4,0),0,1);\r\nred=alpha*(1+sin(redf)/4-z3d/4)/7;\r\nblue=alpha*(1+sin(bluef)/4-z3d)/20;\r\ngreen=alpha*(1+sin(greenf)/3-z3d/2)/12;\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:191: content: "name: \"Upward Current\"\nmode: lines\nblend: additive\npersist: 0.914\nlinewidth: 1.629\n\n[init]\nn = 869\n\n[frame]\nt = t + dt * (0.134 + mid * 0.5)\nhue = hue + dt * 0.122\nflash = flash * 0.87\n\n[beat]\nflash = 1\n\n[point]\nth = i * 6.28318 * 2 + t\nr = abs(cos(2 * th + bass * 0.656))\nrad = r * (0.5 + bass * 0.3 + sv * 0.2 + flash * 0.08)\nx = sin(th) * rad / aspect\ny = cos(th) * rad\nred = 0.25 + 0.65 * r + v * 0.25 * abs(sin(th * 0.5))\ngreen = 0.25 + 0.65 * r + v * 0.25 * 0.22\nblue = 0.25 + 0.65 * r + v * 0.25 * abs(cos(th * 0.5))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:200: content: "name: \"Aqua-fumes\"\nmode: dots\nblend: additive\npersist: 0.787\nlinewidth: 2.043\n\n[init]\nn = 966\n\n[frame]\ntravel = travel + dt * (0.347 + vol_att * 1.816)\nhue = hue + dt * 0.076\n\n[point]\na = rand(i * 7.3) * 6.28318\nz = frac(rand(i * 3.1 + 5) + travel * (0.5 + rand(i + 9) * 0.7))\nrad = z * z * 1.075\nx = sin(a) * rad / aspect\ny = cos(a) * rad\ntw = 0.4 + 0.6 * sin(z * 40 + time * 3) * (0.5 + treb)\nred = tw * abs(sin(i * 3.959))\ngreen = tw * 0.22\nblue = tw * abs(cos(i * 3.959))\nsize = 1 + z * 3 * (0.5 + bass)\nskip = if(above(z, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:209: content: "name: \"Club Seizure (color enhanced mix)\"\nmode: lines\nblend: additive\npersist: 0.864\nlinewidth: 2.379\n\n[init]\nn = 946\n\n[frame]\nt = t + dt * (0.322 + bass_att * 0.9)\nhue = hue + dt * 0.089\nflash = flash * 0.86\n\n[beat]\nflash = 1\n\n[point]\nst = floor(i * 2)\nsi = frac(i * 2)\ns = si * 6 * 6.28318 + t\nph = st * 3.14159\nrad = (0.28 + bass * 0.32 + flash * 0.06) * (0.55 + 0.45 * (cos(s + ph) * 0.5 + 0.5))\nx = sin(s + ph) * rad / aspect\ny = (si - 0.5) * 1.8\nred = 0.25 + 0.55 * (cos(s + ph) * 0.5 + 0.5) + treb * 0.25 * (0.45 + 0.55 * sin(hue * 6.28318 + s * 0.3))\ngreen = 0.25 + 0.55 * (cos(s + ph) * 0.5 + 0.5) + treb * 0.25 * (0.45 + 0.55 * sin(hue * 6.28318 + s * 0.3 + 2.09))\nblue = 0.25 + 0.55 * (cos(s + ph) * 0.5 + 0.5) + treb * 0.25 * (0.45 + 0.55 * sin(hue * 6.28318 + s * 0.3 + 4.19))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:218: content: "name: \"Electro blobs\"\nmode: lines\nblend: additive\npersist: 0.866\nlinewidth: 1.536\n\n[init]\nsegs = 12\nn = 616\n\n[frame]\nrot = rot + dt * (0.085 + mid_att * 0.5)\nhue = hue + dt * 0.131\nflash = flash * 0.85\n\n[beat]\nflash = 1\n\n[point]\nseg = floor(i * segs)\nsi = frac(i * segs)\na0 = si * 6.28318 / segs + rot\namp = 0.1 + sv * 0.55 + bass * 0.25 + flash * 0.06\nrad = 0.15 + amp * (0.4 + 0.6 * sin(a0 * 5 + time * 2))\na = seg * 6.28318 / segs + a0 * if(below(seg % 2, 1), 1, -1)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + amp * 1.3 * 0.85\ngreen = 0.3 + amp * 1.3 * 0.92\nblue = 0.3 + amp * 1.3\nskip = if(above(si, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:227: content: "name: \"Kaleidofied\"\nmode: lines\nblend: additive\npersist: 0.885\nlinewidth: 1.542\n\n[init]\nn = 1126\n\n[frame]\nt = t + dt * (0.589 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.1\n\n[point]\na = i * 6.28318 * 1\nwob = sin(a * 3 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.232 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5))\ngreen = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5 + 2.09))\nblue = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5 + 4.19))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:236: content: "name: \"Magma Flow II\"\nmode: dots\nblend: additive\npersist: 0.804\nlinewidth: 2.633\n\n[init]\nrings = 3\nn = rings * 104\n\n[frame]\nt = t + dt * (0.258 + bass_att * 0.6)\nhue = hue + dt * 0.036\nsquash = 0.387 + 0.25 * sin(t * 0.203)\n\n[point]\nring = floor(i * rings)\nri3 = frac(i * rings)\nr0 = 0.16 + ring * 0.148\na = ri3 * 6.28318 + t * (1.2 - ring * 0.18) + ring * 2.4\nx = sin(a) * r0 * (1 + bass * 0.18) / aspect\ny = cos(a) * r0 * squash\nsat = frac(ri3 * 5)\nsize = if(below(sat, 0.14), 3 + bass * 3, 1)\nred = 0.25 + bass * 0.5 + ring * 0.07 * abs(sin(ring * 1.3))\ngreen = 0.25 + bass * 0.5 + ring * 0.07 * 0.22\nblue = 0.25 + bass * 0.5 + ring * 0.07 * abs(cos(ring * 1.3))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:245: content: "name: \"Multiple Orgasms\"\nmode: lines\nblend: additive\npersist: 0.873\nlinewidth: 1.6\n\n[init]\nspokes = 30\nn = spokes * 33\n\n[frame]\nrot = rot + dt * (0.106 + mid * 0.4)\nt = t + dt * 2.164\nhue = hue + dt * 0.106\n\n[point]\nsp = floor(i * spokes)\nsi = frac(i * spokes)\na = sp * 6.28318 / spokes + rot\nwave = sin(si * 4 * 3.14159 - t) * (0.03 + bass * 0.28)\nrad = 0.12 + si * 0.919 + wave\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = (1 - si) * 0.45 + 0.15 + sv * 0.55 * (0.45 + 0.55 * sin(hue * 6.28318 + sp * 0.4))\ngreen = (1 - si) * 0.45 + 0.15 + sv * 0.55 * (0.45 + 0.55 * sin(hue * 6.28318 + sp * 0.4 + 2.09))\nblue = (1 - si) * 0.45 + 0.15 + sv * 0.55 * (0.45 + 0.55 * sin(hue * 6.28318 + sp * 0.4 + 4.19))\nskip = if(above(si, 0.985), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:254: content: "name: \"Pina Colada\"\nmode: lines\nblend: additive\npersist: 0.887\nlinewidth: 1.779\n\n[init]\nn = 943\n\n[frame]\nt = t + dt * (0.219 + bass_att * 1.8)\nhue = hue + dt * 0.098 + beat * 0.012\n\n[point]\narm = floor(i * 8)\nfa = frac(i * 8)\nd = fa\nang = arm * 1.519 + d * 1.263 * 3.14159 + t\nrad = (0.04 + pow(d, 2.354) * 1.15) * (0.7 + bass * 0.5)\nx = sin(ang) * rad / aspect\ny = cos(ang) * rad\nred = (0.3 + 0.7 * d) * (0.3 + mid) * (0.25 + bass * 0.95)\ngreen = (0.3 + 0.7 * d) * (0.3 + mid) * (0.25 + mid * 0.95)\nblue = (0.3 + 0.7 * d) * (0.3 + mid) * (0.25 + treb * 0.95)\nskip = if(below(fa, 0.04), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:263: content: "name: \"Scope in Spotlight II\"\nmode: lines\nblend: additive\npersist: 0.854\nlinewidth: 2.056\n\n[init]\nsegs = 7\nn = 462\n\n[frame]\nrot = rot + dt * (0.107 + mid_att * 0.5)\nhue = hue + dt * 0.035\nflash = flash * 0.85\n\n[beat]\nflash = 1\n\n[point]\nseg = floor(i * segs)\nsi = frac(i * segs)\na0 = si * 6.28318 / segs + rot\namp = 0.1 + sv * 0.55 + bass * 0.25 + flash * 0.06\nrad = 0.15 + amp * (0.4 + 0.6 * sin(a0 * 4 + time * 2))\na = seg * 6.28318 / segs + a0 * if(below(seg % 2, 1), 1, -1)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = min(1, 0.3 + amp * 1.3 * 1.3)\ngreen = 0.3 + amp * 1.3 * 0.5\nblue = 0.3 + amp * 1.3 * 0.12\nskip = if(above(si, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:272: content: "name: \"Solero Shots\"\nmode: lines\nblend: additive\npersist: 0.878\nlinewidth: 2.226\n\n[init]\nbars = 40\nn = bars * 12\n\n[frame]\nrot = rot + dt * (0.078 + mid * 0.3)\nhue = hue + dt * 0.032\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.813\na = bar * 6.28318 / bars + rot\nrad = 0.218 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.25 + bi * 0.75 * 0.3\ngreen = 0.25 + bi * 0.75 * 0.65\nblue = min(1, 0.25 + bi * 0.75 * 1.3)\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:281: content: "name: \"Square Minded\"\nmode: dots\nblend: additive\npersist: 0.783\nlinewidth: 2.696\n\n[init]\nn = 1492\n\n[frame]\nt = t + dt * 0.656\nhue = hue + dt * 0.13\n\n[point]\nu = rand(i * 1.7) * 2 - 1\nw = rand(i * 3.3 + 11) * 2 - 1\nm = sin((u * 3.356 + w * 3.959 + t) * 3.14159) * sin((u * 3.01 - w * 6.626 - t * 0.7) * 3.14159)\nx = u * 0.994 / aspect\ny = w * 0.856\nlum = max(0, m) * (0.3 + bass * 0.9) + 0.06\nred = lum * 0.85\ngreen = lum * 0.92\nblue = lum\nsize = 1 + abs(m) * 3.211\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:290: content: "name: \"Worm-O-Rama (Raz Remix)\"\nmode: lines\nblend: additive\npersist: 0.894\nlinewidth: 1.933\n\n[init]\nn = 1189\n\n[frame]\nt = t + dt * (0.418 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.102\n\n[point]\na = i * 6.28318 * 3\nwob = sin(a * 3 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.282 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + abs(v) * 1.2 * (0.25 + bass * 0.95)\ngreen = 0.3 + abs(v) * 1.2 * (0.25 + mid * 0.95)\nblue = 0.3 + abs(v) * 1.2 * (0.25 + treb * 0.95)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:299: content: "# Auto-ported from \"UnConeD - Zero-G Maze.avs\" (Winamp AVS / UnConeD)\n# SuperScope point program, 4 AVSTrans macros expanded.\nname: \"Zero-G Maze\"\nauthor: \"UnConeD\"\nmode: lines\nblend: additive\npersist: 0.88\nlinewidth: 2\nysign: -1\n\n[init]\nn=50;ro=0;go=2.0;bo=4.0\n\n[frame]\nt=t-0.05;aa=aa*0.7;\n\n[beat]\naa=0.0;ro=rnd(100)/100*6.28;go=rnd(100)/100*6.28;bo=rnd(100)/100*6.28\n\n[point]\ny=0;x=i*.5-.1;\r\nred=sin(t+ro+i*2)*.5+.5;\r\ngreen=sin(t+go+i*2)*.5+.5;\r\nblue=sin(t+bo+i*2)*.5+.5;\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:308: content: "name: \"Cartoon Trip\"\nmode: lines\nblend: additive\npersist: 0.831\nlinewidth: 2.55\n\n[init]\nbars = 39\nn = bars * 9\n\n[frame]\nrot = rot + dt * (0.116 + mid * 0.3)\nhue = hue + dt * 0.112\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.83\na = bar * 6.28318 / bars + rot\nrad = 0.189 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.25 + bi * 0.75 * 0.85\ngreen = 0.25 + bi * 0.75 * 0.92\nblue = 0.25 + bi * 0.75\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:317: content: "name: \"Containment\"\nmode: lines\nblend: additive\npersist: 0.935\nlinewidth: 1.8\n\n[init]\nn = 847\n\n[frame]\nt = t + dt * (0.436 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.071\n\n[point]\na = i * 6.28318 * 2\nwob = sin(a * 2 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.25 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = min(1, 0.3 + abs(v) * 1.2 * 1.3)\ngreen = 0.3 + abs(v) * 1.2 * 0.5\nblue = 0.3 + abs(v) * 1.2 * 0.12\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:326: content: "# Auto-ported from \"UnConeD - Cubic Flower.avs\" (Winamp AVS / UnConeD)\n# SuperScope point program, 4 AVSTrans macros expanded.\nname: \"Cubic Flower\"\nauthor: \"UnConeD\"\nmode: lines\nblend: additive\npersist: 0.88\nlinewidth: 2\nysign: -1\n\n[init]\nn=40;ro=0;go=2.0;bo=4.0\n\n[frame]\nt=t-0.05;aa=aa*0.7;\n\n[beat]\naa=1;ro=rnd(100)/100*6.28;go=rnd(100)/100*6.28;bo=rnd(100)/100*6.28\n\n[point]\nx=i*.8-.4;y=0;\r\nred=sin(t+ro+i*2)/2+.5+aa;\r\ngreen=sin(t+go+i*2)/2+.5+aa;\r\nblue=sin(t+bo+i*2)/2+.5+aa;\r\nblue=blue+1-min(red+green+blue,1)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:335: content: "name: \"Jello Cube\"\nmode: lines\nblend: additive\npersist: 0.813\nlinewidth: 2.201\n\n[init]\nn = 620\n\n[frame]\nhue = hue + dt * 0.073 + beat * 0.01\ntravel = travel + dt * (0.196 + bass_att * 1.4)\nflash = flash * 0.86\n\n[beat]\nflash = 1\n\n[point]\ng = floor(i * 10)\ngi = frac(i * 10)\nph = frac(rand(g * 5.1 + 1) + travel * (0.55 + rand(g + 17) * 0.85))\na = gi * 6.28318\nrad = ph * (0.226 + bass * 0.743 + flash * 0.08)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nfade = sin(ph * 3.14159)\nred = fade * (0.35 + flash * 0.4) * abs(sin(g * 0.7))\ngreen = fade * (0.35 + flash * 0.4) * 0.22\nblue = fade * (0.35 + flash * 0.4) * abs(cos(g * 0.7))\nskip = if(above(ph, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:344: content: "name: \"Mercury\"\nmode: lines\nblend: additive\npersist: 0.888\nlinewidth: 1.97\n\n[init]\nn = 1109\n\n[frame]\nt = t + dt * (0.329 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.097\n\n[point]\na = i * 6.28318 * 3\nwob = sin(a * 6 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.31 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + abs(v) * 1.2 * 0.3\ngreen = 0.3 + abs(v) * 1.2 * 0.65\nblue = min(1, 0.3 + abs(v) * 1.2 * 1.3)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:353: content: "name: \"Neon Coaster\"\nmode: dots\nblend: additive\npersist: 0.897\nlinewidth: 2.488\n\n[init]\nbars = 33\nn = bars * 12\n\n[frame]\nrot = rot + dt * (0.092 + mid * 0.3)\nhue = hue + dt * 0.066\n\n[point]\nbar = floor(i * bars)\nbi = frac(i * bars)\nlvl = getspec(bar / bars, 0, 0)\nh = lvl * 0.765\na = bar * 6.28318 / bars + rot\nrad = 0.193 + bi * h\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = min(1, 0.25 + bi * 0.75 * 1.3)\ngreen = 0.25 + bi * 0.75 * 0.5\nblue = 0.25 + bi * 0.75 * 0.12\nskip = if(above(bi, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:362: content: "name: \"Plankton\"\nmode: dots\nblend: additive\npersist: 0.83\nlinewidth: 2.37\n\n[init]\nn = 627\n\n[frame]\nhue = hue + dt * 0.033 + beat * 0.01\ntravel = travel + dt * (0.435 + bass_att * 1.4)\nflash = flash * 0.86\n\n[beat]\nflash = 1\n\n[point]\ng = floor(i * 11)\ngi = frac(i * 11)\nph = frac(rand(g * 5.1 + 1) + travel * (0.55 + rand(g + 17) * 0.85))\na = gi * 6.28318\nrad = ph * (0.194 + bass * 0.352 + flash * 0.08)\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nfade = sin(ph * 3.14159)\nred = min(1, fade * (0.35 + flash * 0.4) * 1.3)\ngreen = fade * (0.35 + flash * 0.4) * 0.5\nblue = fade * (0.35 + flash * 0.4) * 0.12\nskip = if(above(ph, 0.96), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:371: content: "name: \"Reflectocube\"\nmode: lines\nblend: additive\npersist: 0.91\nlinewidth: 1.419\n\n[init]\nn = 1235\n\n[frame]\nt = t + dt * (0.31 + bass_att * 1.8)\nhue = hue + dt * 0.065 + beat * 0.012\n\n[point]\narm = floor(i * 4)\nfa = frac(i * 4)\nd = fa\nang = arm * 1.405 + d * 0.906 * 3.14159 + t\nrad = (0.04 + pow(d, 1.825) * 1.15) * (0.7 + bass * 0.5)\nx = sin(ang) * rad / aspect\ny = cos(ang) * rad\nred = (0.3 + 0.7 * d) * (0.3 + mid) * (0.45 + 0.55 * sin(hue * 6.28318 + d * 4.537))\ngreen = (0.3 + 0.7 * d) * (0.3 + mid) * (0.45 + 0.55 * sin(hue * 6.28318 + d * 4.537 + 2.09))\nblue = (0.3 + 0.7 * d) * (0.3 + mid) * (0.45 + 0.55 * sin(hue * 6.28318 + d * 4.537 + 4.19))\nskip = if(below(fa, 0.04), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:380: content: "name: \"Speeder 3K\"\nmode: dots\nblend: additive\npersist: 0.831\nlinewidth: 2.272\n\n[init]\nn = 949\n\n[frame]\ntravel = travel + dt * (0.156 + vol_att * 1.231)\nhue = hue + dt * 0.04\n\n[point]\na = rand(i * 7.3) * 6.28318\nz = frac(rand(i * 3.1 + 5) + travel * (0.5 + rand(i + 9) * 0.7))\nrad = z * z * 1.206\nx = sin(a) * rad / aspect\ny = cos(a) * rad\ntw = 0.4 + 0.6 * sin(z * 40 + time * 3) * (0.5 + treb)\nred = min(1, tw * 1.3)\ngreen = tw * 0.5\nblue = tw * 0.12\nsize = 1 + z * 3 * (0.5 + bass)\nskip = if(above(z, 0.97), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:389: content: "name: \"TC Plasma\"\nmode: lines\nblend: additive\npersist: 0.932\nlinewidth: 1.976\n\n[init]\nn = 1072\n\n[frame]\nt = t + dt * (0.432 + bass_att * 0.8)\nsway = sway + dt * (0.5 + treb)\nhue = hue + dt * 0.076\n\n[point]\na = i * 6.28318 * 3\nwob = sin(a * 4 + t * 2) * (0.08 + treb * 0.3)\nrad = (0.42 + mid * 0.25) * (0.85 + 0.15 * sin(a * 3 + sway)) + v * 0.223 - wob\nx = sin(a) * rad / aspect\ny = cos(a) * rad\nred = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5))\ngreen = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5 + 2.09))\nblue = 0.3 + abs(v) * 1.2 * (0.45 + 0.55 * sin(hue * 6.28318 + a * 0.5 + 4.19))\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:398: content: "name: \"Tie Tunnel SSC\"\nmode: lines\nblend: additive\npersist: 0.851\nlinewidth: 2.021\n\n[init]\nn = 1179\n\n[frame]\nt = t + dt * (0.17 + bass_att * 0.9)\nhue = hue + dt * 0.129\nflash = flash * 0.86\n\n[beat]\nflash = 1\n\n[point]\nst = floor(i * 2)\nsi = frac(i * 2)\ns = si * 6 * 6.28318 + t\nph = st * 3.14159\nrad = (0.28 + bass * 0.32 + flash * 0.06) * (0.55 + 0.45 * (cos(s + ph) * 0.5 + 0.5))\nx = sin(s + ph) * rad / aspect\ny = (si - 0.5) * 1.8\nred = min(1, 0.25 + 0.55 * (cos(s + ph) * 0.5 + 0.5) + treb * 0.25 * 1.3)\ngreen = 0.25 + 0.55 * (cos(s + ph) * 0.5 + 0.5) + treb * 0.25 * 0.5\nblue = 0.25 + 0.55 * (cos(s + ph) * 0.5 + 0.5) + treb * 0.25 * 0.12\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:407: content: "name: \"Zero-G Maze II\"\nmode: lines\nblend: additive\npersist: 0.916\nlinewidth: 1.457\n\n[init]\nn = 1049\n\n[frame]\nt = t + dt * (0.267 + bass_att * 1.8)\nhue = hue + dt * 0.038 + beat * 0.012\n\n[point]\narm = floor(i * 7)\nfa = frac(i * 7)\nd = fa\nang = arm * 1.253 + d * 0.88 * 3.14159 + t\nrad = (0.04 + pow(d, 2.401) * 1.15) * (0.7 + bass * 0.5)\nx = sin(ang) * rad / aspect\ny = cos(ang) * rad\nred = (0.3 + 0.7 * d) * (0.3 + mid) * (0.45 + 0.55 * sin(hue * 6.28318 + d * 2.064))\ngreen = (0.3 + 0.7 * d) * (0.3 + mid) * (0.45 + 0.55 * sin(hue * 6.28318 + d * 2.064 + 2.09))\nblue = (0.3 + 0.7 * d) * (0.3 + mid) * (0.45 + 0.55 * sin(hue * 6.28318 + d * 2.064 + 4.19))\nskip = if(below(fa, 0.04), 1, 0)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:416: content: "name: \"UnConeD -Zero-G Maze III\"\nmode: lines\nblend: additive\npersist: 0.853\nlinewidth: 1.507\n\n[init]\nn = 722\n\n[frame]\nt = t + dt * (0.243 + bass_att * 1.5)\nhue = hue + dt * 0.093\n\n[point]\nring = floor(i * 19)\nri2 = frac(i * 19)\nz = frac(ring / 19 + t)\nrad = 0.05 + z * 0.881\na = ri2 * 6.28318 + ring * 0.16 + sin(t * 0.7) * 2\nx = sin(a) * rad * (0.55 + sv * 0.901) / aspect\ny = cos(a) * rad * (0.55 + sv * 0.901)\nred = (1 - z) * (0.3 + bass * 0.7) * 0.3\ngreen = (1 - z) * (0.3 + bass * 0.7) * 0.65\nblue = min(1, (1 - z) * (0.3 + bass * 0.7) * 1.3)\n", +/home/z/my-project/src/lib/ava/embedded-presets.ts:425: content: "name: \"nebulous (skupers remix)\"\nmode: dots\nblend: additive\npersist: 0.833\nlinewidth: 2.862\n\n[init]\ncols = 28\nn = cols * cols\n\n[frame]\nrot = rot + dt * (0.104 + mid * 0.4)\nhue = hue + dt * 0.08\n\n[point]\ncx = floor(i * cols) / (cols - 1)\ncy = frac(i * cols)\nh = sv * 0.235\nux = (cx - 0.5) * 1.448\nuy = (cy - 0.5) * 1.448\nrx = ux * cos(rot) - uy * sin(rot)\nry = ux * sin(rot) + uy * cos(rot)\nx = (rx / aspect) * (1 - h * 0.7)\ny = ry * (1 - h * 0.7)\nred = 0.22 + h * 2.2 * (0.45 + 0.55 * sin(hue * 6.28318 + cx * 3.774))\ngreen = 0.22 + h * 2.2 * (0.45 + 0.55 * sin(hue * 6.28318 + cx * 3.774 + 2.09))\nblue = 0.22 + h * 2.2 * (0.45 + 0.55 * sin(hue * 6.28318 + cx * 3.774 + 4.19))\nsize = 1.2 + h * 5\n", + +[Showing results with pagination = limit: 60] \ No newline at end of file diff --git a/worklog.md b/worklog.md index f8bdeb2..2d70297 100755 --- a/worklog.md +++ b/worklog.md @@ -2428,3 +2428,41 @@ BROWSER E2E (agent-browser, ALL PASS): Stage Summary: - v7.14.1 shipped: the script engine grew a real composite family (multiply, screen, subtract, replace) and a true zero-fade framebuffer (persist 1 skips the fade pass). The pairing the user asked for -- blend replace + persist 1 + bgzoom/bgrot feedback -- now renders a static-speed blow-out that never fades: colors ride outward at full brightness and the fresh drawing replaces the old color at the center. All existing presets keep their exact behavior (regression-verified headlessly and in-browser); the updated Brainstorm script was delivered to the user for VPS testing. + +--- +Task ID: 44 +Agent: main (Z.ai Code) +Task: v7.15 (user request, blend engine session 4): "Since you added additive, multiply, subtract, and replace -- let's go ahead and complete the list of all possible color blending modes." The user supplied the full compositing catalog (Normal through Plus Darker/Plus Lighter, ~36 named entries incl. the AE stencil/silhouette family and the GIMP grain pair) and set the version target: 7.15. + +DESIGN (41 keywords, two implementations): +- New registry src/lib/ava/blend.ts: 41 canonical keywords + 15 aliases, matched case/ and separator-insensitively (Color Burn = color-burn = COLORBURN). Two paths per mode: 'native' (a direct Canvas2D composite op -- Canvas2D implements the W3C compositing formulas) or 'gpu' (the 21 modes Canvas2D has no operator for, run through a new WebGL compositor, src/lib/ava/blend-gpu.ts: the stroke passes draw onto a scratch canvas, one fullscreen shader pass computes per-pixel blend(backdrop, stroke) weighted by the stroke's coverage, the result replaces the live canvas with composite 'copy'). WebGL-less browsers fall back per mode to the nearest native operator. +- Formula research (agent-browser, 4 independent sources): phoenix = min - max + 1 (glsl-blend phoenix.glsl verbatim, SO Q5919663, chikuyonok, kevinports); hard mix = vivid light thresholded at 0.5 (2/2 code sources); W3C soft-light D(x) helper confirmed from the spec. Notable documented equivalence: negation (Pegtop, "softer Difference") and phoenix ("combines Darken and Lighten") are the same curve 1-|a-b| -- kept as two keywords because apps list both names. +- 'subtract' upgraded from 7.14.1's difference approximation to a TRUE clamped subtract (gpu/9); 'replace' keeps its v7.14.1 semantics (source-over, core pass at FULL alpha). +- The framebuffer went alpha-capable so behind (destination-over) and clear work honestly: the persistence fade is now an alpha ERASE (destination-out) and the bg* wipe a clearRect -- over the black stage both read pixel-identically to the old opaque fills (verified: the fade decays to displayed 0.91/255 with zero pixels above alpha 16), so every existing preset renders as before. +- The blend variable can switch modes per frame (same contract as persist): the expression language is numeric-only (Env = Record), so it carries the mode's 1-based registry number; the Help table lists every number next to its keyword. Unknown values fall back to the header keyword. The two-pass glow tuning moved into GAINS_STD / GAINS_REPLACE so the native and gpu paths share one drawContent(). + +Work Log: +- blend.ts NEW: BLEND_SPECS (41), BLEND_INDEX, findBlend/normalizeBlendName, blendIndex/blendByIndex, BLEND_GROUP_LABELS; every spec carries op/fullAlphaCore/gpuId/fallbackOp/group/note. +- blend-gpu.ts NEW: BlendCompositor (WebGL1, premultiplied uploads, preserveDrawingBuffer, y-flipped vUV); FRAG_SRC implements modes 1-21 with the standard coverage-weighted tail out = mix(a, modeRGB, c) at opacity mix(dst.a, 1, c), special tails for dissolve (stochastic full-intensity speckle) and the four stencil/silhouette masks (backdrop scaled by the stroke's luma/alpha mask). +- engine.ts: alpha-capable canvas (no {alpha:false}, no black fills anywhere), destination-out fade, clearRect bg wipe, draw section rewritten to registry routing (native direct / gpu scratch+compositor with try/catch latch gpuBroken), drawContent() extracted (target-agnostic), env.blend reset per frame, scratchBuffer()/gpuEnsure() lazy lifecycles. +- script.ts: BLENDS set replaced by findBlend; meta stores the CANONICAL key; error message points at the Help table. types.ts: BlendMode = string (registry-validated). help-panel.tsx: blend var row + a grouped 41-row numbered Blend modes table (7 groups) + .ava example updated. +- version.ts: APP_VERSION 7.15.0 + full history entry. release-notes.ts: 7.15.0 "The complete blend mode collection" (3 added + 1 improved, first-person voice). Library untouched (EMBEDDED_SEED_VERSION stays 7.14; all 106 presets keep additive/alpha). + +HEADLESS VALIDATION (/home/z/tmp-validate/blend41/validate.mts, REAL parser + registry, 17/17 PASS): +- All 106 embedded presets still compile; library blend values unchanged (additive family only). +- All 41 canonical keywords accepted + canonicalized; 73 human spellings resolve (Color Burn -> colorburn, plus-lighter -> additive, plus-darker -> linearburn, Subtractive -> subtract, Destination Over -> behind, Stencil Luma -> stencil ...); 8 invalid keywords rejected with the new error. +- blendByIndex inverts the registry order 1..41; key numbers normal=1 additive=2 replace=3 subtract=6 colorburn=10; out-of-range rejected. +- Routing: subtract is gpu/9, replace keeps fullAlphaCore, normal/alpha -> source-over, behind -> destination-over, clear -> clear; phoenix gpu/15, negation gpu/12. +- Alias map: all 56 keys+aliases resolve, zero collisions. + +BROWSER E2E (agent-browser, ALL PASS; pixel analysis via in-page getImageData on the live canvas): +- Fresh load: title "OVE -- Open Visualization Engine (v7.15.0)"; console 0 errors / 0 warnings across the session; dev.log clean (200s only). +- TRUE-SUBTRACT PROOF (single-shot discriminator, identical setup, only the blend line differs): backdrop (230,89,38) painted exact by replace; one subtract application of (102,128,153): 38,502 pixels at (140,0,0) -- the exact coverage-weighted true-subtract value -- while the old difference approximation's signature (B ~ 80) scored 2 (noise); additive contrast run brightens instead (mean G 48->105, B 28->71). The per-frame blend variable did the switching (header unchanged). +- BEHIND/CLEAR ALPHA PROOF: replace paints exact red bands (255,64,64); clear erases the middle stripe (alpha readback 0, redExact 0); behind's full-screen green quad then paints ONLY into the erased hole (4,654 green px inside the stripe, 0 outside) -- the opaque bands stay exact red. Chrome composite semantics probed synthetically in-page first (clear -> [0,0,0,0]; destination-over fills only the hole). +- DISSOLVE PROOF: single-shot dissolve over a gray backdrop at stroke alpha sweeps 0.2/0.5/0.8 -> white fraction 61/93.4/99.5% with mid-tones ~0.0-0.1% -- bimodal speckle tracking coverage (normal would land ~everything in the mid bucket). Coverage model mystery solved: short polyline segments (length ~= line width) put every pixel under round-join disk overlaps, so the scratch coverage is the join-overlap value, not the single-pass value; a subtract-based hash-free measurement (R = 230 - 102c -> c in the join range) confirmed the compositor is faithful. The sin-hash was replaced with a Hoskins-style hash as a robustness upgrade (no large-argument sin). +- STOCK REGRESSION: library Brainstorm (additive, 0.859) on the demo track: PTS 584, near-white flower core [221,223,252] at 88.9% bright (the 7.14.1 baseline look). FADE-PATH REGRESSION: paint-then-stop field at persist 0.6 -> displayed mean channel 0.91/255, zero pixels above alpha 16 (destination-out decays exactly like the old black fill over the black stage). +- What's New: 7.15.0 "The complete blend mode collection" first with the current badge; phoenix / plus-lighter / eraser-pen items present. Help panel: Blend modes table = 41 numbered rows (1 normal ... 41 silhouettealpha) + the blend-variable row. +- Responsive: 375x812 no horizontal overflow (scrollW 375 = clientW), footer pushed (docH 9640); 1280x800 footer sticks to the viewport bottom (docH 800 = innerH 800, footer bottom 800). Test-browser localStorage cleared afterwards. + +Stage Summary: +- v7.15.0 shipped: blend: takes any of 41 keywords (the full Photoshop set, GIMP grain pair, AE stencil/silhouette masks, plus-lighter/plus-darker, Pegtop exotica), case-insensitive with aliases; 21 modes run through a new WebGL compositor (subtract is now a true clamped subtract); behind and clear work honestly on the new alpha framebuffer; the blend variable switches modes per frame by registry number. Every existing preset renders as before (regression-verified headlessly and in-browser); WebGL-less browsers fall back per mode.