30d7a251-db3d-4ef7-9904-20d67254a59e

This commit is contained in:
Z User 2026-11-05 22:25:24 +00:00
parent 9cea959a52
commit f5df41dcf3
42 changed files with 596 additions and 3 deletions

2
.env
View file

@ -1,3 +1 @@
DATABASE_URL=file:/home/z/my-project/db/custom.db DATABASE_URL=file:/home/z/my-project/db/custom.db
OVE_DIRECTORY_URL=https://s3374dir.openvisengine.com
OVE_DIRECTORY_API_KEY=+7MkRB+hkV0UBhPqM1haTQ0f8JGKqkuXwoBTdTSAouU=

View file

@ -1 +1 @@
1198 1048

View file

0
src/app/api/ove-directory/scripts/[id]/route.ts Normal file → Executable file
View file

0
src/app/api/ove-directory/scripts/route.ts Normal file → Executable file
View file

0
src/app/api/ove-directory/status/route.ts Normal file → Executable file
View file

0
src/components/ava/directory-tab.tsx Normal file → Executable file
View file

0
src/components/ava/upload-dialog.tsx Normal file → Executable file
View file

0
src/lib/ava/wake-lock.ts Normal file → Executable file
View file

0
src/lib/ove-directory.ts Normal file → Executable file
View file

0
src/lib/server/ove-directory.ts Normal file → Executable file
View file

0
tool-results/osc12-1-preset-live.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 271 KiB

After

Width:  |  Height:  |  Size: 271 KiB

0
tool-results/osc12-2-rot-test.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 132 KiB

0
tool-results/osc12-3-final-live.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 227 KiB

0
tool-results/osc12-4-mobile.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

0
tool-results/read_1793817131261_fb699e6a294f.txt Normal file → Executable file
View file

0
tool-results/read_1793817160288_8d6de58d6d8d.txt Normal file → Executable file
View file

0
tool-results/read_1793835734103_a615e8778496.txt Normal file → Executable file
View file

View file

@ -0,0 +1,160 @@
2200→- Round-trip EXACT on 207 scripts (90 tools/converted .ava + 6 rust-agent presets + presets.ts inline + 105 DB built-ins): 136,046 → 69,523 chars = 49% shorter overall (best 56%, worst 28%); determinism verified per script.
2201→- Adversarial "soup" (every reserved symbol, all card suits, chess, zodiac, arrows, circled digits, control pictures, backslashes, CRLF, raw control chars, VS16/ZWJ sequences, emoji incl. ZWJ families, combining marks, surrogate edges): exact round-trip.
2202→- 3,000-string fuzz over a hostile alphabet: 3,000/3,000 exact. CJK-comment scripts (colliding with the pair-packing block) and literal pair-block content round-trip via the escape path.
2203→- Decode rejects: truncation (−1/−5/−20 chars), flipped body char (checksum), garbage/empty/malformed inputs; accepts: padded+quoted, bare body, VS16+ZWSP mangled (injected between EVERY char), name with colons/brackets (sanitized), >48-char names (capped).
2204→
2205→BROWSER E2E (agent-browser + VLM, ALL PASS):
2206→- Script tab shows both buttons; Script⇢Hash opens with `Bass Bloom:[▲…③⑬⑧⑭①⑧⑩⑪]` — 679 chars, "49% shorter than the script", semantic symbols + CJK pairs visible; Copy click → "Copied!" (clipboard API present).
2207→- Full UI round-trip: hash captured → Hash⇢Script pasted → Decode → panel "Bass Bloom · 56 lines · 1341 characters · Compiles OK — mode: dots" → Load into Editor → editor content BYTE-IDENTICAL to the original (1341/1341 chars, string equality true).
2208→- Errors: garbage → "does not look like an OVE share string…"; truncated (−15, loses "]") → "looks cut off — it should end with "]" (signature-based message); altered → checksum message.
2209→- Re-open resets paste state (bug fix verified); Settings tab: no Music services section/heading/log-in buttons, Appearance intact (visible panel text verified).
2210→- Mobile 375 px: toolbar wraps with both buttons on-screen, no horizontal overflow; both dialogs fit (16–359 px wide, Script⇢Hash 69–743 px in 812 px viewport after the height-cap fix; textarea ≤ 240 px, scrolls internally). 320 px header: scrollWidth 320 = clientWidth (v7.6.1's removal fixed the old ≤360 px overflow — re-measured as promised).
2211→- VLM (dark, Script⇢Hash): nothing crosses the border, string/symbols/ Copy/stats all present, readable, no defects. VLM (light, Hash⇢Script): title, placeholder "My Script:[▲…]", Cancel/Decode well-formed, contrast good on white. VLM (mobile): fully visible, nothing cut off.
2212→- Fresh reload: console 0 errors/0 warnings (release-notes drift guard silent — v7.7 entries match); dev.log clean (compile + 200s only). Test-browser localStorage cleared afterwards.
2213→
2214→Stage Summary:
2215→- v7.7 shipped: scripts are now shareable as single Unicode strings — ~half the length of the script, self-checking, copy/paste-survivable, lossless for ANY text (compiling not required) — and the Settings tab is decluttered while the house account keeps Stream-a-Link working for everyone. The shared dialog height cap protects every dialog app-wide from tall content on short screens.
2216→
2217→---
2218→Task ID: 37
2219→Agent: main (Z.ai Code)
2220→Task: v7.10.1 (user report while testing their new "Spectrum Bars" script): a section on the very right of spectrum visuals is inactive and never reacts to the music -- same dead right edge on other spectrum scripts. Explain why, then fix it engine-side so every script benefits.
2221→
2222→DIAGNOSIS (why the right edge is dead):
2223→- getspec()/sv mapped bar position 0..1 across the WHOLE FFT: bin = 2 + floor(p^1.6 * 4093) at 8192-point FFT, so pos 1.0 = bin 4095 = Nyquist (22.05/24 kHz). pos 0.8 already lands at ~16.8 kHz.
2224→- Real music carries almost nothing up there, and every lossy source low-passes even lower: the demo collection is 192 kbps MP3 @48 kHz (LAME low-pass ~18.6 kHz), YouTube AAC ~15.5 kHz. Measured on demo-01 (20 s, 8192-FFT): 0.000% of total magnitude above 18.6 kHz; content above -40 dB rel. peak ends at ~13.4 kHz, above -60 dB at ~17.8 kHz.
2225→- So bar positions above ~0.82 read byte 0 every frame -- the rightmost ~20% of every spectrum visual was permanently frozen at the floor. Not a script bug: every script sampling getspec over 0..1 (all 10 converted getspec presets included) showed the same dead edge, exactly like the Winamp AVS originals. The engine's own flux detector already caps at 16 kHz for the same reason (audio.ts getBands).
2226→
2227→Work Log:
2228→- src/lib/ava/audio.ts: new SPEC_TOP_HZ = 16000 const (with the full why-comment); getSpectrum() now maps the field from bin 2 (~12 Hz) to the 16 kHz bin instead of Nyquist: hiBin = clamp(ceil(16000/binHz)), bin = 2 + floor(p^1.6 * (hiBin - 2)). Same log-ish curve, every position now lands on frequencies music occupies; right edge = 12-16 kHz "air" band (cymbals/hats/sparkle). Matches the flux cap.
2229→- rust-agent/src/spectrum.rs: SPEC_TOP_HZ const + spectrum_at() mirrors the new mapping exactly (source parity; not compiled locally, no cargo).
2230→- help-panel.tsx: sv entry now states the span: "spectrum magnitude 0..1 (≈12 Hz to 16 kHz, log-ish -- the range music actually occupies)".
2231→- version.ts 7.10.1 + history entry; release-notes.ts 7.10.1 "Spectrum edge unfrozen" (fixed, first-person voice). lint clean; tsc clean apart from the pre-existing base-target share-codec BigInt literals.
2232→
2233→VERIFICATION (three independent measurements):
2234→- Offline full-track emulation (Blackman window + AnalyserNode dB byte mapping, every 21 ms of demo-01): under the NEW mapping every one of 48 bars is >15/255 in 76-100% of frames and >60/255 in 68-99% -- nothing is structurally dead. Under the old mapping positions >0.82 read literal zero.
2235→- Fresh in-page chain (eval: fetch demo-01 -> decodeAudioData -> own AnalyserNode at t=150 s): top positions dance (pos 1.0 = 16 kHz fluctuates 4..118/255 frame to frame).
2236→- Live E2E with the USER'S OWN "Spectrum Bars" script (found in the test browser's localStorage from the previous session, 28 bars x 4 pts, running on Demo Track 2 at 60 FPS): per-bar pixel measurements across 6 frames show the rightmost bars (f 0.74-1.0 = 9.9-16 kHz) swinging 4%..76% with the music -- under the old mapping those bars sampled 16.8-24 kHz and sat pinned at 0 (the script's own below(lvl,0.004)?0 snap would hold them perfectly flat). Also verified with a purpose-built 48-bar "Edge Check" script earlier in the session.
2237→- Anomaly chased and closed: one 5-sample window showed bars 36-48 at floor while bass danced -- turned out to be the demo track's outro (offline analysis: t=187-191 s has a legitimately dead 10-16 kHz band while lows keep going); the demo ended right after (SRC: IDLE, place advanced), matching the timeline. Not a mapping issue.
2238→- What's New dialog: v7.10.1 "Spectrum edge unfrozen" first with CURRENT badge + FIXED tag; drift guard silent after a clean reload (one transient guard warning was hot-reload event ordering + stale console history); the one hydration error was agent-browser's own data-__ab-ci instrumentation, absent on a clean reload. Console otherwise clean; dev.log clean.
2239→- Test-browser localStorage cleared afterwards (convention); scratch PCM deleted.
2240→
2241→Stage Summary:
2242→- v7.10.1 shipped: the frozen right edge of every spectrum visual is unfrozen. The bar field now spans ~12 Hz to 16 kHz (the range music actually occupies) instead of stretching to Nyquist, so the right bars land on the 10-16 kHz air band and dance with the hats/cymbals. The user's own Spectrum Bars script (whose 0.78+0.45*f treble tilt now has something real to boost) verified live: rightmost bars swing 4..76%.
2243→
2244→---
2245→Task ID: 38
2246→Agent: main (Z.ai Code)
2247→Task: v7.11 (user request, three parts). RESTORED RETROACTIVELY — the entry was lost in a session cutoff (same as Task 35 once was); scope reconstructed from the version.ts 7.11 history and the tool-results/v711-* evidence screenshots (v711-01 through v711-22, all PASS). (1) Mobile wake lock: while any audio source is live the site holds a Screen Wake Lock so phone/tablet screens stay on; released the moment the engine goes idle so normal inactivity dimming returns. (2) A respectful Demo Track button: no longer force-engages the Sequence checkbox when the visitor has loaded a preset (tree double-click / Load / copied preset) or brought their own script material into the editor — Demo just plays the track; the Zai-Magic showcase only starts for a visit that never picked or typed anything. (3) Script tab one-click Save: a valid script shows the Save button with no save target needed; auto-names from the script's name header (a hash import of "Spectrum Bars:[▼…]" saves as "Spectrum Bars"), "Empty Name" when nameless, " (1)"/" (2)"… suffixes on conflicts — and when the name had to be invented, a "Give This Preset a Name" dialog opens to rename the just-saved preset in one step (saved FIRST, renamed second, so nothing is ever lost).
2248→
2249→Work Log (reconstructed):
2250→- src/lib/ava/wake-lock.ts (NEW): Screen Wake Lock sentinel manager — acquire on source-live, release on idle, visibilitychange re-acquire (browsers silently drop the sentinel on hide), silent degradation where unsupported.
2251→- audio-source.ts / control-panel / page.tsx: per-visit manualChoice flag + boot-script snapshot decide whether the Demo showcase may engage; ensureDefaultPreset gained the same guard (mic/file/link never clobber a custom draft either). Demo teardown paths (ended/stop/switch) all respect it.
2252→- script-tab.tsx: Save button visible on any valid script with no target; auto-naming ladder (script name header -> hash import label -> "Empty Name" -> conflict suffixes); "Give This Preset a Name" dialog after any invented save. Hash⇢Script imports clear the stale save target and pass the decoded label through as the fallback name.
2253→- version.ts 7.11 + history; release-notes.ts 7.11 entry.
2254→
2255→E2E (evidence: tool-results/v711-01..22, ALL PASS):
2256→- Fresh boot (no selection, no editor material): Demo engages the sequence showcase as before — v711-19/20.
2257→- Preset loaded first (double-click, v711-03; embedded, v711-04): Demo plays the track, Sequence stays UNCHECKED (v711-06), the running script is untouched — a custom script can be debugged against the demo track without fear of replacement (v711-05 custom material case).
2258→- Hash⇢Script -> Save: lands under "user created" as "Spectrum Bars" from the share-string label (v711-09/10/11); nameless script saves as "Empty Name" then the rename dialog appears (v711-12/15); duplicate conflicts get " (1)"/" (2)" suffixes (v711-16/17) and the rename updates the saved preset (v711-13).
2259→- Default boot script + reload states (v711-18); mobile 375 px (v711-21) and desktop (v711-22) clean; wake lock verified by code path (headless browsers do not expose navigator.wakeLock — degrade-silent branch exercised).
2260→
2261→Stage Summary:
2262→- v7.11 shipped: the screen stays on while music plays, the Demo button stopped hijacking the preset selection, and one click saves any valid script with a smart name. This restored entry closes the gap in the build diary.
2263→
2264→---
2265→Task ID: 39
2266→Agent: main (Z.ai Code)
2267→Task: v7.12 (user request): add the classic-AVS background-movement family to the scripting — the background shifts up/down/left/right, spins clockwise/counter-clockwise, draws in and blows out, with the speed accelerating to the beat and hard hits flipping the spin direction while the fade to black stays slow (so colors blend) — then ship a permanent Zai-Magic preset "osc-rotations": a stationary centered oscilloscope whose left/right points color-shift together and whose center points hold their own hue, over a background rotating cw/ccw to the music with temporary beat acceleration.
2268→
2269→Work Log:
2270→- src/lib/ava/engine.ts — NEW background feedback transform (the AVS movement family):
2271→ * Script controls, read from env AFTER [frame]/[beat] run so this frame's values apply this frame: bgrot (radians/frame, + = CLOCKWISE on screen — canvas y is down so ctx.rotate(+) spins cw), bgx/bgy (per-frame drift, the -1..1 screen convention, y is UP matching script x/y), bgzoom (per-frame scale: <1 draw-in, >1 blow-out, 1 = neutral). Values persist in env like any variable — set from [init] (persists forever), [frame] (every frame) or [beat] (on-beat jumps); neutral readings skip the pass entirely (zero cost for every preset that doesn't move).
2272→ * applyBackground(): snapshot the live canvas into an offscreen buffer (globalCompositeOperation 'copy'), wipe the canvas black (the transformed snapshot must REPLACE the old content, not double-expose), then draw the snapshot back through the frame's transform (translate w/2+bgx*w/2, h/2-bgy*h/2; rotate; scale). Uncovered regions (rotated corners, slid-off edges) read black and the persistence fade blends the trails — exactly how the classic AVS plugins made "speed accelerates to the beat, a hard hit flips the spin, fade stays slow" work: the rate is just a script variable driven by a beatage envelope, and a [beat] section flips a dir variable on hard hits (bass vs bass_att).
2273→ * Guards: bgNum() falls back to neutral for missing/NaN values (a NaN in a canvas transform matrix would black the screen with no error — every later draw becomes a silent no-op); per-frame clamps rot ±0.6 rad, drift ±0.25, zoom 0.5..2. Buffer recreated automatically on resize; null until first use (zero cost otherwise). Gated on this.script so a stale env after clearScript can never spin a blank canvas.
2274→- src/lib/ava/embedded-presets.ts — eleventh Zai-Magic preset "osc-rotations" (user-named, lowercase so it sorts last in the tree): persist 0.965 (slow fade — colors blend), [frame] drives bgrot = dir * (0.0032 + punch * (0.014 + vol_att * 0.012)) with punch = exp(-beatage*3.2) (temporary beat acceleration that relaxes with the kick ring), bgzoom = 1 - 0.0009 - punch*0.0011 (a whisper of draw-in so trails spiral inward instead of ringing), hue drifts dt*0.012 + beat*0.02; [beat] flips dir on hard hits only (bass > 1.25 * bass_att — soft beats leave the spin alone); [point] draws the stationary centered scope x = i*2-1, y = v*(0.3+vol_att*0.8) with mirror-symmetric color h = hue + |i-0.5|*2 * 0.34 (points equidistant left/right of center share one hue, the center holds its own). EMBEDDED_SEED_VERSION 7.10 -> 7.12 (route re-seeds the subtree; fingerprint self-heal would have caught it too). "ten presets" comments updated to eleven (both the file-top and the Zai-Magic section header).
2275→- src/components/ava/help-panel.tsx — bgrot / bgx/bgy / bgzoom rows in the variables table + three example formulas (beat-accelerated spin, hard-hit direction flip in [beat], draw-in).
2276→- src/lib/version.ts 7.12 + history; src/lib/release-notes.ts 7.12 entry (2x added, first-person voice). Share codec deliberately untouched: its dictionary is a frozen compatibility contract (adding entries needs a new scheme marker) — bg* identifiers ride the pair packing like any custom variable.
2277→
2278→HEADLESS VALIDATION (/home/z/tmp-validate/bg-transform/validate-osc.ts, ALL PASS):
2279→- osc-rotations compiles; all 101 embedded presets still compile (regression guard).
2280→- Compiled-program behavior: quiet frame bgrot 0.00397 rad/frame cw + bgzoom 0.99906; hard beat bgrot 0.0256 (6.5x) AND dir flips to -1; soft beat no flip; point pass x spans ±1 with |y| symmetric, mirrored positions share hue exactly (0.7906 both) while center is distinct (0.6206).
2281→
2282→BROWSER E2E (agent-browser + pixel measurement + VLM, ALL PASS):
2283→- Fresh boot: title "OVE -- Open Visualization Engine (v7.12)"; tree shows "Zai-Magic -- 11"; /api/presets re-seeded on the version gate and serves osc-rotations (106 presets total; sorts last in Zai-Magic as designed).
2284→- Preset live on the demo collection (manual load first, then Demo Track — v7.11's respectful-Demo still holds: Random/Sequence stayed UNCHECKED with a preset loaded): footer "SCRIPT: osc-rotations · Demo Track 1/2 · FPS 59-60 · PTS 512 · BPM 132.3/138.8 locked". Mid-band (scope zone) mean 133/255; outer zones lit only by rotation-carried trails.
2285→- bgrot isolation (line mathematically confined to the middle 35% band, so outer-zone content can ONLY be rotation-carried): outer zones hold a steady mean ~14/255 vs EXACTLY 0.00 in the no-bg control — rotation puts content where the line cannot reach.
2286→- bgx sign: +0.012 drifts the bright cloud right (mean x 0.518); -0.012 mirrors it exactly (0.480) — the sign convention verified by symmetry.
2287→- bgy sign: +0.02 pulls the bright cloud UP (mean y-from-top 0.368 vs 0.5 neutral).
2288→- bgzoom: at 1.05/frame the outer zones went from dead 0.00 to ~38/255 (blow-out pushes the confined line's trails outward); at 1.003/frame with persist 0.92 trails die before traveling far (consistent with the fade math — equilibrium analysis, not a defect).
2289→- What's New dialog: 7.12 "Background movement (AVS-style) + osc-rotations" first with CURRENT badge, drift guard silent. Help panel: bg* rows + examples all present.
2290→- VLM on the live screenshot: horizontal oscillating waveform line at vertical center; large soft colorful trail masses around it; hue variation green at the outer left/right edges, yellow mid, red/pink at the center — the mirror-symmetric color design visibly realized; no defects; "60 FPS . 512 PTS" overlay normal.
2291→- Console clean (0 errors/0 warnings); dev.log clean (59 successful requests, no compile errors). Footer: sticks to the viewport bottom on short pages (1280x800 Beat tab: docH 800, footer bottom 800) and pushes to the document end on long pages (375 px Presets tab: docH 1469, footer at doc end, no overlap); 375 px scrollWidth 375 = clientWidth (no horizontal overflow). Test-browser localStorage cleared afterwards.
2292→
2293→Stage Summary:
2294→- v7.12 shipped: scripts can move the whole picture — bgrot spins, bgx/bgy slide, bgzoom draws in / blows out — with the speed riding the music exactly the way the classic AVS plugins did it (beatage envelopes drive the rate, [beat] flips the spin on hard hits, persist keeps the fade slow so colors blend). The eleventh Zai-Magic preset "osc-rotations" demonstrates the full recipe: a stationary centered oscilloscope with mirror-symmetric color (left/right shift together, center holds its own hue) over a beat-accelerated, hard-hit-flipping rotating background.
2295→
2296→---
2297→Task ID: 40
2298→Agent: main (Z.ai Code)
2299→Task: v7.13 (user request): merge the two parallel development lines. The user supplied the v7.12 build ("updated script editor variables and the osc-rotations preset") as an encrypted zip on Google Drive (password: z.ai) and asked to compare it with this tree's "Upload to OVE-Directory" version (v7.11) and merge the improvements into one build.
2300→
2301→MERGE ARCHAEOLOGY:
2302→- The Drive zip (openvisengine.zip, 374 MB, AES-encrypted, compression type 99 — Python zipfile can't read it; pyzipper could) extracted to /home/z/drive-712/v712-full: APP_VERSION 7.12, worklog Tasks 37-39 (v7.10.1 spectrum fix, v7.11 wake lock/respectful-Demo/one-click-Save, v7.12 bg movement + osc-rotations). The partial ove-src12/ extraction from the earlier session verified identical (114/115 sha256; the one mismatch was a Drive-fetch artifact named "globals.css CSS").
2303→- Divergence map via the zip's own .git: BOTH repos share commit d59d398 (tree 953bae5... — IDENTICAL hash on both sides, a true common ancestor at v7.10). After it: this tree shipped v7.11 = the OVE-Directory (directory-tab.tsx, upload-dialog.tsx, /api/ove-directory proxy, lib/ove-directory.ts); the zip tree shipped 7.10.1 + 7.11-wake-lock + 7.12. The ONLY overlapping files were script-tab.tsx, version.ts, release-notes.ts (+ demo-track binaries, identical on both sides).
2304→
2305→Work Log:
2306→- Git 3-way merge: zip repo fetched as remote v712, `git merge 1ea335a` — everything auto-merged (engine.ts applyBackground + bgrot/bgx/bgy/bgzoom, audio.ts SPEC_TOP_HZ 16 kHz cap, rust-agent/spectrum.rs mirror, embedded-presets.ts osc-rotations + EMBEDDED_SEED_VERSION 7.12, wake-lock.ts NEW, audio-source.ts + page.tsx manualChoice/respectful-Demo, presets-tab.tsx, share-dialogs.tsx, store.ts markManualChoice, help-panel.tsx bg* rows + sv span) except three conflicts.
2307→- script-tab.tsx (hand-merged): both sides' state blocks kept side by side — ours' uploadOpen/canUpload (Upload to OVE-Directory, gated on ✔ Compiled OK + no runtime error) + theirs' pendingName/rename* states (one-click Save + "Give This Preset a Name"); toolbar now carries the dual Save (target save / one-click new) AND the Upload button; Hash⇢Script import sets pendingName + clears editTarget + markManualChoice; UploadToDirectoryDialog mounted. Verified byte-lossless: diff vs the v7.12 original removes ONLY comment lines (theirs' code 100% intact; ours' upload code added).
2308→- version.ts + release-notes.ts (hand-merged into ONE timeline): NEW 7.13 entry ("one build, every feature") on top, then 7.12 (bg movement + osc-rotations), 7.11 (the OVE-Directory), 7.10.2 (the parallel line's wake-lock/respectful-Demo/one-click-Save release — RENUMBERED from its original 7.11 so the list reads monotonically; noted in the 7.13 text), 7.10.1 (spectrum edge), 7.10 and below untouched. APP_VERSION = '7.13'. Drift guard green.
2309→- engine.ts / audio.ts / embedded-presets.ts / wake-lock.ts / help-panel.tsx / audio-source.ts verified BYTE-IDENTICAL to the validated v7.12 originals (cmp) — the parallel line's E2E-proven behavior carries over by construction.
2310→
2311→ENVIRONMENT RECOVERY (sandbox quirks, not code):
2312→- The merge swapped db/custom.db underneath the running server → Prisma "readonly database" (dead inode); fixed by restart.
2313→- Turbopack's persistent cache panicked twice ("Failed to restore task data — corrupted database") after file replacements/kills; fixed with rm -rf .next + clean start.
2314→- Directly-spawned background servers were reaped when the Bash session ended; the stable path is the system's own .zscripts/dev.sh (disowned bun run dev). Server now up: / 200, /api/presets 200, /api/ove-directory/* 200.
2315→- EMBEDDED_SEED_VERSION gate fired on first hit (7.10 -> 7.12): DB re-seeded to 106 presets incl. osc-rotations (verified in SQLite: seed=7.12, count=106, osc-rotations=1).
2316→
2317→E2E (agent-browser + pixel measurement + VLM, ALL PASS):
2318→- Fresh boot: title "OVE -- Open Visualization Engine (v7.13)"; tree root/embedded 106 = Amp Picks 66 + Dynamics 9 + Envision 15 + Synth-C 5 + Zai-Magic 11; osc-rotations sorts last in Zai-Magic as designed.
2319→- osc-rotations live on Demo Track (dblclick-load via the treeitem's inner button): footer "SRC: DEMO · Demo Track · FPS 59-60 · PTS 512 · BPM 139.9 locked · SCRIPT: osc-rotations". Two frames 1.2 s apart: 20% of sampled pixels changed (animating). Zone means: mid-band 69.7/255 (the scope) vs corners 3.3-13.8/255 — outer-zone content can ONLY be rotation-carried (the line is confined to the middle), i.e. applyBackground is rotating the picture in the merged build.
2320→- VLM on the clean capture: (1) bright horizontal oscillating waveform at the vertical center ✓; (2) colorful smeared trail masses at corners/edges "consistent with a rotating background layer smearing trails around the stationary center waveform" ✓; (3) mirror-symmetric hues — yellow/gold at BOTH extremes, warm pink/magenta in the middle ✓; (4) no UI defects ✓.
2321→- Script tab: Apply / Save / Script⇢Hash / Hash⇢Script / Upload to OVE-Directory / New / Help ALL present; with a compiling script both Save and Upload enabled (upload title carries the publish/fix-then-apply guidance); Upload dialog opens with the share-string description.
2322→- One-click Save flow: New (template) -> strip the name header -> Save -> saved as "Empty Name" -> "Give This Preset a Name" dialog opened automatically -> renamed to "Merge Test v713" -> "Preset renamed" toast; test preset removed from localStorage afterwards.
2323→- Directory tab: live listing via the proxy (1 script, sort controls, "Spectrum Bars · LINES · Average: 4.5 · 2 votes", Get button).
2324→- Help panel: bgrot / bgx / bgy / bgzoom rows + example formulas all present.
2325→- What's New dialog: 7.13 "One build, every feature" FIRST with CURRENT badge; 7.12, 7.10.2 in the merged timeline; drift guard silent.
2326→- Responsive: 375x812 no horizontal overflow (scrollWidth 375 = clientWidth), footer pushed to document end (docH 1651); 1280x800 footer sticks to viewport bottom (800 = 800).
2327→- Console: 0 errors, 0 warnings (wake lock degrades silently in headless — no navigator.wakeLock); dev.log 0 errors. Test-browser localStorage cleaned afterwards.
2328→
2329→Stage Summary:
2330→- v7.13 shipped: the parallel line is merged — the spectrum 16 kHz cap, the screen wake lock, the respectful Demo button, the one-click Save with auto-naming + rename dialog, the AVS-style background movement family (bgrot/bgx/bgy/bgzoom) and the eleventh Zai-Magic preset "osc-rotations" all run in the same build as the community OVE-Directory, with one clean version timeline (the parallel wake-lock release folded in as 7.10.2). Only three files needed hand-merging; every engine-side change is byte-identical to its validated original.
2331→
2332→---
2333→Task ID: 41
2334→Agent: main (Z.ai Code)
2335→Task: v7.13.1 (user report): in Zai-Magic "Beat Matrix" the rightmost vertical line of dots sat offset +1 upwards -- its bottom dot did not line up with the other columns, and its top dot spilled over onto the next section to the right. Diagnose, explain, fix.
2336→
2337→DIAGNOSIS (why the right column was short and a phantom dot spilled):
2338→- The engine's point position i spans 0..1 INCLUSIVE (classic AVS Superscope convention; engine.ts: i = k/(n-1)). Beat Matrix's grid math assumed exclusive i = k/n: col = floor(i * cols) sends the LAST point (i = 1 exactly) to col 16 -- one column past the 16-column wall (x = 0.986/aspect vs the wall edge 0.87/aspect) at row 0 (top), reading getspec(1.0); and column 15 was left with only 9 dots (rows 0-8, no bottom: its lowest dot sat at y = -0.62 while every other column reaches y = -0.81). Verified headlessly before the fix: col 15 = 9 dots rows 0-8, col 16 = 1 dot, bottom-row y spread col 14 vs 15 = 0.19 script units.
2339→- Sweep of all other floor(i*M) uses in the library (62 occurrences): every other one is benign -- angular presets close their loop (bar = bars lands exactly on bar 0's angle: seg*tau/segs with seg = segs = 2pi = 0), Aurora Veil's phantom lands off-screen (x = 1.19 > 1), the megabuf particle presets (Bass Bloom, Supernova) draw their phantom slot at alpha 0 (uninitialized megabuf reads 0), Strobe Lattice/Tunnel Vision/Prism Chandelier hide one endpoint dot in rotating/mirrored chaos, and the converted Winamp classics rendered identically under original AVS (which also uses inclusive i) -- their authors saw and accepted exactly this behavior. Beat Matrix was the only hand-authored ALIGNED grid where the defect is obvious, so it was the only one that needed the fix.
2340→
2341→Work Log:
2342→- embedded-presets.ts Beat Matrix [point]: the grid mapping now goes through CELL CENTERS -- cell = i * (cols * rows - 1) + 0.5, col = floor(cell / rows), row = floor(cell - col * rows). Because i = k/(n-1) over n = cols*rows points, cell = k + 0.5 exactly (up to 1-ulp dust), so every floor() sits half a cell away from an integer boundary: the endpoint can never spill and float dust can never shuffle a dot into a neighboring cell. getspec/x/y/hue all read col/row as before (col 0..15, row 0..9; the last point now lands at col 15 row 9, the author's original intent under i = k/n). A 6-line comment in the script documents the why.
2343→- EMBEDDED_SEED_VERSION 7.12 -> 7.13.1 (library re-seed replaces the DB's Beat Matrix; verified in SQLite: seed = 7.13.1, 106 presets, fixed content present, old mapping gone).
2344→- version.ts 7.13.1 + history entry; release-notes.ts 7.13.1 "Beat Matrix grid fixed" (fixed, first-person voice).
2345→
2346→HEADLESS VALIDATION (/home/z/tmp-validate/beatmatrix/validate.mts, ALL PASS — REAL parser/compiler, not a re-implementation):
2347→- Regression guard: all 101 embedded presets still compile.
2348→- The fixed Beat Matrix [point] program executed over all 160 points with the engine's exact i = k/(n-1): 160/160 cells occupied, ZERO duplicates, max col 15, max row 9, bottom-right cell (15,9) present, all 16 columns carry their full 10 rows, 16 distinct x symmetric about 0, 10 distinct y rows aligned.
2349→
2350→BROWSER E2E (agent-browser + 8-frame max-brightness composite + VLM, ALL PASS):
2351→- Fresh load: title "OVE -- Open Visualization Engine (v7.13.1)"; /api/presets re-seeded on the version gate; Beat Matrix loads (PTS 160 = 16x10) and plays on the demo track (FPS 57-60, BPM 133.5 locked).
2352→- Pixel lattice analysis of an 8-frame composite (captures the treble moments when the high-band columns light): exactly 16 dot columns detected, even 38-39 px gaps; the BOTTOM dot of every one of the 16 columns sits at the SAME pixel row (y = 619, spread 0 px) -- the row-9 position that only exists under the fix (the old code's col-15 lowest dot sat ~80 px higher).
2353→- Phantom-dot check: the old spill position (x ~722, top row) shows ZERO bright pixels across the composite (x 710-750 all 0); the only brightness right of the wall is column 15's own glow decaying monotonically to nothing by x = 710 (175 -> 45 -> 0 bright-pixel counts), i.e. additive-blend glow, not a dot. The fullscreen-overlay icon (x >= 757) is outside the lattice zone.
2354→- VLM on the composite: "16 columns"; bottom row fully lit across all 16 columns at the same height (clean straight bottom edge); no stray dot right of the rightmost column; no alignment defects.
2355→- What's New dialog: 7.13.1 "Beat Matrix grid fixed" first with CURRENT badge; drift guard silent (0 console errors / 0 warnings across the session); dev.log clean (200s only). Test-browser localStorage cleared afterwards.
2356→
2357→Stage Summary:
2358→- v7.13.1 shipped: Beat Matrix's wall is whole -- every column carries its full 10 dots, the bottom edge is straight across all 16 columns, and the phantom dot that spilled past the right edge is gone. The fix lives in the preset's grid math (cell-center mapping, immune to the inclusive-endpoint and float dust alike); the engine's AVS-correct i convention is untouched, and the library re-seed delivers the fixed preset to every visitor.
2359→

View file

@ -0,0 +1,435 @@
1→// OVE — app identity + version stamp.
2→//
3→// Single source of truth for the product name and version shown in the UI
4→// (header, footer, document title). Bump APP_VERSION whenever we ship a
5→// large change so the running build can always be identified at a glance —
6→// useful both for the z.ai Version History and for naming local backups
7→// (v6.0 = rename to Open Visualization Engine + version indicator).
8→//
9→// STANDING RULE (since v7.6): every APP_VERSION bump MUST come with a
10→// matching entry at the top of RELEASE_NOTES in src/lib/release-notes.ts —
11→// that list powers the header's "What's New!" dialog. A dev-mode guard
12→// warns in the console when the two drift apart.
13→//
14→// History:
15→// 7.13.1 — Beat Matrix endpoint fix (user report): the rightmost column
16→// of dots sat one row short -- its bottom dot missing -- while a
17→// phantom dot spilled one column past the wall's right edge at
18→// the top. Root cause: the engine's point position i spans 0..1
19→// INCLUSIVE (classic AVS Superscope convention, engine.ts: i =
20→// k/(n-1)), but Beat Matrix's grid math assumed exclusive i = k/n:
21→// floor(i*cols) turned the last point into col 16 (one past the
22→// 16-column wall) at row 0, and column 15 was left with nine
23→// dots (rows 0-8, no bottom). Fix: the script now maps through
24→// cell centers -- cell = i*(cols*rows-1)+0.5, col =
25→// floor(cell/rows), row = floor(cell-col*rows) -- which puts
26→// every floor() half a cell away from an integer boundary, so
27→// the endpoint can never spill and float dust can never shuffle
28→// a dot. Full 16x10 bijection verified headlessly (all 160
29→// points in 160 distinct cells, col<=15, row<=9, bottom-right
30→// cell present). Sweep of the other 100 presets: every other
31→// floor(i*M) use is benign -- angular presets close their loop
32→// (bar=bars lands exactly on bar 0's angle), Aurora Veil's
33→// phantom lands off-screen (x=1.19), the megabuf particle
34→// presets draw their phantom slot at alpha 0, and the converted
35→// Winamp classics rendered identically under original AVS
36→// (which also uses inclusive i). EMBEDDED_SEED_VERSION 7.12 ->
37→// 7.13.1 re-seeds the library so every visitor gets the fixed
38→// Beat Matrix.
39→// 7.13 — one build, every feature: the parallel development lines are
40→// merged. This tree now carries BOTH the community OVE-Directory
41→// (v7.11 here) AND the parallel line's additions — the spectrum
42→// 16 kHz cap (its 7.10.1), the screen wake lock + respectful
43→// Demo button + one-click Save (its 7.11, folded into this
44→// history as 7.10.2 to keep one clean timeline), and the
45→// AVS-style background movement family (bgrot / bgx / bgy /
46→// bgzoom) with the eleventh Zai-Magic preset "osc-rotations"
47→// (its 7.12). Git three-way merge against the shared v7.10
48→// ancestor (identical tree hashes verified on both sides); the
49→// only hand-merged surface was the Script tab toolbar, which
50→// now carries the one-click Save and "Upload to OVE-Directory"
51→// side by side, and the two changelogs (here + release-notes).
52→// 7.12 — background movement + osc-rotations. Scripts can now move the
53→// whole framebuffer every frame, the way the classic Winamp AVS
54→// plugins did: bgrot (radians/frame, + clockwise on screen),
55→// bgx / bgy (per-frame drift in the -1..1 screen convention, y
56→// up), bgzoom (< 1 draw-in, > 1 blow-out) -- read after [frame]/
57→// [beat] so this frame's values apply this frame. The engine
58→// snapshots the canvas into an offscreen buffer, wipes, and
59→// draws the snapshot back through the transform, so the
60→// persistence fade blends the moving trails: "speed accelerates
61→// to the beat, a hard hit flips the spin, fade to black stays
62→// slow" is pure script (a beatage envelope drives the rate; a
63→// [beat] section flips a dir variable on hard hits via bass vs
64→// bass_att). Neutral readings (0/0/0/1) skip the pass entirely
65→// (zero cost for every preset that doesn't move); non-finite
66→// values fall back to neutral (a NaN in a canvas transform
67→// matrix would black the screen with no error); per-frame
68→// clamps: rot ±0.6 rad, drift ±0.25, zoom 0.5..2. New 11th
69→// Zai-Magic preset "osc-rotations" (user-requested): a
70→// stationary centered oscilloscope (time-domain v) whose color
71→// is mirror-symmetric -- points equidistant left/right of
72→// center shift together, the center points hold their own hue
73→// -- over a background rotating cw/ccw to the music that
74→// temporarily accelerates on the beat; hard hits
75→// (bass > 1.25 × bass_att) flip the spin; a whisper of draw-in
76→// (bgzoom ~0.999) spirals the trails inward; persist 0.965
77→// keeps the fade slow so colors blend. Help panel: bg* variable
78→// rows + three new example formulas. EMBEDDED_SEED_VERSION
79→// 7.10 -> 7.12 (library re-seed adds the preset; the share
80→// codec's dictionary stays frozen per its compatibility
81→// contract -- bg* identifiers ride the pair packing like any
82→// custom variable). Headless validation of the preset's
83→// compiled programs: quiet 0.004 rad/frame, hard beat 0.026
84→// (6.5×) + direction flip, soft beat no flip, mirrored points
85→// share hue / center distinct
86→// 7.11 — the community OVE-Directory. A sixth tab (Directory) lists every
87→// script published to the community directory — a separate VPS at
88→// s3374dir.openvisengine.com, reached ONLY through this server's
89→// backend proxy (/api/ove-directory/*), which holds the API key in
90→// env and re-validates every upload (the share string must decode
91→// AND compile). Publishing: the Script tab gains "Upload to
92→// OVE-Directory" (enabled only while the editor shows ✔ Compiled OK
93→// with no runtime error); the script travels as its Script⇢Hash
94→// string, so the directory stores a fraction of the source. The
95→// listing carries each entry's name, type and date, a 1–5 star
96→// widget (the voter id is an HttpOnly cookie minted by the proxy;
97→// one vote per script per visitor, enforced upstream), the live
98→// "Average: #.#" to the right of the stars, and sorting by Name /
99→// Type / Date / Rating (done upstream, both directions). "Get"
100→// fetches the full record, decodes the hash back into the exact
101→// script, files it in this browser's preset tree under
102→// root/user created/OVE-Directory (content-deduped, names numbered
103→// "(1) (2) (3)…" on collision) and offers "Open in editor".
104→// Duplicate uploads resolve as success (409 DUPLICATE_HASH carries
105→// the existing row); duplicate votes show the stored aggregates.
106→// 7.10.2 — wake lock, a respectful Demo button, one-click save. While any
107→// audio source is live the site holds a Screen Wake Lock so phone
108→// and tablet screens stay on (released the moment the engine goes
109→// idle so the normal inactivity dimming returns; browsers silently
110→// drop the sentinel on hide, so a visibilitychange watcher
111→// re-acquires it on return while music is still going;
112→// unsupported browsers degrade silently). The Demo Track button no
113→// longer force-engages the Sequence checkbox: a visitor who loaded
114→// a preset (tree double-click / Load / Copy to my presets / created
115→// one), brought their own script material into the editor (typed,
116→// pasted, Hash⇢Script, file), saved their own default startup
117→// script, or runs their own Random/Sequence mix keeps their
118→// selection -- Demo just plays the track (the showcase's tree
119→// re-scope, 20 s interval and retire-on-end all skip too; a new
120→// per-visit manualChoice flag + a boot-script snapshot decide, and
121→// ensureDefaultPreset gained the same guard so mic/file/link never
122→// clobber a custom draft either; the showcase now only starts for
123→// a visit that never picked or typed anything). Script tab: a valid
124→// script shows the Save button with NO save target needed -- one
125→// click creates a preset under "user created", auto-named from the
126→// script's name: header (a hash import of "Spectrum Bars:[▼…]"
127→// saves as "Spectrum Bars"), "Empty Name" when nameless, " (1)"/
128→// " (2)"… suffixes on conflicts, and whenever the name had to be
129→// invented a "Give This Preset a Name" dialog opens to rename the
130→// just-saved preset in one step (the preset is always saved FIRST,
131→// renamed second, so nothing is ever lost to a naming problem).
132→// Hash⇢Script imports clear the stale save target (the editor now
133→// holds foreign content) and pass the decoded label through as the
134→// save-name fallback when the script has no name: header
135→// 7.10.1 — the frozen right edge of spectrum visuals. getspec()/sv mapped
136→// the bar field across the whole FFT (bin 2 ... Nyquist, ~12 Hz to
137→// 24 kHz), but music carries almost nothing above ~16 kHz and every
138→// lossy source low-passes even lower (192 kbps MP3 at ~18.6 kHz,
139→// YouTube AAC at ~15.5 kHz; measured across the demo collection:
140→// 0.000% of total magnitude above 18.6 kHz), so the rightmost ~20%
141→// of every spectrum visual read a permanent zero -- bars that never
142→// moved. getSpectrum() now tops the field out at 16 kHz
143→// (SPEC_TOP_HZ, matching the spectral-flux cap in getBands()), so
144→// the right edge lands on the 12-16 kHz "air" band where cymbals,
145→// hats and synth sparkle live. rust-agent's spectrum_at() mirrors
146→// the change, and the help panel's sv entry now states the span.
147→// 7.10 — ten demo tracks + first-person changelog + declutter. The demo
148→// source is now a COLLECTION: ten mastered tracks in
149→// public/demo-tracks/ (demo-01.mp3 … demo-10.mp3, filename order
150→// 1→10, replacing the single Neural Mecha Pulse file). Each Demo
151→// click plays the visitor's PLACE in the collection once through;
152→// the place advances when a pass truly ends — natural finish or
153→// the Stop button ('ended'/'stop' teardown reasons, a new
154→// onDemoEnded signature) — and wraps 10→1; switching to another
155→// source keeps the place. The place persists per visitor in
156→// localStorage (ove.demoTrack.next), so returning picks up where
157→// they left off. The engine caches one decoded buffer at a time,
158→// keyed by track index (~50–60 MB PCM each — all ten would be half
159→// a gigabyte). The header chip + footer SRC label show the current
160→// track's name (Demo Track N). RELEASE_NOTES rewritten in the
161→// operator's first-person voice (no more third-person marketing
162→// copy or addressing the visitor), and every em dash in the
163→// interface replaced with a plain double minus ( -- ) — including
164→// the embedded preset library's descriptions and script comments
165→// (EMBEDDED_SEED_VERSION 7.01 → 7.10 re-seed). Declutter: the
166→// landing menu's source list line, the presets panel's two
167→// read-only paragraphs, the Random/Sequence hint line, the empty
168→// user-folder note reworded, the Settings theme/highlight/Native
169→// paragraphs, the link dialog's privacy footnote and the footer's
170→// engine-ok dot are all gone — compile errors still toast, so the
171→// always-green badge was noise
172→// 7.9 — footer credit + What's New polish. The footer's blank middle now
173→// carries the maker's signature: "© {year} · Site Created &
174→// Deployed by Sum'ting White" (year generated from the clock,
175→// hydration-guarded) with a "View my portfolio at zcreations.dev"
176→// link that opens zcreations.dev in a new tab — centered in the
177→// blank area from xl (mx-auto between the stats and the version
178→// stamp), dropping to its own centered row on narrower screens so
179→// nothing ever crowds. The What's New dialog got a typographic
180→// tidy-up: a hairline divider above every release box
181→// (border-zinc-800 — a ramp step, so it matches every base theme
182→// through the globals.css remaps), and each change row became an
183→// invisible two-column grid — the kind tag top-right justified
184→// against the column boundary, the description top-left with word
185→// wrap — so all descriptions start on the same pixel column
186→// 7.8 — share strings 2.0: ~72% shorter than the script (was ~49%). The
187→// base-62 idea, cranked to 11,172… 32,164: after the symbol
188→// dictionary (which grew ~170 data-mined entries — every function
189→// WITH its open paren, every engine variable, the AVS idioms
190→// "hue = hue + dt * " and "t = t + dt * ", " * 0.", ") * ",
191→// blank-line+section skeletons, "linewidth: " / "blend: additive"
192→// headers, ~70 number literals, and the library's common
193→// variable names incl. chroma) the whole body is read as ONE BIG
194→// NUMBER and rewritten in base 32,164 — one digit per character
195→// from the CJK + Hangul blocks, ~15 bits a character vs base-62's
196→// 5.95 (so "1400" costs ~0.85 of a character). The decoder gets
197→// the body's alphabet back from a ~32-character bitmap header
198→// instead of ~80 literal symbols. Short scripts where the header
199→// wouldn't pay keep the v7.7 symbol form (encoder picks whichever
200→// is shorter); ▲ strings from v7.7 still decode; still lossless
201→// for ANY text, still copy-safe, still self-checking. Corpus
202→// measure: median share string is 27% of the script's length
203→// (best 22%), e.g. Bass Bloom 1341 → 326 characters
204→// 7.7 — script sharing + settings declutter. Script⇢Hash / Hash⇢Script:
205→// two buttons in the Script tab turn the editor's script into ONE
206→// short shareable Unicode string ("Bass Bloom:[▲…①①①①①①①①]") and
207→// paste one back — the script returns exactly as written (lossless
208→// for ANY text, compiling NOT required, so WIP scripts can be
209→// shared for debugging). The string is built from built-in symbol
210→// references (♤ = line return, ♡ = beats, ♠ = beatage, ♦ = space,
211→// ♩♪♫♬ = the four sections, one symbol per function/variable, plus
212→// a pair-packing layer that folds leftover identifier/number text
213→// two chars per CJK code point) — ~50% shorter than the script on
214→// real presets. Copy-safe by construction (no raw whitespace or
215→// control chars; platform-injected variation selectors / zero-
216→// widths stripped on paste) and self-checking: 8 check digits (an
217→// FNV-1a digest rendered as ①–⑯) reject strings that were cut off
218→// by a character limit or altered in transit, instead of decoding
219→// into garbage. Also: the Music Services log in / "log out of all"
220→// section in Settings is parked (MUSIC_SERVICES_UI flag) — the
221→// built-in house account already powers Stream-a-Link for
222→// everyone; the section returns reworked in a later update
223→// 7.6.1 — header declutter: the Set Beat button is gone from the header
224→// (tap-tempo lives in the Beat tab, and the Space shortcut works
225→// anywhere — both unchanged). The beat indicator dot stays.
226→// 7.6 — "What's New!" dialog: a Sparkles button in the header (left of
227→// the theme switch) opens the visitor-facing changelog — every
228→// release from v4.0 on, newest first, each with one-line Added /
229→// Improved / Fixed / Removed notes (src/lib/release-notes.ts,
230→// color-coded tags, the running version badged "current",
231→// scrollable with the thin scrollbar). A small emerald dot on the
232→// button marks updates the visitor hasn't seen yet — per visitor
233→// in localStorage, cleared on open (mount-guarded, no hydration
234→// mismatch). Standing rule added: version bumps ship with their
235→// release note; a dev-mode guard warns when they drift
236→// 7.5.1 — Link dialog width fix: text no longer escapes the dialog box.
237→// Root cause: Radix dialogs lay their children in an implicit CSS
238→// grid whose single column sizes to the widest child's min-content;
239→// the RECENT LINKS rows carry truncate spans (white-space: nowrap),
240→// and Chromium measures a nowrap flex item's full text width for
241→// that measurement — so a long saved title (e.g. "Bobby Foxx — This
242→// Is Why We Can't Have Nice Things (Official Music Video)") blew
243→// the column ~40 px past the 448 px dialog, and EVERY child (title,
244→// description, input + Load, rows, footer) laid out beyond the
245→// right border. Fix: the shared Dialog/AlertDialog content now pins
246→// the column to minmax(0,1fr) — capped at the available width, so
247→// no nowrap content can ever stretch a dialog again (covers every
248→// dialog app-wide) — the Link dialog widened to max-w-lg for
249→// comfier wrapping, and min-w-0 + break-words added on the
250→// recents/playlist containers and error text as belt-and-braces
251→// 7.5 — yt-dlp compatibility: single tracks resolve by DOWNLOAD + CONVERT
252→// instead of proxying the extractor's stream URL. The old stream
253→// URLs were IP-locked (googlevideo bakes in the resolver's IP),
254→// expired within hours, and arrived as webm/opus — a container
255→// Safari & co. refuse ("The media resource … was not suitable").
256→// The server now runs the operator's pipeline per track:
257→// yt-dlp -f bestaudio/best -x --audio-format mp3
258→// --audio-quality 0 -o "<dir>/%(title)s.%(ext)s" URL
259→// — audio-only download, universal MP3 at VBR-0 (~245 kbps), the
260→// video's real title preserved for the Playing: label. The
261→// finished file streams same-origin with full Range support from
262→// a per-track workspace dir (30-min sliding TTL + orphan sweeper);
263→// /api/audio/stream gained a file-serving mode. Hardening around
264→// it: shared failure classifier for both yt-dlp passes (metadata +
265→// download), 180 s download budget, 300 MB cap, bot-wall/stale-
266→// extractor answers unchanged, ffmpeg-missing degrades to the old
267→// proxy path (logged once), queue look-ahead lead 15 s → 60 s so
268→// playlist transitions don't stall behind conversions
269→// 7.4 — Sequence mode: a second mix checkbox next to Random. Ticked, it
270→// cycles the scope folder's presets IN ORDER (the tree's exact
271→// top-to-bottom order) instead of shuffling — and when it moves
272→// past the last preset it wraps back to the first, so the folder
273→// loops forever. Random and Sequence are mutually exclusive
274→// (ticking either one unticks the other; both share the same
275→// delay and folder scope), Random now never loads the same preset
276→// twice in a row, and Sequence holds its breath through silence
277→// exactly like Random does. The Demo showcase now runs SEQUENCE —
278→// the one play-through walks every Zai-Magic preset in order
279→// (20 s each) rather than repeating random picks, and when the
280→// demo stops, whichever mode it checked is unchecked again
281→// 7.3 — demo-flow refinements: the Demo Track is a single pass — it plays
282→// "Neural Mecha Pulse" once through and stops (a demo, not a radio
283→// station). However it ends (natural finish, Stop, or switching to
284→// another source) the showcase unwinds: the randomizer the Demo
285→// flow force-checked is unchecked again, and the visitor lands
286→// back on the "Select an audio source" overlay. Preset-change
287→// popups are gone ("Preset loaded" / "Random preset" / "Default
288→// preset running") — the footer's SCRIPT: label already echoes
289→// every change, so the toasts were pure intrusion; only compile
290→// errors still toast. Club-mode randomizer now respects silence:
291→// when no music is playing it never re-shuffles the selected
292→// preset, even with the checkbox on — it waits for the next track
293→// 7.2.1 — Supernova (Zai-Magic) preset fix: the particle kill condition
294→// (|px|+|py| > 2.4) was physically unreachable — drag caps a
295→// particle's total travel at vel/1.6 ≈ 1.0, so nothing ever
296→// crossed 1.4, nothing ever died, and since respawning requires a
297→// dead particle, the per-beat "budget = n" detonation could never
298→// fire after the initial one — the preset exploded once on load,
299→// then faded to permanent black. Now every beat force-clears the
300→// whole 620-particle field in [beat] (guaranteed full re-detonation
301→// on the very same frame), fully-cooled particles die by fade so
302→// long beat gaps leave a gentle ember drizzle instead of black,
303→// and each blast re-randomizes its geometry (no two explosions
304→// alike). Embedded library re-seeded (seed marker 7.01)
305→// 7.2 — new-visitor showcase flow. Defaults for first-time visitors:
306→// the Black + Purple Outline theme with the Blue highlight
307→// (previously royal purple + yellow), and Zai-Magic "Bass Bloom"
308→// as the startup preset (previously the first Synth-C classic).
309→// The idle overlay's Demo Track button now carries an animated
310→// reflective shimmer (skewed light band sweeping left→right every
311→// 3.2 s, reduced-motion safe) to draw the click — and that one
312→// click starts the full showcase: the demo track plays while the
313→// preset tree selects + expands Zai-Magic, randomize switches on
314→// scoped to that folder with a 20-second change interval. Music
315→// started with NO preset active (own draft running / selection
316→// cleared) auto-loads Bass Bloom. Preset changes — manual load,
317→// the random mix, the Demo flow — no longer hard-cut: the engine
318→// snapshots the outgoing frame and blur-dissolves it into the new
319→// preset over 700 ms (progressive blur + easeOutCubic fade + a
320→// slight scale-up so the softening edges never gap; plain
321→// crossfade where ctx.filter is unsupported)
322→// 7.1 — real demo track + a beat detector that survives real music.
323→// The Demo button now plays "Neural Mecha Pulse" (the operator's
324→// mastered industrial-EDM banger, public/demo-track.mp3, loops
325→// gaplessly) instead of the synthetic techno pattern — a real
326→// recording is the honest test: deep sub for the bass bands,
327→// driving mids, crisp highs, and a kick buried in sustained
328→// sub-bass. That last part exposed the 6.x detector as fundamentally
329→// broken on mastered music: a LEVEL threshold can never see the
330→// kick through the sub (peak-to-mean caps at ~1.2× → sporadic
331→// fires, phantom 120-BPM locks from the minInterval floor).
332→// v7.1 rewrites detection the way real beat trackers work
333→// (aubio/librosa-style): a full-band spectral-flux ONSET envelope
334→// → autocorrelation over 300–1000 ms lags with a log-BPM prior →
335→// comb-filter phase with grid hysteresis → beats fired on an
336→// absolute grid kept glued by a PLL pull. Headlessly validated
337→// against the actual track PCM (AnalyserNode chain replicated
338→// frame-for-frame): locks the true ~133 BPM (the song drifts
339→// 130.7→133.1 — the grid TRACKS it) in 1.9 s, 92% beat-gap
340→// regularity, confidence 0.99 through the body; techno/hip-hop
341→// patterns lock exactly; silence yields zero beats. Known limit:
342→// sparse kick-vs-snare backbeats (dnb) may lock half-tempo —
343→// stable, and two taps of Set Beat correct it. Visitor-stored
344→// beat configs migrate (floorLevel changed units, level → flux).
345→// The demo BPM slider is gone (a real track's tempo is detected,
346→// not dialed in) — replaced by a track-name chip in the header
347→// 7.00 — Zai-Magic: ten hand-authored presets in root/embedded/Zai-Magic
348→// built around BEAT-SYNCED COLOR — the color wheel turns on the
349→// kick, palettes swap per beat / per 4-beat bar, megabuf particles
350→// remember the hue of the beat that spawned them + new script
351→// tools: hsvr/hsvg/hsvb (HSV→RGB channels), smoothstep and the
352→// beatage kick-envelope variable — all documented in the help
353→// panel. (Numbered 7.00 rather than 6.10 — a new preset family
354→// plus new script-language features is a major release; 6.9.3 was
355→// the last patch of the 6.x line.) Beat engine fixes underneath so
356→// the Demo track actually
357→// locks tempo (was sporadic): demo synth remixed for detection
358→// (hot kick owning the 20–100 Hz band, off-beat bassline voiced
359→// C3+ with a sidechain pump — chronological envelope events!),
360→// and the detector's default threshold 1.4 → 1.2 (the 170 ms FFT
361→// window caps a clean kick's peak-to-mean at ~1.5×, so 1.4 fired
362→// only sporadically and the BPM never locked)
363→// 6.9.3 — canonical domain fix: metadataBase/og:url/og:image pointed at
364→// openvisualengine.com (a DEAD domain baked in by 6.9.1) while the
365→// real site is openvisengine.com — Facebook's "corrupted image"
366→// error was its crawler fetching the image from a host that serves
367→// nothing; all share URLs now use the correct short domain
368→// 6.9.2 — share-image fix: og:image re-encoded as BASELINE JPEG (the
369→// 6.9.1 progressive encoding rendered fine in every browser but
370→// Facebook's Sharing Debugger rejected it as "corrupted"), swapped
371→// in the title-card artwork (gradient wordmark over three
372→// visualizations) and added a ?v=2 cache-bust so crawlers fetch it
373→// 6.9.1 — social share preview: Open Graph + Twitter Card metadata with
374→// a 1200×630 screenshot of the app (public/og-image.jpg) — sharing
375→// openvisualengine.com on Facebook/X/WhatsApp/Discord now shows the
376→// big image card instead of a bare link
377→// 6.9 — house account: anonymous visitors play YouTube links through
378→// the operator's shared disposable-account cookie (server-side
379→// fallback under secrets/, never exposed) — YouTube bot walls stop
380→// applying to guests; visitor's own login always wins. Engine fix
381→// underneath: Deno runtime shipped in bin/ (YouTube requires a JS
382→// runtime for signature/n-challenge solving on authenticated
383→// sessions — without it, logged-in extractions return no formats)
384→// 6.8.2 — login friction cut to ~4 clicks: the exported cookies.txt /
385→// Cookie-Editor JSON file can be dragged straight onto the
386→// login box (or picked via “Import the exported file…”) — no
387→// opening the file, no copy/paste; “Log out” / sign-out
388→// revocation note added (the official Google OAuth flow can't
389→// power the site: Google's APIs never hand out stream URLs and
390→// restricted-scope verification would reject an audio player)
391→// 6.8.1 — cookie login made foolproof: the login dialog recognizes raw
392→// Cookie headers, cookies.txt exports AND Cookie-Editor JSON,
393→// validates the paste LIVE through one shared parser (a single
394→// cookie's value — like a bare LOGIN_INFO string — gets an honest
395→// "this will not log you in" warning), and the how-to steps lead
396→// with the one-click extension export for Chrome AND Firefox
397→// 6.8 — self-healing audio engine: when YouTube changes their mechanics
398→// the server detects the stale extractor, updates yt-dlp in the
399→// background (verified GitHub release download, atomic swap) and the
400→// player retries seamlessly behind an "Updating in Background"
401→// notice; bot walls answer "Google login required…" with an Open
402→// Settings action, and unfixable failures get the honest
403→// "A back-end problem has occurred. Please try again later."
404→// 6.7 — lazy playlist queue: a playlist link becomes a queue of URLs that
405→// streams ONE song at a time (each track is resolved by yt-dlp only
406→// right before it plays — next-track look-ahead at ≤15 s to go),
407→// queue bar with skip/jump/replay + server-side caps (max 2 parallel
408→// extractions); music-service framework: Spotify + Apple Music are
409→// registered providers whose playback ships in a later update
410→// (logins already save, links answer with an honest notice)
411→// 6.6 — music service logins (Settings tab): YouTube / YouTube Music,
412→// SoundCloud, Spotify, Apple Music cookie login, encrypted on the
413→// visitor's computer; Link button gains playlist picking + uses the
414→// login to bypass bot walls
415→// 6.5 — Settings tab (replaces the parked Native tab): theme picker with
416→// base chrome (Royal Purple / Matte Black / Black + Purple Outline /
417→// Light) × selectable highlight color (Purple, Yellow, Blue, Green,
418→// Red, Orange), all per-visitor; simple OVE logo as the site favicon
419→// 6.4 — beat detection suspends when no music is playing/loaded (no ghost
420→// beats after Stop, BPM resets) + dark theme restyle: royal purple
421→// chrome with light-yellow highlights
422→// 6.3 — light/dark theme tick switch in the header (white theme via .light
423→// palette remap; per-visitor, persisted by next-themes)
424→// 6.2 — security hardening: read-only embedded library (server refuses all
425→// writes) + per-visitor "user created" presets stored in the browser
426→// 6.1 — preset library quality pass: every embedded stand-in is now a UNIQUE
427→// generated visual (16 families × seeded parameters), approx badge
428→// 6.0 — renamed to "Open Visualization Engine" + footer version stamp
429→// 5.0 — folder-tree Presets page (Task 9–11 state, restored in Task 12)
430→// 4.0 — link audio source (yt-dlp resolve + stream proxy)
431→
432→export const APP_NAME = 'Open Visualization Engine'
433→export const APP_SHORT = 'OVE'
434→export const APP_VERSION = '7.13.1'
435→

0
tool-results/v711-01-fresh-home.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

0
tool-results/v711-02-fresh-demo.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 194 KiB

After

Width:  |  Height:  |  Size: 194 KiB

0
tool-results/v711-03-preset-loaded.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

0
tool-results/v711-04-demo-with-manual.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

0
tool-results/v711-05-demo-custom-material.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

0
tool-results/v711-06-seq-unchecked.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

0
tool-results/v711-07-state-check.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 134 KiB

0
tool-results/v711-08-whats-new.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 134 KiB

0
tool-results/v711-09-decoded.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 107 KiB

0
tool-results/v711-10-imported.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

0
tool-results/v711-11-saved-named.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

0
tool-results/v711-12-empty-name-dialog.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 99 KiB

After

Width:  |  Height:  |  Size: 99 KiB

0
tool-results/v711-13-renamed.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

0
tool-results/v711-14-rename-conflict.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 97 KiB

After

Width:  |  Height:  |  Size: 97 KiB

0
tool-results/v711-15-empty-name-1.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

0
tool-results/v711-16-suffix-conflict.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 100 KiB

0
tool-results/v711-17-named-dup.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 102 KiB

0
tool-results/v711-18-default-boot.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 94 KiB

0
tool-results/v711-19-default-demo.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

0
tool-results/v711-20-final-fresh.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB

0
tool-results/v711-21-mobile.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

0
tool-results/v711-22-desktop.png Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 125 KiB