[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-3886":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":25,"hasPages":23,"topics":26,"createdAt":10,"pushedAt":10,"updatedAt":27,"readmeContent":28,"aiSummary":29,"trendingCount":16,"starSnapshotCount":16,"syncStatus":30,"lastSyncTime":31,"discoverSource":32},3886,"json-render","vercel-labs\u002Fjson-render","vercel-labs","The Generative UI framework","https:\u002F\u002Fjson-render.dev",null,"TypeScript",15071,815,49,58,0,12,84,336,52,43.74,"Apache License 2.0",false,"main",true,[],"2026-06-12 02:00:55","# json-render\n\n**The Generative UI framework.**\n\nGenerate dynamic, personalized UIs from prompts without sacrificing reliability. Predefined components and actions for safe, predictable output.\n\n```bash\n# for React\nnpm install @json-render\u002Fcore @json-render\u002Freact\n# for React with pre-built shadcn\u002Fui components\nnpm install @json-render\u002Fshadcn\n# or for React Native\nnpm install @json-render\u002Fcore @json-render\u002Freact-native\n# or for video\nnpm install @json-render\u002Fcore @json-render\u002Fremotion\n# or for PDF documents\nnpm install @json-render\u002Fcore @json-render\u002Freact-pdf\n# or for HTML email\nnpm install @json-render\u002Fcore @json-render\u002Freact-email @react-email\u002Fcomponents @react-email\u002Frender\n# or for Vue\nnpm install @json-render\u002Fcore @json-render\u002Fvue\n# or for Svelte\nnpm install @json-render\u002Fcore @json-render\u002Fsvelte\n# or for SolidJS\nnpm install @json-render\u002Fcore @json-render\u002Fsolid\n# or for terminal UIs\nnpm install @json-render\u002Fcore @json-render\u002Fink ink react\n# or for full Next.js apps (routes, layouts, SSR, metadata)\nnpm install @json-render\u002Fcore @json-render\u002Freact @json-render\u002Fnext\n# or for 3D scenes (and gaussian splatting via the GaussianSplat component)\nnpm install @json-render\u002Fcore @json-render\u002Freact-three-fiber @react-three\u002Ffiber @react-three\u002Fdrei three\n```\n\n## Why json-render?\n\njson-render is a **Generative UI** framework: AI generates interfaces from natural language prompts, constrained to components you define. You set the guardrails, AI generates within them:\n\n- **Guardrailed** - AI can only use components in your catalog\n- **Predictable** - JSON output matches your schema, every time\n- **Fast** - Stream and render progressively as the model responds\n- **Cross-Platform** - React, Vue, Svelte, Solid (web), React Native (mobile) from the same catalog\n- **Batteries Included** - 36 pre-built shadcn\u002Fui components ready to use\n\n## Quick Start\n\n### 1. Define Your Catalog\n\n```typescript\nimport { defineCatalog } from \"@json-render\u002Fcore\";\nimport { schema } from \"@json-render\u002Freact\u002Fschema\";\nimport { z } from \"zod\";\n\nconst catalog = defineCatalog(schema, {\n  components: {\n    Card: {\n      props: z.object({ title: z.string() }),\n      description: \"A card container\",\n    },\n    Metric: {\n      props: z.object({\n        label: z.string(),\n        value: z.string(),\n        format: z.enum([\"currency\", \"percent\", \"number\"]).nullable(),\n      }),\n      description: \"Display a metric value\",\n    },\n    Button: {\n      props: z.object({\n        label: z.string(),\n        action: z.string(),\n      }),\n      description: \"Clickable button\",\n    },\n  },\n  actions: {\n    export_report: { description: \"Export dashboard to PDF\" },\n    refresh_data: { description: \"Refresh all metrics\" },\n  },\n});\n```\n\n### 2. Define Your Components\n\n```tsx\nimport { defineRegistry, Renderer } from \"@json-render\u002Freact\";\n\nconst { registry } = defineRegistry(catalog, {\n  components: {\n    Card: ({ props, children }) => (\n      \u003Cdiv className=\"card\">\n        \u003Ch3>{props.title}\u003C\u002Fh3>\n        {children}\n      \u003C\u002Fdiv>\n    ),\n    Metric: ({ props }) => (\n      \u003Cdiv className=\"metric\">\n        \u003Cspan>{props.label}\u003C\u002Fspan>\n        \u003Cspan>{format(props.value, props.format)}\u003C\u002Fspan>\n      \u003C\u002Fdiv>\n    ),\n    Button: ({ props, emit }) => (\n      \u003Cbutton onClick={() => emit(\"press\")}>{props.label}\u003C\u002Fbutton>\n    ),\n  },\n});\n```\n\n### 3. Render AI-Generated Specs\n\n```tsx\nfunction Dashboard({ spec }) {\n  return \u003CRenderer spec={spec} registry={registry} \u002F>;\n}\n```\n\n**That's it.** AI generates JSON, you render it safely.\n\n---\n\n## Packages\n\n| Package                     | Description                                                            |\n| --------------------------- | ---------------------------------------------------------------------- |\n| `@json-render\u002Fcore`         | Schemas, catalogs, AI prompts, dynamic props, SpecStream utilities     |\n| `@json-render\u002Freact`        | React renderer, contexts, hooks                                        |\n| `@json-render\u002Fvue`          | Vue 3 renderer, composables, providers                                 |\n| `@json-render\u002Fsvelte`       | Svelte 5 renderer with runes-based reactivity                          |\n| `@json-render\u002Fsolid`        | SolidJS renderer with fine-grained reactive contexts                   |\n| `@json-render\u002Fshadcn`       | 36 pre-built shadcn\u002Fui components (Radix UI + Tailwind CSS)            |\n| `@json-render\u002Fshadcn-svelte`| 36 pre-built shadcn-svelte components (Svelte 5 + Tailwind CSS)        |\n| `@json-render\u002Freact-three-fiber` | React Three Fiber renderer for 3D scenes (20 built-in components, including GaussianSplat)  |\n| `@json-render\u002Freact-native` | React Native renderer with standard mobile components                  |\n| `@json-render\u002Fnext`         | Next.js renderer — JSON becomes full apps with routes, layouts, SSR    |\n| `@json-render\u002Fremotion`     | Remotion video renderer, timeline schema                               |\n| `@json-render\u002Freact-pdf`    | React PDF renderer for generating PDF documents from specs             |\n| `@json-render\u002Freact-email`  | React Email renderer for HTML\u002Fplain-text emails from specs             |\n| `@json-render\u002Fink`          | Ink terminal renderer with built-in components for interactive TUIs.   |\n| `@json-render\u002Fimage`        | Image renderer for SVG\u002FPNG output (OG images, social cards) via Satori |\n| `@json-render\u002Fcodegen`      | Utilities for generating code from json-render UI trees                |\n| `@json-render\u002Fdevtools`     | Framework-agnostic devtools core — panel UI, event store, picker, stream taps |\n| `@json-render\u002Fdevtools-react`   | React adapter for `@json-render\u002Fdevtools` (drop-in `\u003CJsonRenderDevtools \u002F>`)     |\n| `@json-render\u002Fdevtools-vue`     | Vue adapter for `@json-render\u002Fdevtools`                                           |\n| `@json-render\u002Fdevtools-svelte`  | Svelte adapter for `@json-render\u002Fdevtools`                                        |\n| `@json-render\u002Fdevtools-solid`   | SolidJS adapter for `@json-render\u002Fdevtools`                                       |\n| `@json-render\u002Fredux`        | Redux \u002F Redux Toolkit adapter for `StateStore`                         |\n| `@json-render\u002Fzustand`      | Zustand adapter for `StateStore`                                       |\n| `@json-render\u002Fjotai`        | Jotai adapter for `StateStore`                                         |\n| `@json-render\u002Fxstate`       | XState Store (atom) adapter for `StateStore`                           |\n| `@json-render\u002Fmcp`          | MCP Apps integration for Claude, ChatGPT, Cursor, VS Code              |\n| `@json-render\u002Fyaml`         | YAML wire format with streaming parser, edit modes, AI SDK transform   |\n\n## Renderers\n\n### React (UI)\n\n```tsx\nimport { defineRegistry, Renderer } from \"@json-render\u002Freact\";\nimport { schema } from \"@json-render\u002Freact\u002Fschema\";\n\n\u002F\u002F Flat spec format (root key + elements map)\nconst spec = {\n  root: \"card-1\",\n  elements: {\n    \"card-1\": {\n      type: \"Card\",\n      props: { title: \"Hello\" },\n      children: [\"button-1\"],\n    },\n    \"button-1\": {\n      type: \"Button\",\n      props: { label: \"Click me\" },\n      children: [],\n    },\n  },\n};\n\n\u002F\u002F defineRegistry creates a type-safe component registry\nconst { registry } = defineRegistry(catalog, { components });\n\u003CRenderer spec={spec} registry={registry} \u002F>;\n```\n\n### Vue (UI)\n\n```typescript\nimport { h } from \"vue\";\nimport { defineRegistry, Renderer } from \"@json-render\u002Fvue\";\nimport { schema } from \"@json-render\u002Fvue\u002Fschema\";\n\nconst { registry } = defineRegistry(catalog, {\n  components: {\n    Card: ({ props, children }) =>\n      h(\"div\", { class: \"card\" }, [h(\"h3\", null, props.title), children]),\n    Button: ({ props, emit }) =>\n      h(\"button\", { onClick: () => emit(\"press\") }, props.label),\n  },\n});\n\n\u002F\u002F In your Vue component template:\n\u002F\u002F \u003CRenderer :spec=\"spec\" :registry=\"registry\" \u002F>\n```\n\n### Svelte (UI)\n\n```typescript\nimport { defineRegistry, Renderer } from \"@json-render\u002Fsvelte\";\nimport { schema } from \"@json-render\u002Fsvelte\u002Fschema\";\n\nconst { registry } = defineRegistry(catalog, {\n  components: {\n    Card: ({ props, children }) => \u002F* Svelte 5 snippet *\u002F,\n    Button: ({ props, emit }) => \u002F* Svelte 5 snippet *\u002F,\n  },\n});\n\n\u002F\u002F In your Svelte component:\n\u002F\u002F \u003CRenderer spec={spec} registry={registry} \u002F>\n```\n\n### Solid (UI)\n\n```tsx\nimport { defineRegistry, Renderer } from \"@json-render\u002Fsolid\";\nimport { schema } from \"@json-render\u002Fsolid\u002Fschema\";\n\nconst { registry } = defineRegistry(catalog, {\n  components: {\n    Card: (renderProps) => \u003Cdiv>{renderProps.children}\u003C\u002Fdiv>,\n    Button: (renderProps) => (\n      \u003Cbutton onClick={() => renderProps.emit(\"press\")}>\n        {renderProps.element.props.label as string}\n      \u003C\u002Fbutton>\n    ),\n  },\n});\n\n\u003CRenderer spec={spec} registry={registry} \u002F>;\n```\n\n### shadcn\u002Fui (Web)\n\n```tsx\nimport { defineCatalog } from \"@json-render\u002Fcore\";\nimport { schema } from \"@json-render\u002Freact\u002Fschema\";\nimport { defineRegistry, Renderer } from \"@json-render\u002Freact\";\nimport { shadcnComponentDefinitions } from \"@json-render\u002Fshadcn\u002Fcatalog\";\nimport { shadcnComponents } from \"@json-render\u002Fshadcn\";\n\n\u002F\u002F Pick components from the 36 standard definitions\nconst catalog = defineCatalog(schema, {\n  components: {\n    Card: shadcnComponentDefinitions.Card,\n    Stack: shadcnComponentDefinitions.Stack,\n    Heading: shadcnComponentDefinitions.Heading,\n    Button: shadcnComponentDefinitions.Button,\n  },\n  actions: {},\n});\n\n\u002F\u002F Use matching implementations\nconst { registry } = defineRegistry(catalog, {\n  components: {\n    Card: shadcnComponents.Card,\n    Stack: shadcnComponents.Stack,\n    Heading: shadcnComponents.Heading,\n    Button: shadcnComponents.Button,\n  },\n});\n\n\u003CRenderer spec={spec} registry={registry} \u002F>;\n```\n\n### React Native (Mobile)\n\n```tsx\nimport { defineCatalog } from \"@json-render\u002Fcore\";\nimport { schema } from \"@json-render\u002Freact-native\u002Fschema\";\nimport {\n  standardComponentDefinitions,\n  standardActionDefinitions,\n} from \"@json-render\u002Freact-native\u002Fcatalog\";\nimport { defineRegistry, Renderer } from \"@json-render\u002Freact-native\";\n\n\u002F\u002F 25+ standard components included\nconst catalog = defineCatalog(schema, {\n  components: { ...standardComponentDefinitions },\n  actions: standardActionDefinitions,\n});\n\nconst { registry } = defineRegistry(catalog, { components: {} });\n\u003CRenderer spec={spec} registry={registry} \u002F>;\n```\n\n### Remotion (Video)\n\n```tsx\nimport { Player } from \"@remotion\u002Fplayer\";\nimport {\n  Renderer,\n  schema,\n  standardComponentDefinitions,\n} from \"@json-render\u002Fremotion\";\n\n\u002F\u002F Timeline spec format\nconst spec = {\n  composition: {\n    id: \"video\",\n    fps: 30,\n    width: 1920,\n    height: 1080,\n    durationInFrames: 300,\n  },\n  tracks: [{ id: \"main\", name: \"Main\", type: \"video\", enabled: true }],\n  clips: [\n    {\n      id: \"clip-1\",\n      trackId: \"main\",\n      component: \"TitleCard\",\n      props: { title: \"Hello\" },\n      from: 0,\n      durationInFrames: 90,\n    },\n  ],\n  audio: { tracks: [] },\n};\n\n\u003CPlayer\n  component={Renderer}\n  inputProps={{ spec }}\n  durationInFrames={spec.composition.durationInFrames}\n  fps={spec.composition.fps}\n  compositionWidth={spec.composition.width}\n  compositionHeight={spec.composition.height}\n\u002F>;\n```\n\n### React PDF (Documents)\n\n```typescript\nimport { renderToBuffer } from \"@json-render\u002Freact-pdf\";\n\nconst spec = {\n  root: \"doc\",\n  elements: {\n    doc: {\n      type: \"Document\",\n      props: { title: \"Invoice\" },\n      children: [\"page-1\"],\n    },\n    \"page-1\": {\n      type: \"Page\",\n      props: { size: \"A4\" },\n      children: [\"heading-1\", \"table-1\"],\n    },\n    \"heading-1\": {\n      type: \"Heading\",\n      props: { text: \"Invoice #1234\", level: \"h1\" },\n      children: [],\n    },\n    \"table-1\": {\n      type: \"Table\",\n      props: {\n        columns: [\n          { header: \"Item\", width: \"60%\" },\n          { header: \"Price\", width: \"40%\", align: \"right\" },\n        ],\n        rows: [\n          [\"Widget A\", \"$10.00\"],\n          [\"Widget B\", \"$25.00\"],\n        ],\n      },\n      children: [],\n    },\n  },\n};\n\n\u002F\u002F Render to buffer, stream, or file\nconst buffer = await renderToBuffer(spec);\n```\n\n### React Email (Email)\n\n```typescript\nimport { renderToHtml } from \"@json-render\u002Freact-email\";\nimport { schema, standardComponentDefinitions } from \"@json-render\u002Freact-email\";\nimport { defineCatalog } from \"@json-render\u002Fcore\";\n\nconst catalog = defineCatalog(schema, {\n  components: standardComponentDefinitions,\n});\n\nconst spec = {\n  root: \"html-1\",\n  elements: {\n    \"html-1\": {\n      type: \"Html\",\n      props: { lang: \"en\", dir: \"ltr\" },\n      children: [\"head-1\", \"body-1\"],\n    },\n    \"head-1\": { type: \"Head\", props: {}, children: [] },\n    \"body-1\": {\n      type: \"Body\",\n      props: { style: { backgroundColor: \"#f6f9fc\" } },\n      children: [\"container-1\"],\n    },\n    \"container-1\": {\n      type: \"Container\",\n      props: {\n        style: { maxWidth: \"600px\", margin: \"0 auto\", padding: \"20px\" },\n      },\n      children: [\"heading-1\", \"text-1\"],\n    },\n    \"heading-1\": { type: \"Heading\", props: { text: \"Welcome\" }, children: [] },\n    \"text-1\": {\n      type: \"Text\",\n      props: { text: \"Thanks for signing up.\" },\n      children: [],\n    },\n  },\n};\n\nconst html = await renderToHtml(spec);\n```\n\n### Image (SVG\u002FPNG)\n\n```typescript\nimport { renderToPng } from \"@json-render\u002Fimage\u002Frender\";\n\nconst spec = {\n  root: \"frame\",\n  elements: {\n    frame: {\n      type: \"Frame\",\n      props: { width: 1200, height: 630, backgroundColor: \"#1a1a2e\" },\n      children: [\"heading\"],\n    },\n    heading: {\n      type: \"Heading\",\n      props: { text: \"Hello World\", level: \"h1\", color: \"#ffffff\" },\n      children: [],\n    },\n  },\n};\n\n\u002F\u002F Render to PNG (requires @resvg\u002Fresvg-js)\nconst png = await renderToPng(spec, { fonts });\n\n\u002F\u002F Or render to SVG string\nimport { renderToSvg } from \"@json-render\u002Fimage\u002Frender\";\nconst svg = await renderToSvg(spec, { fonts });\n```\n\n### Three.js (3D)\n\n```tsx\nimport { defineCatalog } from \"@json-render\u002Fcore\";\nimport { schema, defineRegistry } from \"@json-render\u002Freact\";\nimport {\n  threeComponentDefinitions,\n  threeComponents,\n  ThreeCanvas,\n} from \"@json-render\u002Freact-three-fiber\";\n\nconst catalog = defineCatalog(schema, {\n  components: {\n    Box: threeComponentDefinitions.Box,\n    Sphere: threeComponentDefinitions.Sphere,\n    AmbientLight: threeComponentDefinitions.AmbientLight,\n    DirectionalLight: threeComponentDefinitions.DirectionalLight,\n    GaussianSplat: threeComponentDefinitions.GaussianSplat,\n    OrbitControls: threeComponentDefinitions.OrbitControls,\n  },\n  actions: {},\n});\n\nconst { registry } = defineRegistry(catalog, {\n  components: {\n    Box: threeComponents.Box,\n    Sphere: threeComponents.Sphere,\n    AmbientLight: threeComponents.AmbientLight,\n    DirectionalLight: threeComponents.DirectionalLight,\n    GaussianSplat: threeComponents.GaussianSplat,\n    OrbitControls: threeComponents.OrbitControls,\n  },\n});\n\n\u003CThreeCanvas\n  spec={spec}\n  registry={registry}\n  shadows\n  camera={{ position: [5, 5, 5], fov: 50 }}\n  style={{ width: \"100%\", height: \"100vh\" }}\n\u002F>;\n```\n\n### Next.js (Full Apps)\n\n```typescript\nimport type { NextAppSpec } from \"@json-render\u002Fnext\";\nimport { createNextApp } from \"@json-render\u002Fnext\u002Fserver\";\nimport { NextAppProvider } from \"@json-render\u002Fnext\";\n\nconst spec: NextAppSpec = {\n  metadata: { title: { default: \"My App\", template: \"%s | My App\" } },\n  layouts: {\n    main: {\n      root: \"shell\",\n      elements: {\n        shell: { type: \"Container\", props: {}, children: [\"nav\", \"slot\"] },\n        nav: { type: \"NavBar\", props: {}, children: [] },\n        slot: { type: \"Slot\", props: {}, children: [] },\n      },\n    },\n  },\n  routes: {\n    \"\u002F\": {\n      layout: \"main\",\n      metadata: { title: \"Home\" },\n      page: {\n        root: \"hero\",\n        elements: {\n          hero: { type: \"Card\", props: { title: \"Welcome\" }, children: [] },\n        },\n      },\n    },\n  },\n};\n\n\u002F\u002F Server: creates Page, generateMetadata, generateStaticParams\nconst app = createNextApp({ spec });\n\n\u002F\u002F Client: wrap your layout with NextAppProvider\n\u002F\u002F \u003CNextAppProvider registry={registry} handlers={handlers}>\n\u002F\u002F   {children}\n\u002F\u002F \u003C\u002FNextAppProvider>\n```\n\n### shadcn-svelte (Svelte)\n\n```typescript\nimport { defineCatalog } from \"@json-render\u002Fcore\";\nimport { schema } from \"@json-render\u002Fsvelte\u002Fschema\";\nimport { defineRegistry, Renderer } from \"@json-render\u002Fsvelte\";\nimport { shadcnComponentDefinitions } from \"@json-render\u002Fshadcn-svelte\u002Fcatalog\";\nimport { shadcnComponents } from \"@json-render\u002Fshadcn-svelte\";\n\nconst catalog = defineCatalog(schema, {\n  components: {\n    Card: shadcnComponentDefinitions.Card,\n    Stack: shadcnComponentDefinitions.Stack,\n    Heading: shadcnComponentDefinitions.Heading,\n    Button: shadcnComponentDefinitions.Button,\n  },\n  actions: {},\n});\n\nconst { registry } = defineRegistry(catalog, {\n  components: {\n    Card: shadcnComponents.Card,\n    Stack: shadcnComponents.Stack,\n    Heading: shadcnComponents.Heading,\n    Button: shadcnComponents.Button,\n  },\n});\n\n\u002F\u002F In your Svelte component:\n\u002F\u002F \u003CRenderer spec={spec} registry={registry} \u002F>\n```\n\n### Devtools\n\nDrop-in inspector panel for any json-render app. Spec tree, state editor, action log, stream log, catalog browser, DOM picker.\n\n```tsx\n\u002F\u002F React\nimport { JsonRenderDevtools } from \"@json-render\u002Fdevtools-react\";\n\n\u003CJSONUIProvider registry={registry} handlers={handlers}>\n  \u003CRenderer spec={spec} registry={registry} \u002F>\n  \u003CJsonRenderDevtools spec={spec} catalog={catalog} messages={messages} \u002F>\n\u003C\u002FJSONUIProvider>;\n```\n\nFloating toggle appears bottom-right. Hotkey: `Ctrl`\u002F`Cmd` + `Shift` + `J`. Tree-shakes to `null` in production.\n\nAvailable for React, Vue, Svelte, and Solid — swap `@json-render\u002Fdevtools-react` for the adapter that matches your renderer.\n\n### Ink (Terminal)\n\n```tsx\nimport { defineCatalog } from \"@json-render\u002Fcore\";\nimport {\n  schema,\n  standardComponentDefinitions,\n  standardActionDefinitions,\n  defineRegistry,\n  Renderer,\n  JSONUIProvider,\n} from \"@json-render\u002Fink\";\n\nconst catalog = defineCatalog(schema, {\n  components: { ...standardComponentDefinitions },\n  actions: standardActionDefinitions,\n});\n\nconst { registry } = defineRegistry(catalog, { components: {} });\n\nconst spec = {\n  root: \"card-1\",\n  elements: {\n    \"card-1\": {\n      type: \"Card\",\n      props: { title: \"Status\" },\n      children: [\"status-1\"],\n    },\n    \"status-1\": {\n      type: \"StatusLine\",\n      props: { label: \"Build\", status: \"success\" },\n      children: [],\n    },\n  },\n};\n\n\u003CJSONUIProvider initialState={{}}>\n  \u003CRenderer spec={spec} registry={registry} \u002F>\n\u003C\u002FJSONUIProvider>;\n```\n\n## Features\n\n### Streaming (SpecStream)\n\nStream AI responses progressively:\n\n```typescript\nimport { createSpecStreamCompiler } from \"@json-render\u002Fcore\";\n\nconst compiler = createSpecStreamCompiler\u003CMySpec>();\n\n\u002F\u002F Process chunks as they arrive\nconst { result, newPatches } = compiler.push(chunk);\nsetSpec(result); \u002F\u002F Update UI with partial result\n\n\u002F\u002F Get final result\nconst finalSpec = compiler.getResult();\n```\n\n### AI Prompt Generation\n\nGenerate system prompts from your catalog:\n\n```typescript\nconst systemPrompt = catalog.prompt();\n\u002F\u002F Includes component descriptions, props schemas, available actions\n```\n\n### Conditional Visibility\n\n```json\n{\n  \"type\": \"Alert\",\n  \"props\": { \"message\": \"Error occurred\" },\n  \"visible\": [\n    { \"$state\": \"\u002Fform\u002FhasError\" },\n    { \"$state\": \"\u002Fform\u002FerrorDismissed\", \"not\": true }\n  ]\n}\n```\n\n### Dynamic Props\n\nAny prop value can be data-driven using expressions:\n\n```json\n{\n  \"type\": \"Icon\",\n  \"props\": {\n    \"name\": {\n      \"$cond\": { \"$state\": \"\u002FactiveTab\", \"eq\": \"home\" },\n      \"$then\": \"home\",\n      \"$else\": \"home-outline\"\n    },\n    \"color\": {\n      \"$cond\": { \"$state\": \"\u002FactiveTab\", \"eq\": \"home\" },\n      \"$then\": \"#007AFF\",\n      \"$else\": \"#8E8E93\"\n    }\n  }\n}\n```\n\nExpression forms:\n\n- **`{ \"$state\": \"\u002Fstate\u002Fkey\" }`** - reads a value from the state model\n- **`{ \"$cond\": \u003Ccondition>, \"$then\": \u003Cvalue>, \"$else\": \u003Cvalue> }`** - evaluates a condition and picks a branch\n- **`{ \"$template\": \"Hello, ${\u002Fuser\u002Fname}!\" }`** - interpolates state values into strings\n- **`{ \"$computed\": \"fn\", \"args\": { ... } }`** - calls a registered function with resolved args\n\n### Actions\n\nComponents can trigger actions, including the built-in `setState` action:\n\n```json\n{\n  \"type\": \"Pressable\",\n  \"props\": {\n    \"action\": \"setState\",\n    \"actionParams\": { \"statePath\": \"\u002FactiveTab\", \"value\": \"home\" }\n  },\n  \"children\": [\"home-icon\"]\n}\n```\n\nThe `setState` action updates the state model directly, which re-evaluates visibility conditions and dynamic prop expressions.\n\n### State Watchers\n\nReact to state changes by triggering actions:\n\n```json\n{\n  \"type\": \"Select\",\n  \"props\": {\n    \"value\": { \"$bindState\": \"\u002Fform\u002Fcountry\" },\n    \"options\": [\"US\", \"Canada\", \"UK\"]\n  },\n  \"watch\": {\n    \"\u002Fform\u002Fcountry\": {\n      \"action\": \"loadCities\",\n      \"params\": { \"country\": { \"$state\": \"\u002Fform\u002Fcountry\" } }\n    }\n  }\n}\n```\n\n`watch` is a top-level field on elements (sibling of `type`\u002F`props`\u002F`children`). Watchers fire when the watched value changes, not on initial render.\n\n---\n\n## Demo\n\n```bash\ngit clone https:\u002F\u002Fgithub.com\u002Fvercel-labs\u002Fjson-render\ncd json-render\npnpm install\npnpm dev\n```\n\n- http:\u002F\u002Fjson-render.localhost:1355 - Docs & Playground\n- http:\u002F\u002Fdashboard-demo.json-render.localhost:1355 - Example Dashboard\n- http:\u002F\u002Freact-email-demo.json-render.localhost:1355 - React Email Example\n- http:\u002F\u002Fremotion-demo.json-render.localhost:1355 - Remotion Video Example\n- Chat Example: run `pnpm dev` in `examples\u002Fchat`\n- Svelte Example: run `pnpm dev` in `examples\u002Fsvelte` or `examples\u002Fsvelte-chat`\n- Vue Example: run `pnpm dev` in `examples\u002Fvue`\n- Vite Renderers (React + Vue + Svelte + Solid): run `pnpm dev` in `examples\u002Fvite-renderers`\n- React Native example: run `npx expo start` in `examples\u002Freact-native`\n- Gaussian Splatting (R3F): run `pnpm dev` in `examples\u002Freact-three-fiber-gsplat`\n- Gaussian Splatting (experimental standalone gsplat.js demo): run `pnpm dev` in `examples\u002Fgsplat`\n\n## How It Works\n\n```mermaid\nflowchart LR\n    A[User Prompt] --> B[AI + Catalog]\n    B --> C[JSON Spec]\n    C --> D[Renderer]\n\n    B -.- E([guardrailed])\n    C -.- F([predictable])\n    D -.- G([streamed])\n```\n\n1. **Define the guardrails** - what components, actions, and data bindings AI can use\n2. **Prompt** - describe what you want in natural language\n3. **AI generates JSON** - output is always predictable, constrained to your catalog\n4. **Render fast** - stream and render progressively as the model responds\n\n## License\n\nApache-2.0\n","json-render 是一个生成式UI框架，能够根据自然语言提示生成动态且个性化的用户界面。它支持多种前端技术栈，包括React、Vue、Svelte等，并且提供了丰富的预构建组件库（如shadcn\u002Fui），确保生成的UI既安全又可预测。该框架通过定义组件和动作来设置约束条件，使得AI只能在这些范围内生成内容，从而保证了输出的一致性和可靠性。此外，json-render还支持跨平台开发，无论是Web端还是移动端应用，甚至是PDF文档或电子邮件模板，都能轻松应对。适用于需要快速原型设计、多平台兼容性以及希望利用AI辅助进行界面设计的各种开发场景。",2,"2026-06-11 02:56:55","top_language"]