json-render-generative-ui
Generative UI framework that renders AI-generated JSON specs into type-safe UI components across React, Vue, Svelte, Solid, React Native, video, PDF, and email.
安装 / 下载方式
TotalClaw CLI推荐
totalclaw install github:LeoYeAI~openclaw-master-skills~json-render-generative-uicURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/github%3ALeoYeAI~openclaw-master-skills~json-render-generative-ui/file -o json-render-generative-ui.md# json-render Generative UI Framework
> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.
json-render is a **Generative UI framework** that lets AI generate dynamic interfaces from natural language prompts, constrained to a predefined component catalog. AI outputs JSON; json-render renders it safely and predictably across any platform.
## Installation
```bash
# React (core)
npm install @json-render/core @json-render/react
# React + shadcn/ui (36 pre-built components)
npm install @json-render/shadcn
# React Native
npm install @json-render/core @json-render/react-native
# Vue
npm install @json-render/core @json-render/vue
# Svelte
npm install @json-render/core @json-render/svelte
# SolidJS
npm install @json-render/core @json-render/solid
# Video (Remotion)
npm install @json-render/core @json-render/remotion
# PDF
npm install @json-render/core @json-render/react-pdf
# Email
npm install @json-render/core @json-render/react-email @react-email/components @react-email/render
# 3D (React Three Fiber)
npm install @json-render/core @json-render/react-three-fiber @react-three/fiber @react-three/drei three
# OG Images / SVG / PNG
npm install @json-render/core @json-render/image
# State management adapters
npm install @json-render/zustand # or redux, jotai, xstate
# MCP integration (Claude, ChatGPT, Cursor)
npm install @json-render/mcp
# YAML wire format
npm install @json-render/yaml
```
## Core Concepts
| Concept | Description |
|---|---|
| **Catalog** | Defines allowed components and actions (the guardrails for AI) |
| **Spec** | AI-generated JSON describing which components to render and with what props |
| **Registry** | Maps catalog component names to actual render implementations |
| **Renderer** | Platform-specific component that takes a spec + registry and renders UI |
| **Actions** | Named events AI can trigger (e.g. `export_report`, `refresh_data`) |
## Spec Format
The flat spec format uses a root key + elements map:
```typescript
const spec = {
root: "card-1",
elements: {
"card-1": {
type: "Card",
props: { title: "Dashboard" },
children: ["metric-1", "metric-2", "button-1"],
},
"metric-1": {
type: "Metric",
props: { label: "Revenue", value: "124000", format: "currency" },
children: [],
},
"metric-2": {
type: "Metric",
props: { label: "Growth", value: "0.18", format: "percent" },
children: [],
},
"button-1": {
type: "Button",
props: { label: "Export Report", action: "export_report" },
children: [],
},
},
};
```
## Step 1: Define a Catalog
```typescript
import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/react/schema";
import { z } from "zod";
const catalog = defineCatalog(schema, {
components: {
Card: {
props: z.object({ title: z.string() }),
description: "A card container with a title",
},
Metric: {
props: z.object({
label: z.string(),
value: z.string(),
format: z.enum(["currency", "percent", "number"]).nullable(),
}),
description: "Displays a single metric value with optional formatting",
},
Button: {
props: z.object({
label: z.string(),
action: z.string(),
}),
description: "Clickable button that triggers an action",
},
Stack: {
props: z.object({
direction: z.enum(["row", "column"]).default("column"),
gap: z.number().optional(),
}),
description: "Layout container that stacks children",
},
},
actions: {
export_report: { description: "Export the current dashboard to PDF" },
refresh_data: { description: "Refresh all metric data" },
navigate: {
description: "Navigate to a page",
payload: z.object({ path: z.string() }),
},
},
});
```
## Step 2: Define a Registry (React)
```tsx
import { defineRegistry, Renderer } from "@json-render/react";
function format(value: string, fmt: string | null): string {
if (fmt === "currency") return `$${Number(value).toLocaleString()}`;
if (fmt === "percent") return `${(Number(value) * 100).toFixed(1)}%`;
return value;
}
const { registry } = defineRegistry(catalog, {
components: {
Card: ({ props, children }) => (
<div className="rounded-lg border p-4 shadow-sm">
<h3 className="text-lg font-semibold mb-3">{props.title}</h3>
{children}
</div>
),
Metric: ({ props }) => (
<div className="flex flex-col">
<span className="text-sm text-gray-500">{props.label}</span>
<span className="text-2xl font-bold">
{format(props.value, props.format)}
</span>
</div>
),
Button: ({ props, emit }) => (
<button
className="px-4 py-2 bg-blue-600 text-white rounded"
onClick={() => emit("press")}
>
{props.label}
</button>
),
Stack: ({ props, children }) => (
<div
style={{
display: "flex",
flexDirection: props.direction ?? "column",
gap: props.gap ?? 8,
}}
>
{children}
</div>
),
},
});
```
## Step 3: Render the Spec
```tsx
import { Renderer } from "@json-render/react";
function Dashboard({ spec, onAction }) {
return (
<Renderer
spec={spec}
registry={registry}
onAction={(action, payload) => {
console.log("Action triggered:", action, payload);
onAction?.(action, payload);
}}
/>
);
}
```
## Generating Specs with AI (Vercel AI SDK)
```typescript
import { generateObject } from "ai";
import { openai } from "@ai-sdk/openai";
import { getCatalogSchema, getCatalogPrompt } from "@json-render/core";
async function generateDashboard(userPrompt: string) {
const { object: spec } = await generateObject({
model: openai("gpt-4o"),
schema: getCatalogSchema(catalog),
system: getCatalogPrompt(catalog),
prompt: userPrompt,
});
return spec;
}
// Usage
const spec = await generateDashboard(
"Create a sales dashboard showing revenue, conversion rate, and an export button"
);
```
## Streaming Specs
```tsx
import { streamObject } from "ai";
import { openai } from "@ai-sdk/openai";
import { getCatalogSchema, getCatalogPrompt, parseSpecStream } from "@json-render/core";
import { Renderer } from "@json-render/react";
import { useState, useEffect } from "react";
function StreamingDashboard({ prompt }: { prompt: string }) {
const [spec, setSpec] = useState(null);
useEffect(() => {
async function stream() {
const { partialObjectStream } = await streamObject({
model: openai("gpt-4o"),
schema: getCatalogSchema(catalog),
system: getCatalogPrompt(catalog),
prompt,
});
for await (const partial of partialObjectStream) {
setSpec(partial); // Renderer handles partial specs gracefully
}
}
stream();
}, [prompt]);
if (!spec) return <div>Generating UI...</div>;
return <Renderer spec={spec} registry={registry} />;
}
```
## Using Pre-built shadcn/ui Components
```tsx
import { defineCatalog } from "@json-render/core";
import { schema } from "@json-render/react/schema";
import { defineRegistry, Renderer } from "@json-render/react";
import { shadcnComponentDefinitions } from "@json-render/shadcn/catalog";
import { shadcnComponents } from "@json-render/shadcn";
// Pick any of the 36 available shadcn components
const catalog = defineCatalog(schema, {
components: {
Card: shadcnComponentDefinitions.Card,
Stack: shadcnComponentDefinitions.Stack,
Heading: shadcnComponentDefinitions.Heading,
Text: shadcnComponentDefinitions.Text,
Button: shadcnComponentDefinitions.Button,
Badge: shadcnComponentDefinitions.Badge,
Table: shadcnComponentDefinitions.Table,
Chart: shadcnComponentDefinitions.Chart,
Input: shadcnComponentDefinitions.Input,
Select: shadcnComponentDefinitions.Select,
},
action