← Back to the portfolio

LISTENING PARTY ONLINE / MULTIPLAYER MUSIC GAME

A prompt, a room, and the song you were thinking of.

The host opens a room. Players join with its code, answer an original music prompt, and submit the song it brings to mind. The host reviews the YouTube match before it enters the shared queue.

Listening Party’s owned game artwork showing prompt cards, the game box and groups of friends sharing music.
Owned artwork from the live game. Download the full-size image.

How the game works

Listening Party centres the conversation around a song: the memory, person or mood that made someone choose it. Its 40 original prompts give the room a starting point, while separate host and player views keep submissions private until they are ready.

A player can answer by voice or with a private typed fallback. The host sees the proposed match, can preview or search again, and approves the song before the room hears it. This keeps an uncertain automated match away from the shared queue until a person checks it.

Finding a useful prompt quickly

Forty cards are easy to browse until a host wants one for a particular feeling or moment. The prompt finder searches the existing deck from a short request such as “a confidence song for starting over.” It does not write new cards.

The browser implementation compares two familiar retrieval methods. BM25 rewards matching words. Compact 50-dimensional GloVe word vectors can also surface prompts whose language is related without being identical. The live finder now makes those results easier to inspect: it shows matched words, the original-card source and a plain explanation when common words are doing the matching. A host can clear, close or switch category without losing the room flow.

Product decision after a stricter frozen check

Keep BM25 as the default. Each of three stricter rules rejected all 22 requests that had a usable answer. They stopped bad suggestions by stopping useful ones too, so I left them off. The compact GloVe comparison stays available as an experiment.

The decisions behind the flow

Make joining lighter than registering.

There is no account step. A host creates a room and players use its cassette-style code. The tradeoff is that losing the host browser token means creating a new room.

Keep the answer private until it is ready.

Transcripts, extracted song intent and candidate videos stay in the host review flow. Players receive the approved result and shared playback state, not another player’s raw answer.

Treat YouTube selection as a review.

Search results are checked for availability and embedding, then ranked. The host can preview, search manually or paste a YouTube URL before approving a song.

Live Listening Party prompt finder on 15 October 2026, showing a road-trip card with matched-word evidence and recovery controls.
Live desktop capture verified on 15 October 2026. Download desktop capture · download 390px capture.

What the frozen check showed

I used two batches of synthetic, agent-authored English requests: 40 to decide whether a new rule was useful, then 34 held aside for comparison. They were grouped into related intents before scoring. This is an engineering check, not user research, and it does not claim full blinding.

Each new rule stopped bad suggestions by stopping useful ones too, so I kept the simpler search and did not carry those rules into the held-back comparison. There, BM25 found an expected card in the first three for 18 of 22 usable requests and the semantic comparison did so for 19. That small synthetic difference does not justify calling one a winner.

The older 34-case comparison remains available as a dated v1 record. Its denominators are kept separate from this later evaluation.

What the live release checked

A slow connection exposed an old 20-second deadline for the optional model download. I had it extended to 90 seconds while keeping keyword search usable. Two regression cases failed at the old deadline and passed after the change: a simulated 58-second download completed while keyword results stayed available, and a stalled download reached the limit with a retry.

The release then passed 126 tests, with two opt-in provider tests skipped, and 12 live-browser checks. Those checks covered the explanations and recovery controls, keyboard use at 390, 768 and 1440 pixels, the real browser model checksum, and a host dealing a card for a separate guest to read back. They did not test microphone input, transcription, paid providers, physical devices or multi-device audio.

Why this stays in the browser

The deck is small and fixed. That makes a compact local index a better fit than adding a generation service, vector database or laptop companion. Search can run on the visitor’s device after its static assets load, with no model API bill and no host brief sent to a new provider.

Python prepares the compact GloVe model and runs the search evaluation. TypeScript searches the 40-card deck in the browser. The game itself uses Next.js, React, Supabase and Cloudflare, with YouTube search and host approval before shared playback.

What I worked on

I defined the host workflow, directed the search implementation and compared the candidate approaches. I kept BM25 as the default because the stricter options hid useful cards. The host still makes the final choice.

I checked the live flow from finding a card to dealing it to a separate guest. The linked results include the test requests, scores and the reasoning behind that release decision.

Designed for the room

The host reviews each YouTube match before it joins shared playback. Players can join without creating an account; the browser may ask for a tap to start audio.

Hosts can search from their room. Both search methods run in the browser, with BM25 selected by default.