← Blog
Engineering9 min read

The Granularity Problem in GenUI: Where Should LLM Generation Stop?

Notes from building AirJelly's GenUI engine — and why giving the LLM more freedom made the result worse.

This blog comes from our hands-on exploration of the GenUI engine in the AirJelly project. We didn't start with theory. We started from an experiment that was honestly pretty frustrating: why did the result get worse when we gave the LLM more freedom to generate UI?

01 · Background

Why GenUI deserves serious attention

Before the details, it's worth being clear about why GenUI is a serious engineering problem, not just a demo trick. In Generative Interfaces for Language Models, the SALT-NLP / Stanford team compared user preferences between GenUI and traditional text-based chat. The takeaway is clear: when an AI system needs to communicate structured, information-dense content, a dynamically generated interface can be far better than a wall of text.

The GenUI wave accelerated between 2023 and 2025 because two conditions matured at once: LLMs got much better at code generation, and component ecosystems like shadcn/ui and Radix became stable enough to build on. Once those conditions were in place, tools naturally emerged — Vercel v0 is one of the most representative industry implementations.

02 · The starting point

We let the LLM freestyle, and the result got worse

On the feat/genui-real-content-experiment branch we ran a set of comparisons. The old approach had a fixed layout and unified components — polished and predictable. The new approach made the layout more flexible, but the visuals became messy and component styles inconsistent.

This went against our intuition. The more freedom we gave the model, the less control we had, and the worse the visual consistency became. The Gen-UI-Lang paper makes the same point: ask an LLM for raw HTML or JSX and the output is verbose, brittle, and easy to break. That's not a prompt-quality problem — it means we pushed the LLM to a granularity where it isn't at its best.

03 · The core tension

A structural contradiction in GenUI

Through the experiment we identified an internal contradiction that applies to basically every GenUI system.

The more freedom the LLM has, the harder it is to guarantee visual consistency. The stronger the constraints are, the less meaningful GenUI becomes.

This is a structural tension in the paradigm, not a bug in one implementation. Every GenUI system has to find its footing somewhere between these two forces. So the question becomes very concrete: where should the LLM's generation boundary stop?

04 · The field

Existing choices of granularity

Before settling on our own answer, it helps to look at how others have approached the same question.

Vercel v0 — generating down to component code

v0 lets the LLM go all the way down and generate complete React component code. Its visual consistency comes from shadcn/ui's semantic token system — it outsources consistency to the library's theme. The cost: the generation logic becomes tightly coupled to the component ecosystem, so moving off the shadcn/ui + Next.js + Vercel stack creates real friction.

A typical shape of v0-style component code
<Card className={cn("flex flex-col",
  plan.recommended && "border-primary shadow-lg scale-105"
)}>

The arXiv approach — a structured intermediate representation

The SALT-NLP / Stanford approach inserts a structured intermediate representation between natural language and UI code, at two levels: a high-level interaction flow (a directed graph of user paths and task stages) and low-level finite state machines (each component's states and event responses). The final output is still HTML, CSS, and JavaScript — the representation is a guide rail, not the destination.

Gen-UI-Lang — defining a UI intent layer

Gen-UI-Lang designs a dedicated DSL so the LLM only outputs structured node descriptions. The node structure is explicit, shallow, and consistent — exactly what LLMs generate reliably. Versus generating HTML directly, it reports a 65.3% reduction in token usage while improving stability, and it can render to HTML, React JSX, or Gradio from the same description.

A Gen-UI-Lang UI intent description
genui(
  row(
    text("Sales Overview"),
    btn("Load", on_load=lambda: get_graph(2001, 2002))
  ),
  chart(type="line", data="sales_q4"),
)
05 · Our choice

Stop at the product-semantics layer

All three approaches push the LLM upward, away from the rendering layer. They only differ in where they stop. We chose to stop higher than any of them: at the product-semantics layer.

The LLM doesn't output generic UI nodes like row or btn. It outputs product concepts — "this is a task-summary card, high information density, sourced from today's calendar." Which component to render, and how to lay it out, is decided entirely by the component library — not the LLM.

01The direct lesson from our failure case

Once we loosened the LLM's generation freedom, the visual result got worse. The closer the LLM gets to the rendering layer, the higher the cost of its randomness becomes.

02The analogy with browser rendering engines

Browsers don't let page JavaScript control pixels directly. They accept a controlled DOM description, and the engine decides the pixels. A GenUI engine should work the same way.

03The reliability of structured LLM outputs

OpenAI shipped Structured Outputs in 2024 specifically to fight format drift. The closer the output is to the rendering layer, the higher the cost of formatting errors.

04The long-term need for a replaceable component library

Stop at the product-semantics layer and the component library becomes a pluggable rendering backend — swap the design system tomorrow without touching the semantic layer.

06 · An unverified direction

Two-round generation

While debugging the complex GenUIPager component, we found a single LLM pass struggled to optimize content quality and layout quality at the same time. That led us to a two-round architecture — as a hypothesis.

Two-round generation hypothesis
First-round LLM:  content orchestration + page-structure decisions
                  (product semantics layer)
      ↓
Second-round LLM / component library:  concrete rendering decisions

The motivation is reasonable: content orchestration and rendering are two different cognitive tasks, and forcing them into a single pass can make them interfere with each other.

But we have to be honest: this is only a hypothesis, and we haven't fully validated it.

It's here because it points to a direction worth exploring — not because it's a settled conclusion.

07 · The map

A trade-off map of granularity choices

No granularity choice is universally correct. It depends on the product's tolerance for visual inconsistency, the expected lifecycle of the component library, and how structured the generated content is.

ApproachWhere the LLM outputs toHow consistency is guaranteedLibrary replaceable?Suitable scenarios
Vercel v0Component-code layershadcn/ui semantic tokensNo, tightly coupledRapid prototyping within the Vercel ecosystem
Gen-UI-LangGeneral UI intent layerMulti-target rendererYes, framework-agnosticCross-framework prototyping, efficiency-first workflows
arXiv approachHTML / CSS / JSStructured intermediate representation as guide railsDependsScenarios with high interaction complexity
AirJellyProduct semantics layerComponent library fully owns renderingYes, pluggableApplications with high requirements for product UI consistency

If the product has low tolerance for visual inconsistency, the granularity should be higher, closer to product semantics. If the component library is likely to evolve or be replaced, higher again. And if the generated content is highly structured, it's more suitable to describe it semantically at a higher level.

Sources

Sources & further reading

Closing

Granularity is the core design decision in GenUI.

The biggest takeaway isn't that we found the right answer. It's that we clarified the question: GenUI isn't about letting the LLM draw the interface. It's about designing a clear division of responsibility between the LLM and the rendering system.

The choice of granularity decides where that line is drawn — and where the line is drawn decides the system's maintainability, visual stability, and ability to evolve over the long term.

In October 2025 the W3C Design Tokens Community Group published the stable Design Tokens 2025.10 specification — a sign that separating semantics from visuals is becoming an engineering standard. The granularity problem in GenUI is that same trend showing up inside AI-generated interfaces.

We're still on the road. If you're exploring something similar, I'd love to talk.

More from the AirJelly team →