json-render component catalog patterns for AI-safe generative UI. Define Zod-typed catalogs that constrain what AI can generate, use @json-render/shadcn for 36 pre-built components, optimize specs with YAML mode, and apply the three edit modes (patch/merge/diff) for progressive updates. Use when building AI-generated UIs, defining component catalogs, or integrating json-render into React/Vue/Svelte/React Native/Ink/Next.js projects.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
json-render component catalog patterns for AI-safe generative UI. Define Zod-typed catalogs that constrain what AI can generate, use @json-render/shadcn for 36 pre-built components, optimize specs with YAML mode, and apply the three edit modes (patch/merge/diff) for progressive updates. Use when building AI-generated UIs, defining component catalogs, or integrating json-render into React/Vue/Svelte/React Native/Ink/Next.js projects.
json-render (Vercel Labs, 12.9K stars, Apache-2.0) is a framework for AI-safe generative UI. AI generates flat-tree JSON (or YAML) specs constrained to a developer-defined catalog — the catalog is the contract between your design system and AI output. If a component or prop is not in the catalog, AI cannot generate it.
Storybook → catalog import (#1529, 2026-04)
When the project ships a Storybook setup, import the catalog from Storybook stories instead of hand-writing one. The bundled importer at scripts/storybook-to-catalog.mjs reads a @storybook/addon-mcplist-all-documentation manifest and emits a Zod-typed catalog.ts plus a components.tsx registry.
Storybook becomes the single source of truth — adding a story automatically expands the AI-allowed surface; removing one shrinks it. AI safety is enforced at import: callbacks, raw object props, and z.any() are dropped. Full mapping: references/storybook-import.md. Companion fixture for testing: references/storybook-fixture.json.
New in 2026-04 → 2026-05 (json-render 0.14 → 0.19)
Custom directives API (0.19) — @json-render/core now ships defineDirective, letting you declare new JSON shapes (e.g. $format, $math) that resolve to computed values at render time. Directives compose by nesting and resolve inside-out. All four renderers (React, Vue, Svelte, Solid) have built-in directive resolution. This is the safe escape hatch for computed values without widening the catalog to z.any().
@json-render/directives package (0.19) — seven ready-made directives: $format (date / currency / number / percent via Intl), $math (add, subtract, multiply, divide, mod, min, max, round, floor, ceil, abs), $concat, $count, $truncate, $pluralize, $join. Plus createI18nDirective for $t translation keys with interpolation, and for one-line registration. Register once, use in any spec — AI no longer needs string-mangling or duplicated literals.
{{param}}
standardDirectives
Devtools ecosystem (0.18) — five new packages: @json-render/devtools core + framework adapters for React, Vue, Svelte, Solid. Inspector panel has six tabs (Spec, State, Actions, Stream, Catalog, Pick) with DOM element picking that maps back to spec keys. Tree-shakes to null in production. Companion Next.js demo app shipped with AI-chat + catalog integration. Action observer infrastructure exposed for adapters to mirror events into the panel.
Zod 4 fix (0.18) — formatZodType now correctly handles z.record(), z.default(), and z.literal() (previously produced empty/wrong prompt output).
Three edit modes (0.14) — patch (RFC 6902), merge (RFC 7396), diff (unified) for progressive AI refinements. buildEditUserPrompt() + diffToPatches() + deepMergeSpec() in @json-render/core.
@json-render/yaml (0.14) — official YAML wire format + streaming parser; buildUserPrompt({ format: 'yaml' }).
@json-render/ink (0.15) — render catalogs to terminal UIs (Ink-based, 20+ components) using the same spec.
@json-render/next (0.16) — generate full Next.js apps (routes, layouts, SSR, metadata) from a single spec.
@json-render/shadcn-svelte (0.16) — 36-component Svelte 5 + Tailwind mirror of the React shadcn catalog.
shadcn catalog at 36 components (was documented as 29 — the count was wrong even at 0.13). Use @json-render/shadcn as-is, or spread shadcnComponentDefinitions together with your own definitions.
@json-render/react-three-fiber ships 19 components (verified 2026-07-31 against the upstream skill; do not restate the roster here, see Upstream coverage).
@json-render/mcp — upgrade plain MCP tool JSON into interactive iframes inside Claude/Cursor/ChatGPT conversations. See the ork:mcp-visual-output skill.
MCP multi-surface: same spec renders to React, PDF (@json-render/react-pdf), email (@json-render/react-email), terminal (Ink), Next.js apps, and Remotion videos.
Directives — @json-render/directives (0.19)
Directives are the safe escape hatch for computed values. AI emits a $-prefixed object, the renderer resolves it inside-out before the component receives props — the catalog stays strict (no z.any() widening) and the spec stays declarative. The @json-render/directives package ships seven prebuilt directives plus an i18n factory; standardDirectives exports them as one array for one-line registration. Directives nest freely (e.g. $format wrapping $math) and are resolved by all four renderer integrations (React, Vue, Svelte, Solid).
defineDirective lives in @json-render/core (0.19+). A directive declares a Zod schema for its JSON shape and a resolve(raw, ctx) function — use resolvePropValue(raw.field, ctx) to recursively resolve any nested directive or state reference before computing.
import { defineDirective, resolvePropValue } from'@json-render/core'import { z } from'zod'exportconst initialsDirective = defineDirective({
name: '$initials',
description: 'First letter of each word, uppercased.',
schema: z.object({ $initials: z.unknown() }),
resolve(raw, ctx) {
const text = String(resolvePropValue(raw.$initials, ctx) ?? '')
return text.split(/\s+/).map((w) => w[0]?.toUpperCase() ?? '').join('')
},
})
Spread into the renderer alongside standardDirectives: directives={[...standardDirectives, initialsDirective]}. Keep the schema tight — directives are the only place where AI gets to emit non-catalog JSON, so let Zod enforce shape just like a component prop.
Upstream coverage (do not restate)
json-render ships its own per-package skills. This skill wraps them and keeps only the
delta: our Storybook import path, our catalog constraints, and the scars in
references/ork-delta.md. Do not copy vendor rosters or API tables back in.
Topic
First-party source
Core API (defineSchema, defineCatalog, prompts, spec streaming, validation, StateStore)
Developer defines a catalog — Zod-typed component definitions with constrained props
AI generates a spec — flat-tree JSON/YAML referencing only catalog components
Runtime renders the spec — <Renderer> component validates and renders each element
The catalog is the safety boundary. AI can only reference types that exist in the catalog, and props are validated against Zod schemas at runtime. This prevents hallucinated components and invalid props from reaching the UI.
Use jsonSchema({ strict: true }) to export catalog schemas compatible with LLM structured output APIs (OpenAI, Anthropic, Gemini):
// jsonSchema is a METHOD on the Catalog instance, not a top-level export.const schema = catalog.jsonSchema({ strict: true })
// Pass to OpenAI response_format, Anthropic tool_use, or Gemini structured output
The JSON spec is a flat tree — no nesting, just IDs and references. Field-by-field
documentation (root, elements, props, children, on, watch, state, and the
$state / $bindState / $cond / $template / $computed expressions) is upstream in
https://github.com/vercel-labs/json-renderskills/core/SKILL.md.
Event handlers, watch bindings, the built-in actions (setState, pushState,
removeState, validateForm) and the state adapters are upstream in
https://github.com/vercel-labs/json-renderskills/react/SKILL.md and the per-adapter
skills. Do not restate the roster here; see references/ork-delta.md for why.
YAML Mode — 30% Fewer Tokens
For standalone (non-streaming) generation, YAML specs use ~30% fewer tokens than JSON:
Use JSON for inline mode / streaming (JSON Patch RFC 6902 over JSONL requires JSON). Use YAML for standalone mode where token cost matters. Load rules/token-optimization.md for selection criteria.
Progressive Streaming
json-render supports progressive rendering during streaming. As the AI generates spec elements, they render immediately — the user sees the UI building in real-time. This uses JSON Patch (RFC 6902) operations streamed over JSONL:
Elements render as soon as their props are complete — no waiting for the full spec.
@json-render/shadcn — 36 Pre-Built Components
The @json-render/shadcn package provides a production-ready catalog of 36 components
with Zod schemas already defined. The component list and prop schemas are upstream in
https://github.com/vercel-labs/json-renderskills/shadcn/SKILL.md; shadcn/ui
composition itself is the vercel:shadcn skill.
Svelte:@json-render/shadcn-svelte (added in 0.16) mirrors the same 36 components for Svelte 5 + Tailwind projects.
The shadcn catalog components use default Tailwind classes. When your project uses a specific shadcn v4 style (Luma, Nova, etc.), override component implementations to match:
Detection pattern: Read components.json → "style" field to determine which overrides to apply. Style-specific class names: Luma (rounded-4xl, shadow-md, gap-6), Nova (compact px-2 py-1), Lyra (rounded-none).
Edit Modes — patch / merge / diff (0.14+)
For updating specs after initial render (AI-driven refinements, user edits, partial regenerations), core ships three universal edit modes:
Mode
Spec
When to use
patch
RFC 6902 JSON Patch
Precise, streamed diffs (already used for progressive streaming)
merge
RFC 7396 JSON Merge Patch
Simpler updates, whole-field replacements
diff
Unified diff of serialized spec
AI-native output when the model prefers plaintext diffs
import { deepMergeSpec, diffToPatches, buildEditUserPrompt } from'@json-render/core'// Ask the model for an edit in whichever format it finds easiestconst prompt = buildEditUserPrompt(currentSpec, instruction, { format: 'yaml', mode: 'merge' })
// Normalize any edit mode to RFC 6902 patches for applicationconst patches = diffToPatches(aiResponse)
const next = deepMergeSpec(currentSpec, patches)
buildUserPrompt() also gained format and serializer options in 0.14 — pick YAML for standalone specs and JSON for streaming.
Package Ecosystem
Core + 23 renderer/integration packages covering web, mobile, terminal, 3D, codegen, and state management. Load references/package-ecosystem.md for the full list organized by category.
Added since 0.13:
@json-render/yaml (0.14) — YAML wire format + streaming parser
AI generates UI and you need to constrain what it can produce
You want runtime-validated specs that prevent hallucinated components
You need cross-platform rendering (React, Vue, Svelte, React Native, PDF, email)
You are building generative UI features (dashboards, reports, forms from natural language)
Do NOT use json-render when:
Building static, developer-authored UI — use components directly
AI generates code (JSX/TSX) rather than specs — use standard code generation
You need full creative freedom without catalog constraints — json-render is deliberately restrictive
Performance-critical rendering with thousands of elements — the flat-tree abstraction adds overhead
Migrating from Custom GenUI
If you have existing custom generative UI (hand-rolled JSON-to-component mapping), the
target shape is the catalog plus flat-tree spec contract documented upstream in
https://github.com/vercel-labs/json-renderskills/core/SKILL.md. The order that works:
inventory your existing types, give each one a Zod schema in defineCatalog, flatten the
nested spec into root plus elements, move handler props onto the on field, then wrap
your existing components as catalog implementations.
Rule Details
Catalog Definition
How to define catalogs with defineCatalog() and Zod schemas.
Rule
File
Key Pattern
Catalog Definition
rules/catalog-definition.md
defineCatalog with Zod schemas, children types
Prop Constraints
Constraining props to prevent AI hallucination.
Rule
File
Key Pattern
Prop Constraints
rules/prop-constraints.md
z.enum, z.string().max(), z.array().max()
Token Optimization
Choosing JSON vs YAML for token efficiency.
Rule
File
Key Pattern
Token Optimization
rules/token-optimization.md
YAML for standalone mode, JSON for inline/streaming
Key Decisions
Decision
Recommendation
Custom vs shadcn catalog
Start with shadcn, extend with custom types for domain-specific components
JSON vs YAML spec format
YAML for standalone mode (30% fewer tokens), JSON for inline/streaming
Zod constraint strictness
Tighter is better — use z.enum over z.string, z.array().max() over unbounded
State management adapter
Match your app's existing state library (Zustand, Redux, Jotai, XState)
Common Mistakes
Using z.any() or z.unknown() in catalog props — defeats the purpose of catalog constraints, AI can generate anything
Always using JSON specs — wastes 30% tokens when inline/streaming is not needed (use YAML in standalone mode)
Nesting component definitions — json-render uses a flat tree; all elements are siblings referenced by ID
Re-declaring shadcn components instead of spreading shadcnComponentDefinitions — you lose the upstream Zod bounds
Not setting .max() on arrays — AI can generate unbounded lists that break layouts
Related Skills
ork:ai-ui-generation — AI-assisted UI generation patterns for v0, Bolt, Cursor
ork:ui-components — shadcn/ui component patterns and CVA variants
ork:component-search — Finding and evaluating React/Vue components
ork:design-to-code — Converting designs to production code