Cinemap is a recommendation engine over 140,000+ films and shows. Each title is represented by five signal blocks: emotional affect, director style, personnel, microgenre, and cast career-trajectory. A contrastive metric-learning multi-layer perceptron fuses these into an 85-dimensional vector whose geometry reproduces an inferred human ground truth.
State-of-the-art recommenders optimise for predicting your next action - what you'll click, watch, or finish.
The engineering is excellent - collaborative filtering, two-tower retrieval, transformer sequence models over enormous interaction logs. But the objective is a proxy, and the proxy has drifted from the goal. Maximizing predicted engagement rewards habit and popularity, and converges on more of what you already do.
A recommender's job shouldn't be to predict what you will do next; it should be to help you discover what you should do next and help you get there.
Cinemap optimises for that directly: a content-first representation supervised by an inferred human ground truth of genuine similarity, so a recommendation targets what is worth watching, not what is most likely to be watched.
Model the probability of your next click or watch and maximise it. Efficient at scale, but it optimises a proxy - engagement - that rewards popularity and habit over value.
Model genuine similarity and quality from an inferred human ground truth, then guide the viewer toward it. The target is what someone should watch next, learned independently of behaviour.
Describe each film with five complementary signal blocks, then learn - not hand-tune - how to fuse them into a single 85-dimensional vector, supervised by an external human ground truth. Once every film is a point, each product surface is a geometric operation over that one space: browse is sampling, similarity is nearest-neighbours between films, and - because a viewer is placed in the same space (next) - personalization is retrieval between a user's vector and the films around it.
Five per-title signal blocks, each L2-normalised: emotional affect, director style, literal personnel, microgenre, and the career trajectory of the cast at the moment the film was made.
We don't hand-define similarity. We learn it from an inferred human ground truth - the implicit signal in how large communities co-curate films - that is independent of our own vectors. Contrastive metric learning pulls co-grouped titles together and pushes everything else apart.
Every title is described by five independently-computed feature blocks. Each is L2-normalised, so it contributes a unit direction and the learned model is free to weight it; a title missing a block - an unknown director, absent cast data - simply falls back on the others.
35 continuous feelings - tension, awe, dread, humour - a dense affective fingerprint.
A director's emotional signature, graph-attention-enriched across kindred creators.
Literal shared cast & crew identity, compressed to a dense collaboration vector.
The scene a film belongs to - neo-noir, heist, elevated horror.
Where each person was in their career at the release year - the rising-star signal.
A language model scores 35 anchored affective dimensions per title, based on latent knowledge about each title as well as a corpus of text scraped from the internet about each title; the block is the unit-normalised score vector - the axis a genre label cannot express.
Per director, a bias-corrected concentration of their films in emotion space - the auteur index - gates a leave-one-out centroid of their work. A graph-attention layer then blends in kindred directors, with attention weighted by similarity × distinctiveness, so a film inherits a whole stylistic family rather than one name.
A sparse title × person incidence over cast and crew, TF-IDF weighted so rare, distinctive collaborators count for more, then reduced by truncated SVD to a dense identity vector.
A multi-hot over a fixed microgenre vocabulary, TF-IDF weighted so a distinctive tag outweighs a common one - and deliberately down-weighted during training so a literal premise never dominates tone.
Each person sampled at the film's release year: a recency-weighted, billing-discounted popularity (stardom-at-the-time), a breakout signal (future minus past), career stage and experience - aggregated director vs cast, then standardised. This captures dynamics like whether a film features a breakout performance.
The films are points; a viewer is placed in that same 85-dimensional space, as a small set of taste vectors (centroids). Recommendation is then a single geometric operation - retrieve the film vectors nearest a user's taste vectors - and personalization is the progressive motion of those user points through the film cloud as a session accumulates evidence.
Several centroids let a viewer who likes both bleak thrillers and warm comedies keep both, rather than averaging into a midpoint between them that recommends neither.
Explicit signals are weighted up to 4× by recency and trigger a debounced recompute from full history. Passive dwell folds in as a capped soft signal, so scrolling can never outvote a deliberate like.
Each page mixes proximity to the user's vectors with a fixed exploration quota, capped to one film per microgenre - enough novelty to keep the estimate improving without leaving the neighbourhood.
Nine of the 35 affective dimensions rendered as a radar: a per-title read-out of the emotional profile, and - with draggable vertices - a control that filters the catalog by feeling.
Emotion and microgenre are both axes of the same vector, so you can filter on their combinations (tense and heist; heartwarming and sci-fi; funny and horror). That is not keyword search: it is direct navigation of the embedding space, moving to a coordinate and pulling the titles around it.
Now showing: Inception
The surfaces let you move directly through the embedding space and pull its levers by hand.
Pinterest-style poster grids are graph traversal, each tap stepping to a neighbouring node; a TikTok-style trailer feed is discovery along your taste; and mood sliders, microgenres and seeds are direct controls on where in the space you sit.

A full-bleed, auto-playing feed with the title's emotional radar overlaid and live mood chips.

Drag dots on the radar to filter by feeling - the affective axis turned into a direct-manipulation control.

Curated tags - Cyberpunk, Home Invasion, '70s Paranoia - combined as OR sets and used as a diversity constraint.

A wizard that turns "what do you wish you could watch for the first time?" into seed nodes for the engine.

Curated and user lists - editorial collections sit beside anything the community makes public.

A masonry of posters with a human voice - “movies my friend Mike will enjoy over 4–5 Miller Lites.”

Ratings, streaming, trailer and the signature radar - the affective fingerprint made legible.

Per-country availability with array-overlap filtering, so results respect the services you pay for.
← scroll · drag to explore the surfaces →
The web "For You" feed estimates a taste vector client-side from implicit signals - trailer dwell time and skips - with no account, then retrieves the film vectors nearest it: the user-to-film case of the same geometry the "More Like This" rail runs film-to-film. A progress indicator reflects the confidence of the session estimate as evidence accumulates.
Open any title and the “More Like This” rail is pure geometric retrieval - approximate nearest neighbors in the 85-d space, oversampled and diversity-capped so a single prolific director can't dominate the results.
Cinemap is a solo project - the data pipeline, representation-learning model, backend, and both clients - developed since 2020. Always happy to chat about recommender systems, applied ML, or movies.