DigDeeper · experiments

Experiments & prototypes

Independent prototypes, dashboards and analysis writeups. Each project lives in its own folder. Two kinds live here: static writeups and small Flask tools, and a Next.js app for the ones that need real app UI — the card’s footer says which.

Rekordbox bridge — one export, then the folder syncs itself

How few times does a DJ have to do anything for us to import their collection and keep it in sync? Once. One rekordbox.xml export names the exact folders their music lives in — so nobody is ever asked "where is your library?" — and hands over the crates and ratings no folder on disk can show. After that the music folder alone does the work: the rig walks it in the browser, keeps the handle, and fingerprints every file, so Rescan reports precisely what a sync run would touch. It reads ID3, Vorbis and M4A tags to show what the catalogue match gets for free, and decodes each file to the 16 kHz mono the analyser eats, encoding Opus at ~29× smaller than the source — a 50 GB upload turned into under 2 GB. No agent, no second export, and no network calls at all.

2026-09-23 · integrations · static writeup

Struktur im Ranking — dieselbe Suche, einmal mit dem Verlauf des Tracks

Die Produktion vergleicht Tracks über einen gemittelten Vektor aus 60 Sekunden. Hier steht daneben, was passiert, wenn der zeitliche Verlauf mitzählt: jeder Track über seine ganze Länge in 8 Abschnitte, abschnittsweise gegen den Seed. Vier echte Digs, beide Spalten aus demselben Kandidatenpool von je 500 Nachbarn, jeder Titel zum Anhören verlinkt. Das Ergebnis sortiert um (im Schnitt 5 Plätze je Track, 14 Tracks neu in den gezeigten Top-25), stellt die Spitze aber nicht auf den Kopf — plausibel, denn das 60-Sekunden-Fenster repräsentiert den ganzen Track schon mit cos 0,988. Gegen Saves gemessen (134 gelabelte Listen) war kein signifikanter Gewinn nachweisbar; ob die rechte Liste besser ist, muss das Ohr entscheiden.

2026-09-22 · similarity · static writeup

Why they leave after one listen — what 412 drop-offs had in common

The aggregate behind the drop-off tool, and mostly a negative result: on genre agreement, artist spread, tempo distance, playability and embedding closeness, the people who left got results indistinguishable from the people who stayed — and on playability they got better ones. What separates them is how far they listened (1.3 tracks vs 5.3, rank 2 vs rank 7), and playing one or two tracks predicts a return no better than playing none. The one quality effect that survives is the outlier tail: a top result under 0.85 cosine — 3.8% of first searches, mostly non-electronic YouTube links — drops the return rate to 23.7% from 38.3%. The sharpest split is not about music at all: the drop-offs are two-thirds phone users against a desktop majority among the returners, a phone session runs five minutes to desktop's fifteen, and the player itself works fine on both.

2026-09-18 · retention · static writeup

Re-Ranking Lab — does the signal model beat plain similarity?

A blind A/B on the ranking itself. Submit a seed track and the page shows two orderings of the same candidates side by side — one pure cosine similarity, one re-ranked by the measured external signals (collection ownership, Bandcamp buyers, MixesDB DJ plays, era proximity) with shrinkage and artist de-clumping. Which column is which is decided per run and only revealed after you rate, so the tester cannot score their own hypothesis. Weights come from a conditional logistic fit on 14 829 measured pairs with a user holdout: 54.1% test accuracy on discordant pairs — real, but close enough to a coin flip that the blind test is the point. Ratings are stored with both ranks, so the count of keepers in each column's top 5/10/20 is the verdict. Moved here from the main app (2026-09-23), where it briefly sat open on beta.

2026-09-23 · ranking · next.js app · auth-gated

Drop-off — why they left after one listen

The accounts that submitted a track, played one or two of the recommendations and never came back — one at a time, with the evidence. Every search stores the full ranking it returned, and every 3.5-second play is logged, so the page can show exactly which rows they heard, at which rank, how long after the search, next to everything else we hold: where they came from, what they saved, what they told us. All of it playable, because whether a set of recommendations deserved a second session is a thing you hear, not a number. Of the current cut, 91% were gone within five minutes and 3% saved anything.

2026-09-18 · retention · next.js app · auth-gated

Features — what the similarity model actually hears

The embedding's 1280 dimensions are not a list of concepts: a network packs more properties into a space than it has axes, so each property lies along a slanted direction and each axis carries several at once. A sparse autoencoder re-expressed them as 10 240 units of which every track lights up 32 — and those units are readable. One fires on 1 254 tracks spanning 57 BPM whose tags are darkpsytrance at 179x lift: not a tempo, not a genre, a production style. Each unit shows its strongest tracks (playable), what it lines up with across every track that fires it, and a steering panel: push a different track along the unit's direction and watch which ten neighbours the catalogue answers with.

2026-08-30 · interpretability · next.js app · auth-gated

Sound Map — the catalogue as regions of sound, not tags

300 000 playable tracks clustered on the embedding, then grouped into a hierarchy you can walk: continents, regions, neighbourhoods. Each region carries its measured signature — tempo, tonality, era, vocals, genre mix — and its tracks are ranked closest-to-centre first, so the top of a list is that sound's prototype and reading down walks out to its edges. Two views (grid and a real point cloud), a catalogue search that drops you into the matching region, and a switch between seven embedding spaces for comparison.

2026-08-29 · clustering · next.js app · auth-gated

Set Timelines — a DJ set as a tracklist and a waveform

Paste a set, get its timeline: segments, matched tracks where we can identify them, and the similar sounds around each moment.

2026-08 · dj-sets · next.js app · auth-gated

Set Digger — dig from one moment in a set

Mark a 60-second window anywhere in a set and search the catalogue from exactly that sound, rather than from a track name.

2026-08 · dj-sets · next.js app · auth-gated

Match Label — is the matcher's pick actually the right track?

The matcher decides which YouTube upload to play and which Discogs release to attach for every track we ingest, on a confidence score with a hand-tuned threshold — and until now nobody could say how often either is wrong, because there was no labelled data. That is what makes matcher work whack-a-mole: each fix is validated against the one anecdote that prompted it, and its regressions surface weeks later. One match per screen, our track beside the pick, verdict on a keystroke; a wrong verdict asks why, and that histogram is the work plan — “37% of false positives are mix mismatches” points at one gate in the scorer. Filterable by the source a track was discovered on (bandcamp, traxsource, deejay, decks …), since each scraper's metadata is shaped differently. Exports straight into the offline scorer, which replays every label in milliseconds. Precision only — a match the pipeline rejected leaves no row behind.

2026-08-30 · match-quality · live app · auth-gated · ground truth

Mood & energy — do the mood heads work on club music?

Essentia's mood heads run on the EffNet embeddings we already store — no audio, no re-analysis. First view measures whether they spread at all inside our catalogue: party, aggressive and relaxed do (std ~0.13–0.19, Techno 0.62 vs Ambient 0.34 on party), while danceability saturates (median 0.87 — in a techno catalogue everything is danceable) and the 56-tag Jamendo head is mostly flat. Second view plays a track and records what it actually is, in DJ vocabulary (hypnotic, driving, dubby, raw) — words no pretrained model has, since there is no public mood dataset for electronic music. The CSV is the deliverable.

2026-08-26 · mood-energy · live app · auth-gated · prototype

Set Digger — dig from any moment of a DJ set

Paste a YouTube DJ set and it plays right there, over a timeline you can mark regions on. Auto-scan maps the set's shape — including a drift line showing where it turns — and every region is embedded on its own and queried against the live catalogue, in three views: crate (fits here, not already in the set), nearest, and a probable ID for partial tracklisting. Auth-gated: a dynamic app that spends analyzer time per set.

2026-08-16 · dj-sets · live app · auth-gated · prototype

Current vs mean-centered — recommendation A/B

Same model, two scorings: what digdeeper.fm returns today vs the same neighbours with the corpus mean subtracted. The live space is anisotropic (||mu||/mean||x|| = 0.69) — two random tracks already score 0.48, which squeezes rank 1 to rank 50 into a 0.069-wide band. Centering doubles that margin, and swaps ~1 in 4 of every top-10. Every row playable, so you can judge whether the swap is an improvement. Auth-gated (basic auth): a dynamic app against the shared DB + Qdrant, not a static writeup. (Was: six embedding spaces — the five contrastive variants lost.)

2026-08-30 · embedding-strategy · live app · auth-gated

Audio near-duplicates — verify

Tracks whose full-track embedding is near-identical (cosine ≥ 0.995) — the same recording regardless of how the metadata reads. Catches what id/slug/title signals miss: cross-artist collab reuploads, "various artists" compilation copies, differing credit strings, re-masters. ~8% of tracks have such a twin. Each group is playable inline (Bandcamp/YouTube) with a title+artist match badge — listen, mark same/different, export verdicts. No merges happen here.

2026-06-06 · dedup · sample: 1,500 random tracks

Resolving credits — artists & labels per track

The follow-up to the classifier: given a track's stored title + artist + Bandcamp label.name, decide the real artist(s) and label(s) — no re-fetch, exactly what a backfill sees. 10/11 artists and 8/11 full credits on the check-set; 180 random tracks shown input→output, grouped by confidence so you can judge the low-confidence boundary yourself.

2026-06-05 · resolver · 180 random + 11-track check-set

Artist or label? — classifying Bandcamp pages

A Bandcamp URL can't tell you if a page is a solo artist or a label, but Dig Artist / Dig Label need to. Tested a simple rule (“many distinct artists ⇒ label” + the Various-Artists flag) over all 127,840 pages in prod — 7/10 on a labelled check set. Directionally right, but the stored artist field is the bottleneck: it collapses to the label name on some catalogs and inflates on “feat.”-heavy artists.

2026-06-05 · classification · 4.78M sources, 10-page check set

Traxsource — scraper recon & embed player

Can we ingest Traxsource, and can we play it back? Three catalog endpoints are open (no Cloudflare) — an estimated ~9.4M tracks reachable by ID sweep. The official embed player is live here, but has no JS control API (unlike SoundCloud/YouTube). Plus the licensing split: analyze freely, but don't reskin their preview.

2026-06-05 · recon · sample: 4000 random title IDs

decks.de → YouTube / SoundCloud matching

decks.de has no embeddable player, so each track needs a matched YouTube or SoundCloud source to be playable. The matcher run over a random sample of the archived backlog — 74% get a playable match — every match playable inline so you can judge it yourself.

2026-06-04 · matching · sample: 100 archived decks tracks

Matcher: measured, not guessed

Picking the YouTube upload for a track used to be one tuned number against one threshold, and nobody could say how often it was wrong. 101 matches judged by hand now say: the old scorer was right on 70, the field model on 95. A separate playlist of twelve independently flagged bad matches replays clean — eight now find nothing, four pick a different video, none survive. The labels also say where the damage is: below score 0.9 every single labelled row was wrong (15/15, 268k tracks), while the "perfect" 1.0 band is only 18% wrong but holds 94% of the volume — about a million bad matches. Plus three things we stopped guessing about: adding (Original Mix) to the query halves the hit rate, the exit country changes nothing, and the fallback query ladder costs 1.23 searches per track.

2026-09-23 · match-quality · 101 hand-labelled matches + 12 negatives · precision only

How the matcher decides — the rules, visualized

The full logic behind decks/Traxsource → Discogs + YouTube/SoundCloud, step by step: the search ladder (barcode → catno → tracklist → fuzzy → stop-words), the four scoring signals, and the accept/reject rules (corroboration, not title resemblance — incl. the tracklist check that fixed Jeff Mills and killed catno collisions). Read it to sanity-check the pipeline.

2026-06-06 · explainer · matcher flow + open questions

decks.de — live matcher results

The actual stored matches from the production drain (decks → YouTube + Discogs), not a re-run. Each row links the matched YouTube (▶ to verify the pick) and Discogs release, with confidence + the no_youtube_match visibility flag. Eyeball it to find where the matcher still goes wrong.

2026-06-06 · review · ~150 freshly-analyzed decks tracks

decks & Traxsource → matchers — verify

100 real source tracks (50 decks, 50 Traxsource), each run through the two matchers that matter: YouTube (playback — the ingest gate) and Discogs (metadata/buy). SoundCloud was dropped (mostly noise). Playable: decks ~73%, Traxsource ~92%. Discogs matches by free-text + catalog-number search, confirmed by the tracklist / release title / catno+artist — recovering placeholder-titled vinyl ("track two" → the catno finds the record), mis-credited artists (Decibel Ft Leveetra → Decibel Feat. La Veetra) and catnos decks mis-files into the label field: decks ~92%, Traxsource ~36%, and 0 false positives. Each match surfaces the release's curated YouTube link (▶ YT). Source rows link back to decks/Traxsource.

2026-06-06 · matching · sample: 100 decks + traxsource tracks

decks & Traxsource → matchers — verify (sample 2)

A second, non-overlapping random sample (50 decks, 50 Traxsource) through the same two matchers — a cross-check that coverage holds beyond the first 100. decks ~94% on Discogs (47/50), ~72% playable; Traxsource ~90% playable, ~34% on Discogs; 0 false positives. Confirms the catalog-number / placeholder- vinyl recovery generalizes to fresh tracks.

2026-06-06 · matching · second sample: 100 fresh decks + traxsource tracks

decks.de → Discogs matching

Discogs isn't playback — it's metadata and a buy link. Matching by catalog number / barcode (which decks gives us), 92% of tracks resolve to a Discogs release — 38 by exact catalog number — bringing label, year, genre/style, marketplace stats and a buy link, and often fixing decks' own bad metadata.

2026-06-05 · matching · sample: 100 archived decks tracks

decks.de matching — second sample

The same matcher over a second, non-overlapping 100-track sample from the archived backlog — 83% get a playable match. A cross-check that coverage holds beyond the first sample, after the metadata + matcher fixes.

2026-06-04 · matching · sample: 100 fresh archived decks tracks

Similar tracks — six ways of listening

The 100 nearest neighbours of a seed track, playable inline, with six embedding strategies scored side by side. They agree on what's similar but disagree a lot on order.

2026-05-29 · embedding-strategy · seed: Le Nomad — Two Left Turns

Sample HTML app

A tiny no-build prototype with shared DigDeeper styling, inline CSS animation, and simple JavaScript controls.

2026-06-04 · sample · static-html
Add a project: create your own folder under site/<slug>/, build an index.html that links /style.css, add a card here, commit & push. See .claude/skills/publish-experiment and the repo CLAUDE.md.