diff --git a/db/custom.db.seed b/db/custom.db.seed index 30d5575..0bfb762 100755 Binary files a/db/custom.db.seed and b/db/custom.db.seed differ diff --git a/src/lib/ava/embedded-presets.ts b/src/lib/ava/embedded-presets.ts index 12ddc7a..ca8e3ee 100755 --- a/src/lib/ava/embedded-presets.ts +++ b/src/lib/ava/embedded-presets.ts @@ -7,10 +7,12 @@ // for originals that rely on effects the script engine cannot run. // // The "Zai-Magic" folder at the END of EMBEDDED_LIBRARY is the exception to -// "do not edit": eleven presets HAND-AUTHORED for this engine (v7.00 + the -// v7.12 osc-rotations addition) to show off beat-synced color and the v7.12 -// background transform -- they use hsvr/hsvg/hsvb, beatage, megabuf particle -// physics, getspec(), loop() and the bg* framebuffer controls. If the +// "do not edit": twelve presets HAND-AUTHORED for this engine (v7.00 + the +// v7.12 osc-rotations addition + the v7.18 spectrogram) to show off +// beat-synced color and the v7.12 background transform -- they use +// hsvr/hsvg/hsvb, beatage, megabuf particle physics, getspec(), loop() and +// the bg* framebuffer controls (the twelfth, "Beautiful Spectrogram", is +// built on the bgx left-scroll + persist 1 zero-fade framebuffer). If the // converter ever regenerates this file, keep that section verbatim. // // EMBEDDED_SEED_VERSION: bump whenever this library is regenerated — the @@ -21,9 +23,14 @@ // the wall and the rightmost column keeps its bottom dot; v7.14: Arctic // Rainbow re-imagined as a music-driven water spray — slower rise, arching // fall, music-gated drop count, per-drop bass-hit hue shifts, falling-only -// RGB tails). +// RGB tails; v7.18: twelfth Zai-Magic preset "Beautiful Spectrogram" +// added — a true scrolling spectrogram on the bgx feedback slide; v7.18.1: its ink math re-derived -- the engine +// strokes every line segment separately, so a dense column paints each +// pixel 1 + width/spacing coats per pass and a fixed alpha cyan-washed +// the field; the preset now computes the coat count from the live +// geometry each frame and pre-divides the per-frame alpha). -export const EMBEDDED_SEED_VERSION = '7.14' +export const EMBEDDED_SEED_VERSION = '7.18.1' export interface EmbeddedPreset { folder: string @@ -849,13 +856,15 @@ export const EMBEDDED_LIBRARY: EmbeddedPreset[] = [ }, // ========================================================================== - // Zai-Magic — eleven presets hand-authored for this engine (v7.00; the - // eleventh, "osc-rotations", shipped with v7.12). Every one is built around - // BEAT-SYNCED COLOR: the color wheel turns on the kick, palettes swap per - // beat or per 4-beat bar, and kick envelopes (beatage) drive brightness; - // osc-rotations adds the v7.12 background transform (bgrot/bgzoom) to the - // toolkit. Techniques span all three render modes, megabuf particle - // physics, direct getspec() calls and loop() setup. + // Zai-Magic — twelve presets hand-authored for this engine (v7.00; the + // eleventh, "osc-rotations", shipped with v7.12; the twelfth, "Beautiful + // Spectrogram", with v7.18). Eleven are built around BEAT-SYNCED COLOR: + // the color wheel turns on the kick, palettes swap per beat or per 4-beat + // bar, and kick envelopes (beatage) drive brightness; osc-rotations adds + // the v7.12 background transform (bgrot/bgzoom) and Beautiful Spectrogram + // the bgx feedback slide + persist 1 zero-fade framebuffer to the toolkit. + // Techniques span all three render modes, megabuf particle physics, direct + // getspec() calls and loop() setup. // KEEP VERBATIM when regenerating this file with the converter. // ========================================================================== { @@ -1369,6 +1378,98 @@ green = hsvg(h, 0.95, lum) blue = hsvb(h, 0.95, lum) size = 2 + punch * 1.6 alpha = 0.92 +`, + }, + { + folder: "root/embedded/Zai-Magic", + name: "Beautiful Spectrogram", + author: "Zai", + description: + "A true scrolling spectrogram: every frame inks a fresh frequency column at the right edge -- quiet bins whisper pink, loud ones climb red, orange, yellow and finally white -- and the whole picture drifts left through a deep dark blue field that never fades, so the music leaves its heat-print hanging in the air until it scrolls away. Hand-authored for OVE (bgx feedback slide + persist 1 zero-fade framebuffer + megabuf level smoothing).", + content: `name: "Beautiful Spectrogram" +author: "Zai" +mode: lines +blend: additive +persist: 1 +linewidth: 2 + +[init] +n = 64 +# Palette table in megabuf: six RGB anchors (402..419) and the five segment +# bounds between them (420..425) -- deep dark blue -> pink -> red -> orange +# -> yellow -> white, indexed by the smoothed spectrum level. +megabuf(402) = 0.04; megabuf(403) = 0.06; megabuf(404) = 0.23 +megabuf(405) = 1.00; megabuf(406) = 0.35; megabuf(407) = 0.62 +megabuf(408) = 1.00; megabuf(409) = 0.13; megabuf(410) = 0.15 +megabuf(411) = 1.00; megabuf(412) = 0.50; megabuf(413) = 0.08 +megabuf(414) = 1.00; megabuf(415) = 0.88; megabuf(416) = 0.24 +megabuf(417) = 1.00; megabuf(418) = 0.99; megabuf(419) = 0.95 +megabuf(420) = 0; megabuf(421) = 0.16; megabuf(422) = 0.38 +megabuf(423) = 0.58; megabuf(424) = 0.78; megabuf(425) = 1 +lasp = 0 +booted = 0 +myt = 0 + +[frame] +# A stage resize wipes the canvas -- replay the fill sweep (skip the erase, +# the resize already cleared everything). +if(band(above(abs(aspect - lasp), 0.02), equal(booted, 1)), myt = 0.5, 0) +lasp = aspect +booted = 1 +myt = myt + dt +# Erase phase: with persist 1 the previous preset's framebuffer would ride +# the scroll for a whole screen width -- fade it out in half a second +# instead (the preset-change dissolve covers the transition). +persist = if(below(myt, 0.5), 0.45, 1) +# The time axis: the whole picture drifts LEFT (bgx is in half-width +# units). 15x speed for 3 s after the erase so the navy field sweeps the +# screen, then the slow crawl (a full width takes ~25 s). The per-frame +# step is capped at 1% of the width so slow frame rates still tile. +warm = 1 + 14 * max(0, 1 - max(0, myt - 0.5) / 3) +sf = min(0.04 * dt * warm, 0.01) +bgx = -2 * sf +spx = sf * w +# The write head: a vertical stroke at the right edge, ratio scroll-steps +# wide. Narrow while the sweep is fast (and on slow frame rates) so each +# coat of paint stays above 8-bit quantization -- the engine strokes every +# segment separately, so one frame paints a column pixel +# coats = 1.12 + 1.604 * wpx / segl +# times (core pass 0.9 + halo pass 0.22 x 3.2, each covering +# 1 + width/spacing segments), and a content element spends ratio frames +# under the brush. The per-frame alpha is pre-divided so that transit +# accumulates to full palette strength: quiet bins read as solid deep dark +# blue, loud ones as pure palette color. +rwm = 1.2 + 1.8 * clamp((8 - warm) / 7, 0, 1) +rfs = max(1.6, 3 - 18 * (dt - 0.0222)) +ratio = min(rwm, rfs) +wpx = ratio * spx +segl = 0.96 * h / 63 +coats = 1.12 + 1.604 * wpx / segl +ink = if(below(myt, 0.5), 0, min(0.6, 1.1 / (coats * ratio))) +colw = wpx * 480 / h +flash = exp(-beatage * 5) + +[point] +k = floor(i * 63 + 0.5) +# Level: tilt the quiet treble up, then gamma the palette open. +raw = sv * (1.75 + 0.75 * i) +lvl = pow(clamp(raw, 0, 1), 0.72) +# Attack at once, fall slow -- transients linger as a glow. +sm = max(lvl, megabuf(k) * exp(-dt * 2.5)) +megabuf(k) = sm +# Palette: pick the segment, lerp its anchor pair. +seg = above(sm, 0.16) + above(sm, 0.38) + above(sm, 0.58) + above(sm, 0.78) +lo = megabuf(420 + seg) +hi = megabuf(421 + seg) +u = (sm - lo) / (hi - lo) +pb = 402 + seg * 3 +x = 0.985 +y = i * 1.92 - 0.96 +red = lerp(megabuf(pb), megabuf(pb + 3), u) * (1 + flash * 0.12) +green = lerp(megabuf(pb + 1), megabuf(pb + 4), u) * (1 + flash * 0.12) +blue = lerp(megabuf(pb + 2), megabuf(pb + 5), u) * (1 + flash * 0.12) +size = colw +alpha = ink `, }, ] diff --git a/src/lib/release-notes.ts b/src/lib/release-notes.ts index aaec305..8220bb0 100755 --- a/src/lib/release-notes.ts +++ b/src/lib/release-notes.ts @@ -39,6 +39,20 @@ export interface ReleaseNote { } export const RELEASE_NOTES: ReleaseNote[] = [ + { + version: '7.18.0', + name: 'Beautiful Spectrogram', + changes: [ + { + kind: 'added', + text: 'I added a twelfth Zai-Magic preset: "Beautiful Spectrogram" -- a true scrolling spectrogram. Every frame inks a fresh frequency column at the right edge (bass at the bottom, treble at the top) and the whole picture drifts left through a deep dark blue field that never fades, so the music leaves its heat-print hanging in the air until it scrolls off the edge. Quiet bins whisper pink; loud ones climb red, orange, yellow and finally white, with hits lingering as a glow and the newest ink flaring on the beat.', + }, + { + kind: 'improved', + text: 'The preset is built entirely from script-engine features that already existed -- the background slide, the zero-fade framebuffer and megabuf bin memory -- so it doubles as a worked example of a whole new visual family (data-plots that write their own history) without any engine changes.', + }, + ], + }, { version: '7.17.0', name: 'True-black trails', diff --git a/src/lib/version.ts b/src/lib/version.ts index a7ac009..7b74bb4 100755 --- a/src/lib/version.ts +++ b/src/lib/version.ts @@ -12,6 +12,28 @@ // warns in the console when the two drift apart. // // History: +// 7.18 — "Beautiful Spectrogram" (user request, twelfth Zai-Magic +// preset): a true scrolling spectrogram as a pure script -- the +// v7.12 bgx feedback slide moves the whole framebuffer left +// every frame (the time axis) while persist 1 (v7.14.1's +// zero-fade framebuffer) keeps the history locked, so the print +// only ever leaves by scrolling off the left edge. The write +// head is a 256-point vertical line at the right edge: sv (the +// per-point spectrum) drives a megabuf attack/slow-decay level +// per frequency bin, which indexes a six-anchor palette table +// (also megabuf) -- deep dark blue background, then pink -> red +// -> orange -> yellow -> white as bins get loud. Two tricks make +// it read clean: (1) the stroke is exactly four scroll-steps +// wide with its per-frame alpha pre-divided by the accumulation +// factor (core 0.9 + halo 0.22*3.2 passes, times four overlapping +// steps ~= 1.6*4), so overlapping columns sum to exactly full +// palette strength and the quiet field renders as SOLID navy +// rather than banded; (2) a half-second erase phase (per-frame +// persist override to 0.45) drains the previous preset's +// framebuffer before the zero-fade lock engages, and a 15x +// three-second fill sweep (plus a replay on stage resize) paints +// the navy field across the whole screen instead of making the +// visitor wait 25 s for the crawl to cover it. // 7.17 — True-black trail fade (user request, "Orange Burst"): the // persistence fade multiplies the framebuffer by persist in // 8-bit steps, so any persist >= 0.5 leaves fixed points @@ -594,4 +616,4 @@ export const APP_NAME = 'Open Visualization Engine' export const APP_SHORT = 'OVE' -export const APP_VERSION = '7.17.0' +export const APP_VERSION = '7.18.0' diff --git a/worklog.md b/worklog.md index 3960abb..882dc58 100755 --- a/worklog.md +++ b/worklog.md @@ -2658,3 +2658,29 @@ Push status (unchanged from Task 49's note): blocked from inside the sandbox -- Stage Summary: - Task 47's persistence stack re-verified end-to-end and fully intact: tracked .env.ove/.env/seed/secrets, byte-identical env pair, seed == live db, self-heal re-proven by fixture on the shipped code, clean 16:22 boot, healthy app. Nothing needed re-doing. Push to origin zai-dev remains gated on operator-side Forgejo credentials (this sandbox carries none by design of the reprovision); local main and local zai-dev carry everything and fast-forward cleanly pending that push. + +--- +Task ID: 51 +Agent: main (Z.ai Code) +Task: v7.18.0 (user request): create a visual script preset "Beautiful Spectrogram" under Zai-Magic -- a deep dark blue background that slowly scrolls to the left, with the audio print colored pink -> red -> orange -> yellow -> white -- and provide the script code in chat. Project changes acceptable. + +Approach: +- Pure script, zero engine changes: the time axis is the v7.12 bgx feedback slide (whole framebuffer drifts left every frame), persist 1 (v7.14.1 zero-fade) locks the history so the print only leaves by scrolling off the left edge, and the write head is a 64-point vertical line at x=0.985 whose per-point color lerps a six-anchor megabuf palette (deep navy -> pink -> red -> orange -> yellow -> white) indexed by an attack/slow-decay smoothed per-bin level (sv with a +0.75i treble tilt, ^0.72 gamma). +- THE HARD PART -- ink calibration. First cut (fixed alpha 0.155, 256 points) cyan-washed the field. Root cause chain, all measured on the live canvas: (1) drawContent strokes every segment separately, so one frame paints a column pixel 1 + width/pointSpacing coats per pass (a 256-point column under a 32px warm-up brush = ~21 coats/frame -> alpha saturates in one frame, colors blow past the palette and clamp channel-by-channel); (2) once the per-frame alpha is pre-divided small enough, the faint channels die to 8-bit quantization (navy's r=10/255 under ink<0.1 adds < 1 LSB per coat and rounds away -> the same cyan, from the other side); (3) frame-rate coupling (headless idle throttling to ~2fps showed dt-clamped 0.1 steps) proves the geometry must be computed from live dt/w/h every frame. Final design, all computed per frame in [frame]: scroll step capped at 1% of width per frame; brush ratio = ratio scroll-steps wide, narrow (1.2) during the 15x fill sweep and on slow frame rates (1.6 floor), 3 at steady state; coats = 1.12 + 1.604*wpx/segl (core 0.9 + halo 0.22x3.2 passes, each covering 1 + width/spacing segments); ink = 1.1/(coats*ratio) clamped 0.6 -- so the ratio-frame transit accumulates to ~full palette strength at every fps, aspect and brush width, with per-coat adds kept >= ~2 LSB. +- Lifecycle: a 0.5s erase phase (per-frame persist override 0.45, ink 0) drains the previous preset's framebuffer before the zero-fade lock engages (otherwise old art rides the scroll for a full screen width); then a 3s 15x fill sweep paints the navy field across the screen (96% coverage) so the visitor does not wait 25s for the crawl to cover it; a stage resize (canvas wipe) replays the sweep (aspect-change detector with a 0.02 deadband, booted flag so the first frame does not trigger); beat flare: newest ink brightens 12% on exp(-beatage*5). + +Work Log: +- src/lib/ava/embedded-presets.ts: twelfth Zai-Magic preset "Beautiful Spectrogram" appended (KEEP VERBATIM section); EMBEDDED_SEED_VERSION 7.14 -> 7.18.1 (bumped twice: 7.18 added the preset, 7.18.1 replaced the first cut's flawed ink math -- the fingerprint gate only re-seeds on version change since folder+name were unchanged); file header + Zai-Magic section comments updated (eleven -> twelve). +- src/lib/version.ts: APP_VERSION 7.18.0 + history entry (the full ink-math derivation). src/lib/release-notes.ts: 7.18.0 "Beautiful Spectrogram" (added + improved, first person, no em dashes). +- db/custom.db.seed re-synced after the library re-seed (107 presets incl. the new row, verified by direct SQLite read). + +BROWSER E2E (agent-browser, ALL PASS): +- Parse/compile: validateScript clean (lines/additive/persist 1); 64 points, megabuf palette + bins; offline simulation of [init]/[frame]/[point] across 10 scenarios (erase, wash t=1/2/3, steady 60/120/10fps, portrait, ultrawide, wash-at-10fps) -- every case ink 0.21-0.37, per-coat red add 1.9-3.4 LSB, accumulation 1.1x palette. +- Library: /api/presets re-seeded on both version bumps; Zai-Magic serves 12 presets with Beautiful Spectrogram sorted between Aurora Veil and Bass Bloom; tree double-click loads it (footer SCRIPT: Beautiful Spectrogram, PTS: 64). +- Canvas pixels (quiet passage): background rgb(5,13,54) = deep dark navy (palette anchor 10,15,59); palette census pink 5.2% / red 9.8% / orange 5.0% / yellow 3.5% / white 2.0% / green 0.00% / cyan 0.01% -- the first cut's cyan plague measured 23.5% white + green fields, now gone. +- Scroll: engine bgx verified independently with a burst probe (bgx -0.01 -> 216px/s measured vs 209 predicted); the spectrogram measured per-frame via high-pass Pearson cross-correlation -- steady state 0.483px/frame vs 0.526 design (8%, beat-stripe noise), warm-up ramp 1.82px/frame at warm~5.5 as designed; direction LEFT (r up to 0.997). +- VLM screenshot review (desktop, loud passage): "coherent scrolling spectrogram, sensible frequency-vs-time structure", ramp deep red -> orange -> golden yellow -> near-white, "no green or cyan anywhere"; portrait 420x800 renders at 60fps with the resize re-warm firing (harmonic stripe structure is real 64-bin resolution, not an artifact). +- App: title "OVE -- Open Visualization Engine (v7.18.0)"; What's New dialog leads with 7.18.0 "Beautiful Spectrogram"; console 0 errors / 0 warnings; bun run lint clean; dev.log 200s only. + +Stage Summary: +- v7.18.0 shipped: "Beautiful Spectrogram", the twelfth hand-authored Zai-Magic preset -- a true scrolling spectrogram as a pure script (bgx slide + persist 1 zero-fade + megabuf bin memory + palette table), with the per-frame ink computed from live stroke geometry so the accumulation lands on the palette at any fps/aspect/brush width. Browser-verified end to end: navy field, pink-to-white print, leftward crawl at design rate, no channel contamination, clean console.