Every store clerk adapts to the customer in front of them. Web pages serve everyone the same room. I designed an engine that closes that gap, with an LLM that compiles itself out of the runtime.
A family walks into an electronics store, toward the TV section. The salesman watches from a distance. The older kid says "dad, we need one that works with the PS5." The mom: "it can't be too big, the couch is close." The younger one points at a Samsung: "can I watch YouTube on this?" The dad answers, "yes, but I want an LG. My LG monitor has been great."
When the salesman finally walks over, he already knows exactly what to show them: an LG smart TV, 4K@60 for the PS5, 55 inches max. No interrogation. He observed, then removed every irrelevant option between the family and the TV they were always going to buy.
On the web, this scene has no equivalent. We designers predict broad personas ahead of time and ship one fixed experience per persona. But a persona is mutable. The same person has different moments, different goals, different company on the couch. Granularity always runs out. Edge cases surface months later through analytics, maybe get prioritized, maybe get designed, maybe get shipped. The visitor who hit the friction, and everyone like them who followed, was lost long before the retro.
I sketched an engine to close that gap. Working name on the blueprint: UX:LOCK (understand the visitor while they navigate, instead of after) and UI:LOAD (let the interface answer what was learned). It shipped as ui-morph. This essay is part 1, the concept. What happened when I made it real is part 2.
Observe first
The salesman never asked the family a single question. The information walked in with them. The web equivalent of that posture: data gathering must follow user actions. The blueprint's first sheet maps four stages, each unlocked by something the visitor does:
The order matters more than the list. A first-touch visitor yields device class and referrer, and gets assumed to be nobody in particular. Behavior earns the next stage; volunteered data earns the one after. The last two stages live deliberately outside the engine's core: sign-in data and enrichment exist as opt-in adapters, because the honest version of this idea has to work on first-party behavior alone. And it does. Consent here is structural rather than decorative: before opt-in the machine holds no listeners and no storage, and opting out erases every byte.
The persona is a JSON that earns its fields
Four moments of one object. It starts empty on purpose: tier: undefined, intent barely a guess. Events fill in traits (curious, visual, slow-decision) and an engagement score. Volunteered info sharpens intent into goals. Enrichment, if the visitor allowed it, completes the mirror: next-best-action, buying chance, blockers. Every field arrives with evidence attached. In the shipped engine each trait carries the rule that fired it, in plain words, so the persona reads as an audit trail that happens to describe a person.
What the page does with it
Knowing the visitor is worthless until the page answers. The response scales with the tier of evidence. A generic visitor gets the safe, responsible default. A defined persona with an identified pain point gets the page rebuilt around removing exactly that friction:
Note what these interventions are made of: accordions, comparisons, videos, FAQs, tooltips. Nothing exotic. The entire expressive power is five operations (hide, show, reorder, emphasize, swap-variant) against elements the page itself declared morphable. Protected zones like navigation, checkout and anything legal reject every op, mechanically. The interesting decisions are which components appear when. That judgment call is exactly what an LLM is good at, inside a vocabulary it cannot escape.
Predict the path, prepare the next room
The salesman anticipates. He walks to the LG shelf before the family gets there. The blueprint's sharpest idea is the web version of that move:
From the persona, estimate ranked objectives with probabilities. From the top objective, derive the expected page sequence. Then pre-adapt the next page while the visitor is still on this one. The adaptation compiles in the background and applies at the page boundary, the only place mutations are ever allowed. The visitor never sees a layout move under their cursor. They simply arrive at a room that happens to be arranged for them.
The design system is the vocabulary
When the persona says gamer, the card receives swap-variant → "gamer": a token theme the design system already ships, authored by a designer, reviewed like any other code. The engine picks words that exist in your system's vocabulary, and only those. This is the same argument I made about design tokens as prompts, pointed at runtime: the machine consumes your system's contract, so the contract is where control lives.
Why nobody ships this
Look at who actually ships what. The personalization incumbents (Optimizely, Adobe Target, Dynamic Yield, Webflow's acquired Intellimize) all run ML that picks among variants humans authored. LLMs appear only at authoring time. The generative-UI frontier (Google's Gemini dynamic views, Vercel's json-render, Thesys C1) builds fresh surfaces for agent conversations, far from your existing pages. The middle sits empty for three documented reasons. Unstable layouts measurably hurt people: Findlater & McGrenere, Gajos, and Office 2000's adaptive menus, rolled back into the static Ribbon. Tracking-based personas need cookie-grade consent in the EU. And per-visitor LLM inference is a cost wall that Qubit's meta-analysis (90% of on-site changes move revenue less than ±1.2%) says you can never pay back.
All three walls fall at the same place: a boundary the model cannot cross, because the system enforces it.
The engine, end to end
The model sees only two things: the quantized persona and the page's own manifest. The DOM and the visitor stay invisible to it. Its output is ops from the closed vocabulary, validated by a guard. Unknown target, protected zone, unknown variant, blown budget: rejected, with the reason written to an audit log. And the persona is deliberately quantized into tiny closed vocabularies per axis, because a quantized persona is a cache key, and cache keys are meant to collide:
A novel persona triggers the model once. The surviving ops are cached as a chain. Every later visitor who quantizes the same, or near enough via deterministic similarity over the keys, replays the chain instantly, with zero model calls. Ship a redesign and the manifest hash changes, so stale chains die by themselves. The LLM's job here is to compile adaptations, once each, into inspectable, versionable, revertible artifacts. In the shipped engine's 200-session simulation, 72% of page arrivals were served from that cache. The warm path is the majority case, measured.
The claim, sized honestly
I'm making a narrow claim. Adaptive pages printing money is a separate question, Qubit's distribution applies to me too, and the engine still lacks an outcome-feedback loop (chains that fail to help should evict themselves). The claim is an existence proof: the salesman-at-a-distance is buildable today, without creepy tracking, without layout roulette, without per-pageview inference, if you put the boundaries before the capabilities. Making that real, with a full funnel, a live model and two hundred simulated shoppers, is part 2 of this essay.
Proof by construction: the engine is open source at github.com/Type-zero-labs/ui-morph, with one runtime dependency, five ops, 52 tests, a full e-commerce funnel demo on IBM Carbon, and a persona laboratory that replays hundreds of deterministic shoppers.
References: Google Research, Generative UI · Nielsen on Google's study · NN/g, Generative UI · Findlater & McGrenere · Gajos et al., CHI '08 · Qubit meta-analysis · EFF on GDPR & fingerprinting · vercel-labs/json-render · Hidden Technical Debt in GenUI













Top comments (0)