Inspiration

Plotmeld is for people who know what they like to watch and read but have no gaming history to feed a game recommender. I wanted them to start from one film or TV show and one book they already love, and get a short list of games with the evidence behind each pick.

What it does

You type a film or TV title and a book title. Plotmeld looks both up in Qloo. If a title is ambiguous, it asks you to choose. A bare "Twin Peaks" brings up the 1990 series, the 2017 series and a 1977 film, so you pick the one you mean, or type "Twin Peaks (1990, TV)" up front. Then it returns up to three video games in Qloo's affinity order.

Each game card shows:

  • the developer, publisher, release date and platforms, as Qloo returned them
  • the Qloo affinity score (audience overlap)
  • how much of the pull came from your show and how much from your book
  • tags the game shares with each of your two titles, when there are any
  • one to three short reasons, each citing the facts above

A "Check before you buy" list reminds you that price, hardware and store availability are not covered. An optional familiarity setting caps Qloo's popularity score at 0.95 or 0.9 if you want less familiar picks. You can also open the research trace to see every Qloo and LLM call the agent made, with its inputs and timing.

With the default example, Twin Peaks plus The Secret History, the live demo returns Life is Strange, Little Nightmares and Oxenfree.

How it uses Qloo, and why Qloo is indispensable

Qloo decides which games appear and in what order. The language model never picks, ranks or adds a game. Every fact on a card comes from the Qloo response for that request: the affinity score, the per-input contribution Qloo returns when explainability is on, the game's properties and its tags. Without Qloo the app has nothing to rank and nothing to cite. An LLM on its own could name games that sound like Twin Peaks, but it has no measured audience overlap and cannot tell you whether the book or the show drove a pick.

The request-to-result flow, with entity IDs left out:

  1. GET /search for the screen title (movie and TV types) and for the book title (book type). An exact name has to match any year or type the user typed. Otherwise the user picks from the returned options, and the agent checks that choice against a fresh search.
  2. GET /v2/insights with filter.type=urn:entity:videogame, both entity IDs in signal.interests.entities, feature.explainability=true and take=10. filter.popularity.max is added only when a familiarity setting is chosen.
  3. Code removes the two input titles and duplicate titles, keeps the top three in Qloo's order, and turns the returned fields into numbered facts.
  4. Claude Haiku rewrites those facts as short reasons. A grounding check rejects any reason that cites a fact that isn't there, changes a number, or names something the facts don't contain. A game whose reasons all fail gets one correction turn; after that, the card shows the plain fact text instead.

The agent makes its own calls along the way: whether a title is clear enough to resolve or needs the user, whether a user's choice still appears in a fresh search, which written reasons to keep, and when to ask the writer again or fall back to plain facts. It works inside a fixed budget of Qloo and LLM calls, and the trace panel shows each step.

How I built it

Plotmeld is a Next.js 15 and React 19 app in TypeScript, deployed on Vercel. Zod validates the API input, every Qloo response, and the report the browser receives. The writer is Anthropic's claude-haiku-5-5, called through the Vercel AI SDK. Each request is capped at eight Qloo attempts and two writer turns, and both API keys stay on the server.

Tests run on Vitest. Mock Qloo and mock LLM modes let anyone run the app offline with synthetic data (Node.js 22.19 or newer):

git clone https://github.com/ktwu1997/plotmeld.git
cd plotmeld
npm ci
QLOO_MODE=mock LLM_PROVIDER=mock npm run dev

Live mode needs QLOO_MODE=live, a server-side QLOO_API_KEY, and LLM_PROVIDER=anthropic with ANTHROPIC_API_KEY.

Challenges I ran into

My first insights calls came back with HTTP 400 because I used urn:entity:video_game. The value the API accepts is urn:entity:videogame.

Shared tags don't always exist. For The Expanse plus Project Hail Mary, Factorio shares no tags with either title, so its card says the pick rests on affinity and contribution alone.

A browser replay caught a bug the offline tests missed. When the grounding check rejected only some of the reasons, the whole writer step was marked as failed and the page showed "Search interrupted". I fixed it, and the live smoke test now checks each report against the same schema the browser uses.

Accomplishments that I'm proud of

The language model can't change which games appear or add a fact about them. In the last live smoke run, five fixed screen-and-book pairs all came back with grounded reasons that passed the browser's schema check. One pair needed a rerun after a one-off Qloo search error.

What I learned

Qloo's explainability says how much each input pushed a result. It doesn't say which trait matched. I keep that number and the code-computed shared tags as separate facts on the card, so no reason presents a tag overlap as Qloo's explanation.

The default results lean popular. In my first tests, every top-ten game already had a Qloo popularity score above 0.9, so I describe Plotmeld as a starting point for new players, and the familiarity setting is the way to push past the best-known titles.

What's next for Plotmeld

Two gaps are still open: price, hardware and store checks, and books entered by their original non-English titles. Film and TV titles in other scripts already resolve through the choice screen. Books currently resolve best by their English title.

Known limitations

Affinity measures audience overlap and does not promise you'll enjoy the game. Platforms are copied from Qloo and not checked against stores. Offline mock mode uses invented games and facts.

Built With

Share this project:

Updates

Submission history