Role

Product ⁠· UX/UI ⁠· Design system ⁠· Content & imagery direction

Client

HEC Montréal

Disciplines

UX/UI Design · Design System · Prototyping · Frontend

Year

2026

An editorial streaming platform whose atomic unit is a human-curated narrative theme, not a title ⁠— designed end-to-end across four platforms on one token system and shipped live as a React app

Problem
every streaming UI is an infinite algorithmic wall; choice fatigue is the product, not curation
Insight
no platform’s atomic unit is a curated narrative theme ⁠— Netflix sells titles, MUBI one film at a time
Solution
editorial streaming across 4 platforms (80+ screens) on one token set, 2 modes; I owned product, UX/UI, design system + a live grounded AI Curator
Outcome
shipped: an installable React PWA with weekly push, live on my own server ⁠— 0 unbound design values, €0/mo AI on free-tier failover

Curation as the product, not another algorithm wall

Every streaming UI is an infinite algorithmic wall, and the scrolling it forces is the real product. Benchmarking Netflix, Disney+, MUBI and Criterion exposed the unoccupied space: no platform’s atomic unit is a curated narrative theme. NUX makes finite, editor-curated clusters the whole point ⁠— Criterion × MUBI × Apple TV.

Every decision serves that thesis. Editorial anatomy appears wherever a collection does ⁠— amber eyebrow, serif headline, two-sentence dek, curator byline with a date ⁠— with finite counts, never “More like this ∞” ⁠— “Five Films on Grief” began as this principle’s example and now ships as a live collection. One filled amber CTA per region, rationed like ink to ≤10% of any screen, so the single Play always wins the glance.

“Projection Still Life” ⁠— one symbolic object, one amber key light, 35mm grain. The imagery is the color system: the UI stays warm near-black so the art carries the screen

The finite-count promise, kept ⁠— Five Films on Grief, live in the app

One token set, two variable modes ⁠— wireframes and hi-fi are the same screens

The core engineering decision: a single semantic token set (surfaces, text, borders, actions, icons) carries two Figma variable modes. Wireframe is a greyscale HIG ramp in Plus Jakarta Sans + Inter; Hi-Fi is a warm ink ladder (#070606→#332E27) with paper text tones at 17.0:1 / 8.4:1 / 6.3:1, amber #C8922A accents using dark-on-amber labels (7.1:1 ⁠— white fails at 2.4:1), hairlines instead of shadows and 2.5% film grain. 35 wireframe + 46 hi-fi screens, audited to 0 hardcoded values and 0 unstyled text layers.

Type does the editorial work: Fraunces names content, Inter handles anything functional, Newsreader carries long-reads, at a display-to-metadata ratio of at least 5×. A 50+ component library per platform covers every interactive state (default/hover/pressed/focus/disabled), plus selective iOS 26 glass tab bars and a tvOS focus model ⁠— white ring and lift, one focus per screen. Every platform has its player, and both fidelity modes run as fully clickable prototypes.

Figma hi-fi Desktop Home ⁠— the same token system the app ships on

A placeholder-free catalog of real British cinema with a generated-imagery identity

The catalog is real British cinema ⁠— 72 films, each with its poster and landscape stills (The Third Man, Lawrence of Arabia, The Red Shoes, Black Narcissus…), 21 of them designed end-to-end in the hi-fi prototype, with period cast portraits and strict portrait-in-portrait, still-in-landscape discipline. For surfaces with no real art ⁠— genres, fictional titles, onboarding ⁠— I designed “Projection Still Life”: one symbolic object per genre, a single amber key light, 35mm grain, photographic and deliberately not 3D so it never fights the editorial ink language.

AI curation as a conversation ⁠— grounded so it cannot hallucinate a title

If curation is the product, the next move is to let the viewer ask for a mood in plain language and have the house answer. The Curator is a concierge in the live app, reachable from two entry points ⁠— a floating button on every screen and a “✦ Ask the Curator” pill beside the Browse search. Type “a tense noir about betrayal” or tap a mood chip, and it replies in NUX’s editorial voice with a short note plus real film cards. The conversation continues ⁠— “something shorter?”, “more like the noir one” ⁠— on the same surface.

It can’t invent a title: the whole catalog fits in one prompt (no RAG), the model returns only film ids, and the server validates them against the real catalog before anything renders. It runs on the free tiers of five models from two providers, three on Groq and two on Gemini: when one is busy or retired, the next answers within seconds. Keys stay server-side, rate-limited and input-capped. The same engine generates themed editorial rails (“Islands of the Mind”, “Portraits of Obsession”), cached and refreshed weekly ⁠— and subscribers get a single push notification when the new programme lands. Built test-first: provider failover, id-validation and a prompt-injection guard all covered.

The follow-up is the point ⁠— “something shorter?” narrows the same conversation rather than starting a new search, and every card is a real film from the catalogue

A playable promise ⁠— the games in the catalog are real

The catalog isn’t only films ⁠— it spans documentaries, games and courses, so I made the games real. Neon Drift, the one game in the library, isn’t a still: press Play on its title page and a small synthwave canvas game opens ⁠— pilot a salvaged starfighter through the neon ruins, reflex-driven, inside its own focus-trapped, reduced-motion-aware overlay. The content types aren’t a façade; the promise is kept in code.

Neon Drift ⁠— a playable canvas game that opens from its title page, with its own synthwave identity

Inside the run: gates drift in, one clip and you’re scrap

No RAG, and a model that cannot invent a film

Retrieval-augmented generation is the reflex architecture for a catalogue assistant. I ruled it out because the whole catalogue fits in a single prompt, which makes RAG infrastructure that buys nothing and adds a failure mode. The harder constraint was hallucination. An editorial platform that recommends a film which does not exist has broken its only promise. The model returns film ids rather than prose titles, and the server validates every id against the real catalogue before anything renders, so invention is structurally impossible rather than discouraged by a prompt.

The editorial rule is a refusal too. Every collection ships with a finite count and a named curator, never an infinite “more like this” rail. Endless rails are the cheapest way to raise session length, and they are precisely the choice fatigue the product exists to argue against, so the atomic unit stays a human-curated theme with a byline and a date attached.

The two-mode token architecture was paid for up front, before it was obviously worth it: a greyscale wireframe ramp and a warm hi-fi ink ladder built on one token set. It returned the cost twice. Hi-fi took hours rather than weeks, and every late change, a token re-alias or a component fix, propagated across 33 screens at once. For surfaces with no real artwork I designed a photographic “Projection Still Life” system, deliberately not 3D so it never fights the editorial ink language.

Instrumentation was a decision, not an afterthought. The project shipped with Microsoft Clarity wired in, session recordings, heatmaps and Core Web Vitals, plus a custom event taxonomy mapped to the real funnel. It paid for itself within a day. The cursor-reactive poster dome built for the hero on 23 June was intercepting clicks on the CTAs beneath it, and the fix shipped on the 24th: a dead click no self-testing had surfaced. It also settled where the front door belonged, since the standalone landing added after the app went live drew 448 sessions against 87 on the app’s own home. Between 1 June and 7 September 2026 the project saw 1,040 unique users, 62% average scroll depth, zero rage clicks, and Core Web Vitals of 1.32s LCP and 0.039 CLS, both inside Google’s “good” thresholds. That export includes some local development sessions, so it measures behaviour rather than clean external traffic.

Seven review rounds and a real iPhone

In September I went looking for what was broken, and the first audit found the worst of it. By early August both AI providers had retired the models the Curator ran on, so for six weeks every question got the same reply: “The Curator stepped away. Try again in a moment.” The weekly collections stood still too. It was back the next day, and it now has five models on two providers to fall back on.

Seven review rounds followed, against NN/g’s mobile and usability guidelines and Apple’s HIG, plus a review for assistive technology. They ran at my own iPhone’s width, at 262 px with text at 150%, on a throttled network, in landscape, on iPad and with only a keyboard. AI review agents I briefed did the legwork, and each finding was checked in the code or a browser before it was fixed. Together the rounds turned up more than 200 findings. Each round’s fixes were tested and deployed before the next one began, and the last round hunted for anything the earlier fixes had broken.

At 342 px, the width of my iPhone at 115% zoom, Browse now reaches its first title in 1.4 screens instead of 2.6. On emulated 3G a film page no longer goes blank or jumps while it loads (cumulative layout shift 0, down from 0.39–⁠0.62). Genre labels over the brightest photos read at 5.2:1 or better, where they had dropped to 1.3:1. A cast name now links only when that person has other films here: 273 of 329 links used to lead straight back to the film you were on.

The last check ran on my own iPhone, with NUX installed on the Home Screen and driven from a Mac through Safari’s Web Inspector while I used it. It caught what no emulator shows. The installed app’s tab bar covers the bottom 106 px, and an empty search had put its buttons under it. iOS raises the keyboard only for a field focused inside the tap, so the search button on a scrolled page did nothing; now it focuses the field within the tap.

All of this was expert review. Nobody outside the project has used NUX under observation yet, and the script for a five-person usability test is written and waiting.

A responsive React build, live on my own infrastructure

The full responsive app is live ⁠— Home, Browse, film pages with anchored sections, critic pull-quotes and Downloads that really do store on device, a keyboard-driven Player with a “?” cheat sheet, editorial collections, My List + Continue Watching, auth, Profile, editable taste and onboarding ⁠— React + Vite on the exported token system, real catalog data, a poster→hero View-Transition morph, a poster-thumbnail hero pager, hover crossfades into film stills, scroll-driven editorial reveals and a floating glass tab bar on mobile. It’s built to production standard: WCAG-AA accessibility (focus management, reduced-motion, screen-reader live regions, a screen-reader-grade Curator overlay), an axe gate in the test suite, a backend suite and CI that builds and smoke-tests the real Docker image, and a hardened non-root container ⁠— self-hosted on my own infrastructure (Docker ⁠· nginx ⁠· Coolify ⁠· Hetzner), auto-deployed on push. Before this release the whole flow went through an adversarially verified UX audit: 42 findings distilled to 13 root causes, all fixed, so the unhappy paths tell the truth too. The app ships as an installable PWA ⁠— a service-worker offline fallback, add to home screen, web push with one notification a week when the Curator publishes ⁠— and a separate marketing landing, built on the same token system, sits in front at nux.ontwrpn.com.

Film pages grew anchored sections and critic pull-quotes, matching the Figma spec to the pixel

app.nux.ontwrpn.com — live preview
Live demo
app.nux.ontwrpn.com
Open

Live ⁠— try it

Mobile ⁠— floating glass tab bar + detached search (iOS 26 pattern)

The modes architecture paid for itself twice: hi-fi took hours, not weeks, and every late decision ⁠— a token re-alias, a component fix ⁠— propagated to 33 screens at once. The discipline of auditing to zero raw values is what made that speed possible

The mark it was graded on ⁠— 15/⁠15, “A+ Impressively exceeds expectations” (HEC Montréal / edX)

Sources

Next project
noda