openvisengine/src/lib/version.ts
2026-11-05 06:53:07 +00:00

322 lines
23 KiB
TypeScript
Executable file
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.

// OVE — app identity + version stamp.
//
// Single source of truth for the product name and version shown in the UI
// (header, footer, document title). Bump APP_VERSION whenever we ship a
// large change so the running build can always be identified at a glance —
// useful both for the z.ai Version History and for naming local backups
// (v6.0 = rename to Open Visualization Engine + version indicator).
//
// STANDING RULE (since v7.6): every APP_VERSION bump MUST come with a
// matching entry at the top of RELEASE_NOTES in src/lib/release-notes.ts —
// that list powers the header's "What's New!" dialog. A dev-mode guard
// warns in the console when the two drift apart.
//
// History:
// 7.11 — the community OVE-Directory. A sixth tab (Directory) lists every
// script published to the community directory — a separate VPS at
// s3374dir.openvisengine.com, reached ONLY through this server's
// backend proxy (/api/ove-directory/*), which holds the API key in
// env and re-validates every upload (the share string must decode
// AND compile). Publishing: the Script tab gains "Upload to
// OVE-Directory" (enabled only while the editor shows ✔ Compiled OK
// with no runtime error); the script travels as its Script⇢Hash
// string, so the directory stores a fraction of the source. The
// listing carries each entry's name, type and date, a 1–5 star
// widget (the voter id is an HttpOnly cookie minted by the proxy;
// one vote per script per visitor, enforced upstream), the live
// "Average: #.#" to the right of the stars, and sorting by Name /
// Type / Date / Rating (done upstream, both directions). "Get"
// fetches the full record, decodes the hash back into the exact
// script, files it in this browser's preset tree under
// root/user created/OVE-Directory (content-deduped, names numbered
// "(1) (2) (3)…" on collision) and offers "Open in editor".
// Duplicate uploads resolve as success (409 DUPLICATE_HASH carries
// the existing row); duplicate votes show the stored aggregates.
// 7.10 — ten demo tracks + first-person changelog + declutter. The demo
// source is now a COLLECTION: ten mastered tracks in
// public/demo-tracks/ (demo-01.mp3 … demo-10.mp3, filename order
// 1→10, replacing the single Neural Mecha Pulse file). Each Demo
// click plays the visitor's PLACE in the collection once through;
// the place advances when a pass truly ends — natural finish or
// the Stop button ('ended'/'stop' teardown reasons, a new
// onDemoEnded signature) — and wraps 10→1; switching to another
// source keeps the place. The place persists per visitor in
// localStorage (ove.demoTrack.next), so returning picks up where
// they left off. The engine caches one decoded buffer at a time,
// keyed by track index (~50–60 MB PCM each — all ten would be half
// a gigabyte). The header chip + footer SRC label show the current
// track's name (Demo Track N). RELEASE_NOTES rewritten in the
// operator's first-person voice (no more third-person marketing
// copy or addressing the visitor), and every em dash in the
// interface replaced with a plain double minus ( -- ) — including
// the embedded preset library's descriptions and script comments
// (EMBEDDED_SEED_VERSION 7.01 → 7.10 re-seed). Declutter: the
// landing menu's source list line, the presets panel's two
// read-only paragraphs, the Random/Sequence hint line, the empty
// user-folder note reworded, the Settings theme/highlight/Native
// paragraphs, the link dialog's privacy footnote and the footer's
// engine-ok dot are all gone — compile errors still toast, so the
// always-green badge was noise
// 7.9 — footer credit + What's New polish. The footer's blank middle now
// carries the maker's signature: "© {year} · Site Created &
// Deployed by Sum'ting White" (year generated from the clock,
// hydration-guarded) with a "View my portfolio at zcreations.dev"
// link that opens zcreations.dev in a new tab — centered in the
// blank area from xl (mx-auto between the stats and the version
// stamp), dropping to its own centered row on narrower screens so
// nothing ever crowds. The What's New dialog got a typographic
// tidy-up: a hairline divider above every release box
// (border-zinc-800 — a ramp step, so it matches every base theme
// through the globals.css remaps), and each change row became an
// invisible two-column grid — the kind tag top-right justified
// against the column boundary, the description top-left with word
// wrap — so all descriptions start on the same pixel column
// 7.8 — share strings 2.0: ~72% shorter than the script (was ~49%). The
// base-62 idea, cranked to 11,172… 32,164: after the symbol
// dictionary (which grew ~170 data-mined entries — every function
// WITH its open paren, every engine variable, the AVS idioms
// "hue = hue + dt * " and "t = t + dt * ", " * 0.", ") * ",
// blank-line+section skeletons, "linewidth: " / "blend: additive"
// headers, ~70 number literals, and the library's common
// variable names incl. chroma) the whole body is read as ONE BIG
// NUMBER and rewritten in base 32,164 — one digit per character
// from the CJK + Hangul blocks, ~15 bits a character vs base-62's
// 5.95 (so "1400" costs ~0.85 of a character). The decoder gets
// the body's alphabet back from a ~32-character bitmap header
// instead of ~80 literal symbols. Short scripts where the header
// wouldn't pay keep the v7.7 symbol form (encoder picks whichever
// is shorter); ▲ strings from v7.7 still decode; still lossless
// for ANY text, still copy-safe, still self-checking. Corpus
// measure: median share string is 27% of the script's length
// (best 22%), e.g. Bass Bloom 1341 → 326 characters
// 7.7 — script sharing + settings declutter. Script⇢Hash / Hash⇢Script:
// two buttons in the Script tab turn the editor's script into ONE
// short shareable Unicode string ("Bass Bloom:[▲…①①①①①①①①]") and
// paste one back — the script returns exactly as written (lossless
// for ANY text, compiling NOT required, so WIP scripts can be
// shared for debugging). The string is built from built-in symbol
// references (♤ = line return, ♡ = beats, ♠ = beatage, ♦ = space,
// ♩♪♫♬ = the four sections, one symbol per function/variable, plus
// a pair-packing layer that folds leftover identifier/number text
// two chars per CJK code point) — ~50% shorter than the script on
// real presets. Copy-safe by construction (no raw whitespace or
// control chars; platform-injected variation selectors / zero-
// widths stripped on paste) and self-checking: 8 check digits (an
// FNV-1a digest rendered as ①–⑯) reject strings that were cut off
// by a character limit or altered in transit, instead of decoding
// into garbage. Also: the Music Services log in / "log out of all"
// section in Settings is parked (MUSIC_SERVICES_UI flag) — the
// built-in house account already powers Stream-a-Link for
// everyone; the section returns reworked in a later update
// 7.6.1 — header declutter: the Set Beat button is gone from the header
// (tap-tempo lives in the Beat tab, and the Space shortcut works
// anywhere — both unchanged). The beat indicator dot stays.
// 7.6 — "What's New!" dialog: a Sparkles button in the header (left of
// the theme switch) opens the visitor-facing changelog — every
// release from v4.0 on, newest first, each with one-line Added /
// Improved / Fixed / Removed notes (src/lib/release-notes.ts,
// color-coded tags, the running version badged "current",
// scrollable with the thin scrollbar). A small emerald dot on the
// button marks updates the visitor hasn't seen yet — per visitor
// in localStorage, cleared on open (mount-guarded, no hydration
// mismatch). Standing rule added: version bumps ship with their
// release note; a dev-mode guard warns when they drift
// 7.5.1 — Link dialog width fix: text no longer escapes the dialog box.
// Root cause: Radix dialogs lay their children in an implicit CSS
// grid whose single column sizes to the widest child's min-content;
// the RECENT LINKS rows carry truncate spans (white-space: nowrap),
// and Chromium measures a nowrap flex item's full text width for
// that measurement — so a long saved title (e.g. "Bobby Foxx — This
// Is Why We Can't Have Nice Things (Official Music Video)") blew
// the column ~40 px past the 448 px dialog, and EVERY child (title,
// description, input + Load, rows, footer) laid out beyond the
// right border. Fix: the shared Dialog/AlertDialog content now pins
// the column to minmax(0,1fr) — capped at the available width, so
// no nowrap content can ever stretch a dialog again (covers every
// dialog app-wide) — the Link dialog widened to max-w-lg for
// comfier wrapping, and min-w-0 + break-words added on the
// recents/playlist containers and error text as belt-and-braces
// 7.5 — yt-dlp compatibility: single tracks resolve by DOWNLOAD + CONVERT
// instead of proxying the extractor's stream URL. The old stream
// URLs were IP-locked (googlevideo bakes in the resolver's IP),
// expired within hours, and arrived as webm/opus — a container
// Safari & co. refuse ("The media resource … was not suitable").
// The server now runs the operator's pipeline per track:
// yt-dlp -f bestaudio/best -x --audio-format mp3
// --audio-quality 0 -o "<dir>/%(title)s.%(ext)s" URL
// — audio-only download, universal MP3 at VBR-0 (~245 kbps), the
// video's real title preserved for the Playing: label. The
// finished file streams same-origin with full Range support from
// a per-track workspace dir (30-min sliding TTL + orphan sweeper);
// /api/audio/stream gained a file-serving mode. Hardening around
// it: shared failure classifier for both yt-dlp passes (metadata +
// download), 180 s download budget, 300 MB cap, bot-wall/stale-
// extractor answers unchanged, ffmpeg-missing degrades to the old
// proxy path (logged once), queue look-ahead lead 15 s → 60 s so
// playlist transitions don't stall behind conversions
// 7.4 — Sequence mode: a second mix checkbox next to Random. Ticked, it
// cycles the scope folder's presets IN ORDER (the tree's exact
// top-to-bottom order) instead of shuffling — and when it moves
// past the last preset it wraps back to the first, so the folder
// loops forever. Random and Sequence are mutually exclusive
// (ticking either one unticks the other; both share the same
// delay and folder scope), Random now never loads the same preset
// twice in a row, and Sequence holds its breath through silence
// exactly like Random does. The Demo showcase now runs SEQUENCE —
// the one play-through walks every Zai-Magic preset in order
// (20 s each) rather than repeating random picks, and when the
// demo stops, whichever mode it checked is unchecked again
// 7.3 — demo-flow refinements: the Demo Track is a single pass — it plays
// "Neural Mecha Pulse" once through and stops (a demo, not a radio
// station). However it ends (natural finish, Stop, or switching to
// another source) the showcase unwinds: the randomizer the Demo
// flow force-checked is unchecked again, and the visitor lands
// back on the "Select an audio source" overlay. Preset-change
// popups are gone ("Preset loaded" / "Random preset" / "Default
// preset running") — the footer's SCRIPT: label already echoes
// every change, so the toasts were pure intrusion; only compile
// errors still toast. Club-mode randomizer now respects silence:
// when no music is playing it never re-shuffles the selected
// preset, even with the checkbox on — it waits for the next track
// 7.2.1 — Supernova (Zai-Magic) preset fix: the particle kill condition
// (|px|+|py| > 2.4) was physically unreachable — drag caps a
// particle's total travel at vel/1.6 ≈ 1.0, so nothing ever
// crossed 1.4, nothing ever died, and since respawning requires a
// dead particle, the per-beat "budget = n" detonation could never
// fire after the initial one — the preset exploded once on load,
// then faded to permanent black. Now every beat force-clears the
// whole 620-particle field in [beat] (guaranteed full re-detonation
// on the very same frame), fully-cooled particles die by fade so
// long beat gaps leave a gentle ember drizzle instead of black,
// and each blast re-randomizes its geometry (no two explosions
// alike). Embedded library re-seeded (seed marker 7.01)
// 7.2 — new-visitor showcase flow. Defaults for first-time visitors:
// the Black + Purple Outline theme with the Blue highlight
// (previously royal purple + yellow), and Zai-Magic "Bass Bloom"
// as the startup preset (previously the first Synth-C classic).
// The idle overlay's Demo Track button now carries an animated
// reflective shimmer (skewed light band sweeping left→right every
// 3.2 s, reduced-motion safe) to draw the click — and that one
// click starts the full showcase: the demo track plays while the
// preset tree selects + expands Zai-Magic, randomize switches on
// scoped to that folder with a 20-second change interval. Music
// started with NO preset active (own draft running / selection
// cleared) auto-loads Bass Bloom. Preset changes — manual load,
// the random mix, the Demo flow — no longer hard-cut: the engine
// snapshots the outgoing frame and blur-dissolves it into the new
// preset over 700 ms (progressive blur + easeOutCubic fade + a
// slight scale-up so the softening edges never gap; plain
// crossfade where ctx.filter is unsupported)
// 7.1 — real demo track + a beat detector that survives real music.
// The Demo button now plays "Neural Mecha Pulse" (the operator's
// mastered industrial-EDM banger, public/demo-track.mp3, loops
// gaplessly) instead of the synthetic techno pattern — a real
// recording is the honest test: deep sub for the bass bands,
// driving mids, crisp highs, and a kick buried in sustained
// sub-bass. That last part exposed the 6.x detector as fundamentally
// broken on mastered music: a LEVEL threshold can never see the
// kick through the sub (peak-to-mean caps at ~1.2× → sporadic
// fires, phantom 120-BPM locks from the minInterval floor).
// v7.1 rewrites detection the way real beat trackers work
// (aubio/librosa-style): a full-band spectral-flux ONSET envelope
// → autocorrelation over 300–1000 ms lags with a log-BPM prior →
// comb-filter phase with grid hysteresis → beats fired on an
// absolute grid kept glued by a PLL pull. Headlessly validated
// against the actual track PCM (AnalyserNode chain replicated
// frame-for-frame): locks the true ~133 BPM (the song drifts
// 130.7→133.1 — the grid TRACKS it) in 1.9 s, 92% beat-gap
// regularity, confidence 0.99 through the body; techno/hip-hop
// patterns lock exactly; silence yields zero beats. Known limit:
// sparse kick-vs-snare backbeats (dnb) may lock half-tempo —
// stable, and two taps of Set Beat correct it. Visitor-stored
// beat configs migrate (floorLevel changed units, level → flux).
// The demo BPM slider is gone (a real track's tempo is detected,
// not dialed in) — replaced by a track-name chip in the header
// 7.00 — Zai-Magic: ten hand-authored presets in root/embedded/Zai-Magic
// built around BEAT-SYNCED COLOR — the color wheel turns on the
// kick, palettes swap per beat / per 4-beat bar, megabuf particles
// remember the hue of the beat that spawned them + new script
// tools: hsvr/hsvg/hsvb (HSV→RGB channels), smoothstep and the
// beatage kick-envelope variable — all documented in the help
// panel. (Numbered 7.00 rather than 6.10 — a new preset family
// plus new script-language features is a major release; 6.9.3 was
// the last patch of the 6.x line.) Beat engine fixes underneath so
// the Demo track actually
// locks tempo (was sporadic): demo synth remixed for detection
// (hot kick owning the 20–100 Hz band, off-beat bassline voiced
// C3+ with a sidechain pump — chronological envelope events!),
// and the detector's default threshold 1.4 → 1.2 (the 170 ms FFT
// window caps a clean kick's peak-to-mean at ~1.5×, so 1.4 fired
// only sporadically and the BPM never locked)
// 6.9.3 — canonical domain fix: metadataBase/og:url/og:image pointed at
// openvisualengine.com (a DEAD domain baked in by 6.9.1) while the
// real site is openvisengine.com — Facebook's "corrupted image"
// error was its crawler fetching the image from a host that serves
// nothing; all share URLs now use the correct short domain
// 6.9.2 — share-image fix: og:image re-encoded as BASELINE JPEG (the
// 6.9.1 progressive encoding rendered fine in every browser but
// Facebook's Sharing Debugger rejected it as "corrupted"), swapped
// in the title-card artwork (gradient wordmark over three
// visualizations) and added a ?v=2 cache-bust so crawlers fetch it
// 6.9.1 — social share preview: Open Graph + Twitter Card metadata with
// a 1200×630 screenshot of the app (public/og-image.jpg) — sharing
// openvisualengine.com on Facebook/X/WhatsApp/Discord now shows the
// big image card instead of a bare link
// 6.9 — house account: anonymous visitors play YouTube links through
// the operator's shared disposable-account cookie (server-side
// fallback under secrets/, never exposed) — YouTube bot walls stop
// applying to guests; visitor's own login always wins. Engine fix
// underneath: Deno runtime shipped in bin/ (YouTube requires a JS
// runtime for signature/n-challenge solving on authenticated
// sessions — without it, logged-in extractions return no formats)
// 6.8.2 — login friction cut to ~4 clicks: the exported cookies.txt /
// Cookie-Editor JSON file can be dragged straight onto the
// login box (or picked via “Import the exported file…”) — no
// opening the file, no copy/paste; “Log out” / sign-out
// revocation note added (the official Google OAuth flow can't
// power the site: Google's APIs never hand out stream URLs and
// restricted-scope verification would reject an audio player)
// 6.8.1 — cookie login made foolproof: the login dialog recognizes raw
// Cookie headers, cookies.txt exports AND Cookie-Editor JSON,
// validates the paste LIVE through one shared parser (a single
// cookie's value — like a bare LOGIN_INFO string — gets an honest
// "this will not log you in" warning), and the how-to steps lead
// with the one-click extension export for Chrome AND Firefox
// 6.8 — self-healing audio engine: when YouTube changes their mechanics
// the server detects the stale extractor, updates yt-dlp in the
// background (verified GitHub release download, atomic swap) and the
// player retries seamlessly behind an "Updating in Background"
// notice; bot walls answer "Google login required…" with an Open
// Settings action, and unfixable failures get the honest
// "A back-end problem has occurred. Please try again later."
// 6.7 — lazy playlist queue: a playlist link becomes a queue of URLs that
// streams ONE song at a time (each track is resolved by yt-dlp only
// right before it plays — next-track look-ahead at ≤15 s to go),
// queue bar with skip/jump/replay + server-side caps (max 2 parallel
// extractions); music-service framework: Spotify + Apple Music are
// registered providers whose playback ships in a later update
// (logins already save, links answer with an honest notice)
// 6.6 — music service logins (Settings tab): YouTube / YouTube Music,
// SoundCloud, Spotify, Apple Music cookie login, encrypted on the
// visitor's computer; Link button gains playlist picking + uses the
// login to bypass bot walls
// 6.5 — Settings tab (replaces the parked Native tab): theme picker with
// base chrome (Royal Purple / Matte Black / Black + Purple Outline /
// Light) × selectable highlight color (Purple, Yellow, Blue, Green,
// Red, Orange), all per-visitor; simple OVE logo as the site favicon
// 6.4 — beat detection suspends when no music is playing/loaded (no ghost
// beats after Stop, BPM resets) + dark theme restyle: royal purple
// chrome with light-yellow highlights
// 6.3 — light/dark theme tick switch in the header (white theme via .light
// palette remap; per-visitor, persisted by next-themes)
// 6.2 — security hardening: read-only embedded library (server refuses all
// writes) + per-visitor "user created" presets stored in the browser
// 6.1 — preset library quality pass: every embedded stand-in is now a UNIQUE
// generated visual (16 families × seeded parameters), approx badge
// 6.0 — renamed to "Open Visualization Engine" + footer version stamp
// 5.0 — folder-tree Presets page (Task 9–11 state, restored in Task 12)
// 4.0 — link audio source (yt-dlp resolve + stream proxy)
export const APP_NAME = 'Open Visualization Engine'
export const APP_SHORT = 'OVE'
export const APP_VERSION = '7.11'