json-render — Vercel Labs Generative UI framework
json-render is a Vercel Labs framework (Apache-2.0, @json-render/core on npm) for Generative UI: an LLM emits a JSON spec constrained to a developer-defined catalog of components + actions + data bindings, and a renderer materializes it into a live interface. The catalog acts as a typed action space — Zod-validated props schemas, enumerated actions, structured data bindings — and the same spec renders across 20+ target runtimes: React, Vue, Svelte, Solid, React Native, Next.js, TanStack Start, Three.js (including a GaussianSplat component), Remotion (video), React PDF, React Email, Ink (terminals), and Satori-based image/SVG output. Ships with 36 pre-built shadcn/ui components, a streaming compiler (SpecStream) that renders progressively as the model responds, a state model with dynamic prop expressions ($state, $cond, $template, $computed), state watchers, MCP integration for Claude/ChatGPT/Cursor/VS Code, and drop-in devtools panels per adapter.
Key claims
Section titled “Key claims”- The catalog defines the entire generative surface: components (Zod props schemas + descriptions), actions (named enumerated intents), and data bindings, from which
catalog.prompt()derives a system prompt for the model [README §Quick Start, §AI Prompt Generation]. - Output is a flat spec with a
rootelement ID and anelementsmap keyed by ID, where each element carriestype/props/children(plus optionalvisible,watch) — parseable as pure JSON [README §Renderers/React]. - Any prop value can be a data-driven expression from a fixed vocabulary:
{ "$state": "/path" },{ "$cond": …, "$then": …, "$else": … },{ "$template": "…${/path}…" },{ "$computed": "fn", args: … }[README §Dynamic Props]. - Components trigger actions via a
setStateprimitive plus named catalog actions; state changes re-evaluate visibility conditions and dynamic expressions, and top-levelwatchfields let a state change trigger further actions [README §Actions, §State Watchers]. - The same catalog + spec renders across host runtimes without spec changes — React, Vue 3, Svelte 5 (runes), Solid (fine-grained), React Native, Next.js (full apps with layouts / routes / SSR / metadata), TanStack Start, React Three Fiber (20 built-in 3D components including
GaussianSplat), Remotion (timeline schema for video), React PDF, React Email, Ink (TUIs), and Satori (SVG/PNG) [README §Packages, §Renderers]. - The
SpecStreamcompiler consumes model chunks incrementally and yields partial specs + patch sets, so the UI updates as the model responds rather than after the final token [README §Streaming]. - Component adherence is the trust contract: the AI can only reference components declared in the catalog, so output is guardrailed at the schema level rather than by post-hoc validation [README §Why json-render?].
- Ships 36 pre-built shadcn/ui components (Radix UI + Tailwind) via
@json-render/shadcn, with a Svelte-5 counterpart via@json-render/shadcn-svelte, and a companion@json-render/directivespackage of pre-built expression directives ($format,$math,$concat,$count,$truncate,$pluralize,$join,$tfor i18n) [README §Packages]. - MCP integration (
@json-render/mcp) exposes the framework to Claude, ChatGPT, Cursor, and VS Code as MCP Apps, and adapters exist for Redux / Zustand / Jotai / XState as external state stores [README §Packages]. - Devtools panel is framework-agnostic: spec tree, state editor, action log, stream log, catalog browser, DOM picker; drop-in adapters for React / Vue / Svelte / Solid, tree-shakes to
nullin production [README §Devtools].
Method
Section titled “Method”The framework factors the generative-UI problem into four stable pieces:
- Catalog (
defineCatalog(schema, { components, actions })) — the typed action space the model is allowed to emit. Component definitions bind a name to a Zod props schema plus a natural-language description; actions are named intents with descriptions.catalog.prompt()turns this into a system prompt containing the schemas and descriptions, so schema updates propagate to the LLM system prompt automatically. - Registry (
defineRegistry(catalog, { components })) — the host-runtime binding that maps each component name to a concrete implementation (React function, Vue render function, Svelte snippet, etc.). One catalog, many registries. - Spec — a flat JSON document with
root: stringandelements: Record<id, { type, props, children }>. Elements can carryvisible: [predicate…]andwatch: { "/state/path": { action, params } }. Prop values can be literals or one of the expression forms. - Renderer + SpecStream — a framework-appropriate
<Renderer spec={spec} registry={registry} />component evaluates dynamic expressions against a state model, subscribes children to state changes, and dispatches action callbacks;createSpecStreamCompiler()incrementally builds the spec from streaming model output and emits patches so the UI updates progressively.
The Next.js and TanStack Start adapters lift the spec above a single view: a NextAppSpec / StartAppSpec carries metadata, layouts, and routes maps whose values are specs, so the model can emit an entire multi-route app (with SSR, generateMetadata, generateStaticParams) as one JSON document. The Remotion adapter reshapes the spec into a composition + tracks + clips + audio timeline; the image adapter reuses the same tree through Satori to produce SVG/PNG.
Results
Section titled “Results”The repo is a framework release, not a benchmarked system, so there are no evaluation numbers. Concrete artifacts:
- 20+ published npm packages under
@json-render/*(core, per-framework adapters, per-target renderers, devtools, state-store adapters, MCP, YAML wire format, codegen). - 36 pre-built shadcn/ui + 36 shadcn-svelte components ready to drop into a catalog.
- Six example apps in the repo (docs playground, dashboard demo, React Email demo, Remotion video demo, chat example, Svelte examples, Vue examples, Vite renderers demo, React Native / Expo, R3F Gaussian-splat demo, standalone gsplat.js demo).
- An experimental
Jevcomposition mode (experimental_composeSpec/experimental_createEvaluator) surfaced in the playground under a feature flag; unreleased.
No claimed benchmarks against alternatives (LangChain UI, Vercel AI SDK Generative UI, Assistant UI, etc.), no throughput / latency numbers, no coverage measurements of catalog-vs-model adherence — this is a framework release, not a paper.
Why it’s interesting
Section titled “Why it’s interesting”Sits adjacent to Tool-Use Agents at a different level of the stack: where the Tool-Use Agents concept has converged on structured function calls as the model’s action space (with SimpleTool: Parallel Decoding for Real-Time LLM Function Calling SimpleTool and Introducing System One Models & Jev Jev pushing calibrated typed-output decoding into the model itself), json-render treats the user interface as the structured output surface — one JSON tree per user turn, guardrailed by a Zod-validated component catalog, streamable, and portable across web / native / video / PDF / email / terminal targets. The catalog-as-action-space + catalog.prompt() pattern is the same trust-contract idea the tool-use recipes rely on (a typed schema the model is constrained to, not politely asked to follow), extended from callable actions to renderable structure.
The multi-renderer + streaming-partial-tree design shifts the interesting engineering question from “can the model produce valid JSON?” (largely solved by schema-constrained decoding, cf. Jev’s mathematical-guarantee framing) to “how much application state is expressible as pure projections over a spec?” — the same question Agent architecture as event log + typed components — actors composed with Tardigrade and Effect‘s “everything is f(log)” agent-architecture sketch raises for the event log, but applied to UI state instead of agent state (dynamic props + state watchers + visible predicates give a small algebra for expressing conditional UI without emitting a new spec each turn). Concrete framework instance of the Generative UI paradigm that a Luma-side agent surface (assistant that shows a live dashboard / storyboard / 3D scene / video timeline in response to a query) would want to build against or adapt.
See also
Section titled “See also”- Tool-Use Agents — same catalog-as-typed-action-space trust contract, but the emitted structure is a UI spec rather than a function call
- Introducing System One Models & Jev — Jev pushes typed structured-output decoding into the model class; json-render is the complementary framework side that consumes such outputs into a live rendered surface
- SimpleTool: Parallel Decoding for Real-Time LLM Function Calling — SimpleTool applies parallel-per-key decoding to function-call JSON at inference; the same trick would fit json-render’s spec-streaming compiler
- Agent architecture as event log + typed components — actors composed with Tardigrade and Effect — the “state is a pure projection from an event log” thesis for agent architecture parallels json-render’s “UI is a pure projection from a spec + state model” design