openvisengine/tool-results/read_1793921017322_9c38b72c422b.txt
2026-11-05 23:35:41 +00:00

454 lines
No EOL
36 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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