From 68f8cd15710a027504ddf6b9380d63114921bd2e Mon Sep 17 00:00:00 2001 From: teahubxyz Date: Tue, 20 Oct 2026 22:29:58 +0000 Subject: [PATCH] gandora: moved out of teahubxyz/time ventures/gandora into its own repo --- STORAGE.md | 60 +++ brain.js | 294 ++++++++++ favicon.svg | 1 + index.html | 1383 ++++++++++++++++++++++++++++++++++++++++++++++++ tools/build.sh | 3 + 5 files changed, 1741 insertions(+) create mode 100644 STORAGE.md create mode 100644 brain.js create mode 100644 favicon.svg create mode 100644 index.html create mode 100644 tools/build.sh diff --git a/STORAGE.md b/STORAGE.md new file mode 100644 index 0000000..9d267ab --- /dev/null +++ b/STORAGE.md @@ -0,0 +1,60 @@ +# gandora storage contract + +The page keeps everything through one object, `db`, in `index.html`. Today it is IndexedDB in the browser; a backend +replaces it by implementing the same four calls and pointing `db` at the new implementation. Nothing else in the page +touches storage (`brain.js` reads through `db.all()` too). + +``` +db.put(row, store = "tracks") // create or replace, keyed by row.id +db.all(store = "tracks") // every row, newest first (tracks by `made`, stations by `last`) +db.del(id, store = "tracks") +db.open() // internal; a backend adapter can drop it +``` + +Two stores. + +## tracks + +``` +{ + id: "1760998800000-211979153", // spec.made + "-" + hash32(title); stable, made by the page + made: 1760998800000, // ms epoch, when the DJ wrote it + kept: false, // pinned by KEEP (the only pin) + plays: 3, // play starts + loop passes + blob: Blob, // the audio (FLAC from Venice, mp3 from Runware); a backend may return { url } instead + spec: { // the song on paper: enough to re-render it anywhere + title, tags, lyrics, bpm, key, energy, line, // what the DJ wrote (tags = the music prompt, <= 500 chars) + seed, station, stationId, // where it came from + reaction: "๐Ÿ”ฅ โค๏ธ \"less snare\" [skipped]", // the listener's reactions, in order; words quoted, skips bracketed + guess: 0.71, // the taste net's prediction when it was cooked (optional) + plays, id, made // mirrored for convenience + } +} +``` + +## stations + +``` +{ + id: "s-1760998800000-211979153", // "s-" + ms + hash32(seed) + seed: "rainy trains", + name: "Platform Nine", // chosen by the DJ on the first track, then stable + taste: { like: [...], avoid: [...], notes: [...] }, // last 8 of each, in words, fed to the DJ + history: [ { id, title, tags, bpm, key, energy, reaction, made } ], // last 8 tracks, no blobs + made: 1760998800000, + last: 1761002400000, // touched on every play and reaction + played: 23 +} +``` + +## what a backend adds + +- identity: rows are per listener; `/user/station/track` links need the listener in the key +- `blob` as a URL the `