mirror of
https://github.com/vercel-labs/json-render.git
synced 2026-10-03 20:38:21 +08:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
090dffa489 | ||
|
|
66e6e36b7b |
@@ -1,8 +1,8 @@
|
|||||||
# json-render
|
# json-render
|
||||||
|
|
||||||
**Predictable. Guardrailed. Fast.**
|
**The framework for User-Generated Interfaces (UGI).**
|
||||||
|
|
||||||
Let end users generate dashboards, widgets, apps, and videos from prompts — safely constrained to components you define.
|
Dynamic, personalized UIs per user without sacrificing reliability. Predefined components and actions for safe, predictable output.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install @json-render/core @json-render/react
|
npm install @json-render/core @json-render/react
|
||||||
@@ -14,11 +14,12 @@ npm install @json-render/core @json-render/remotion
|
|||||||
|
|
||||||
## Why json-render?
|
## Why json-render?
|
||||||
|
|
||||||
When users prompt for UI, you need guarantees. json-render gives AI a **constrained vocabulary** so output is always predictable:
|
json-render enables **User-Generated Interfaces**: dynamic UIs that end users create through natural language prompts, powered by Generative UI. You define the guardrails, AI generates within them:
|
||||||
|
|
||||||
- **Guardrailed** — AI can only use components in your catalog
|
- **Guardrailed** - AI can only use components in your catalog
|
||||||
- **Predictable** — JSON output matches your schema, every time
|
- **Predictable** - JSON output matches your schema, every time
|
||||||
- **Fast** — Stream and render progressively as the model responds
|
- **Fast** - Stream and render progressively as the model responds
|
||||||
|
- **Cross-Platform** - React (web) and React Native (mobile) from the same catalog
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@@ -237,8 +238,8 @@ Any prop value can be data-driven using expressions:
|
|||||||
|
|
||||||
Two expression forms:
|
Two expression forms:
|
||||||
|
|
||||||
- **`{ "$path": "/state/key" }`** -- reads a value from the data model
|
- **`{ "$path": "/state/key" }`** - reads a value from the data model
|
||||||
- **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** -- evaluates a condition (same syntax as visibility conditions) and picks a branch
|
- **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** - evaluates a condition (same syntax as visibility conditions) and picks a branch
|
||||||
|
|
||||||
### Actions
|
### Actions
|
||||||
|
|
||||||
@@ -265,9 +266,9 @@ pnpm install
|
|||||||
pnpm dev
|
pnpm dev
|
||||||
```
|
```
|
||||||
|
|
||||||
- http://localhost:3000 -- Docs & Playground
|
- http://localhost:3000 - Docs & Playground
|
||||||
- http://localhost:3001 -- Example Dashboard
|
- http://localhost:3001 - Example Dashboard
|
||||||
- http://localhost:3002 -- Remotion Video Example
|
- http://localhost:3002 - Remotion Video Example
|
||||||
- React Native example: run `npx expo start` in `examples/react-native`
|
- React Native example: run `npx expo start` in `examples/react-native`
|
||||||
|
|
||||||
## How It Works
|
## How It Works
|
||||||
@@ -283,10 +284,10 @@ flowchart LR
|
|||||||
D -.- G([streamed])
|
D -.- G([streamed])
|
||||||
```
|
```
|
||||||
|
|
||||||
1. **Define the guardrails** — what components, actions, and data bindings AI can use
|
1. **Define the guardrails** - what components, actions, and data bindings AI can use
|
||||||
2. **Users prompt** — end users describe what they want in natural language
|
2. **Users generate** - end users describe what they want in natural language
|
||||||
3. **AI generates JSON** — output is always predictable, constrained to your catalog
|
3. **AI generates JSON** - output is always predictable, constrained to your catalog
|
||||||
4. **Render fast** — stream and render progressively as the model responds
|
4. **Render fast** - stream and render progressively as the model responds
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ React Native renderer with standard components, providers, and hooks.
|
|||||||
|
|
||||||
## defineRegistry
|
## defineRegistry
|
||||||
|
|
||||||
Create a type-safe component registry. Standard components are built-in -- only register custom components.
|
Create a type-safe component registry. Standard components are built-in; only register custom components.
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import { defineRegistry, type Components } from '@json-render/react-native';
|
import { defineRegistry, type Components } from '@json-render/react-native';
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ const fixed = autoFixSpec(spec);
|
|||||||
|
|
||||||
### Improved: State Management
|
### Improved: State Management
|
||||||
|
|
||||||
`DataProvider` has been renamed to `StateProvider` with a clearer API. State is now a first-class part of specs -- elements can bind to state via `$path` expressions, and the built-in `setState` action updates state directly.
|
`DataProvider` has been renamed to `StateProvider` with a clearer API. State is now a first-class part of specs. Elements can bind to state via `$path` expressions, and the built-in `setState` action updates state directly.
|
||||||
|
|
||||||
### Improved: AI Prompts
|
### Improved: AI Prompts
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,19 @@ export const metadata = { title: "Introduction" }
|
|||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
Predictable. Guardrailed. Fast. Let users generate dashboards, widgets, apps, and data visualizations from prompts.
|
The framework for User-Generated Interfaces (UGI). Dynamic, personalized UIs per user without sacrificing reliability.
|
||||||
|
|
||||||
## What is json-render?
|
## What is json-render?
|
||||||
|
|
||||||
json-render lets end users generate UI from natural language prompts — safely constrained to components you define. You set the guardrails: what components exist, what props they take, what actions are available. AI generates JSON that matches your schema, and your components render it natively.
|
json-render is the framework for **User-Generated Interfaces**: dynamic UIs that end users generate through natural language prompts, powered by Generative UI. You define the guardrails: what components exist, what props they take, what actions are available. AI generates JSON that matches your schema, and your components render it natively on web or mobile.
|
||||||
|
|
||||||
|
Every interface is unique to the user, but every interface is safe and predictable.
|
||||||
|
|
||||||
## Why json-render?
|
## Why json-render?
|
||||||
|
|
||||||
### Guardrailed
|
### Guardrailed
|
||||||
|
|
||||||
AI can only use components in your catalog. No arbitrary code generation.
|
AI can only use components in your catalog. No arbitrary code generation. Predefined components and actions for safe, predictable output.
|
||||||
|
|
||||||
### Predictable
|
### Predictable
|
||||||
|
|
||||||
@@ -22,9 +24,13 @@ JSON output matches your schema, every time. Actions are declared by name, you c
|
|||||||
|
|
||||||
Stream and render progressively as the model responds. No waiting for completion.
|
Stream and render progressively as the model responds. No waiting for completion.
|
||||||
|
|
||||||
|
### Cross-Platform
|
||||||
|
|
||||||
|
Render on web with React and on mobile with React Native from the same catalog and spec format.
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
1. Define the guardrails — what components, actions, and data bindings AI can use
|
1. Define the guardrails - what components, actions, and data bindings AI can use
|
||||||
2. Users prompt — end users describe what they want in natural language
|
2. Users generate - end users describe what they want in natural language
|
||||||
3. AI generates JSON — output is always predictable, constrained to your catalog
|
3. AI generates JSON - output is always predictable, constrained to your catalog
|
||||||
4. Render fast — stream and render progressively as the model responds
|
4. Render fast - stream and render progressively as the model responds
|
||||||
|
|||||||
@@ -9,12 +9,15 @@ export default function Home() {
|
|||||||
<>
|
<>
|
||||||
{/* Hero */}
|
{/* Hero */}
|
||||||
<section className="max-w-5xl mx-auto px-6 pt-24 pb-16 text-center">
|
<section className="max-w-5xl mx-auto px-6 pt-24 pb-16 text-center">
|
||||||
<h1 className="text-5xl sm:text-6xl md:text-7xl font-bold tracking-tighter mb-6">
|
<p className="text-xs sm:text-sm font-medium text-muted-foreground tracking-widest uppercase mb-4">
|
||||||
|
The framework for User-Generated Interfaces
|
||||||
|
</p>
|
||||||
|
<h1 className="text-4xl sm:text-6xl md:text-7xl font-bold tracking-tighter mb-6">
|
||||||
AI → json-render → UI
|
AI → json-render → UI
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-lg text-muted-foreground max-w-2xl mx-auto mb-12 leading-relaxed">
|
<p className="text-lg text-muted-foreground max-w-2xl mx-auto mb-12 leading-relaxed">
|
||||||
Define a component catalog. Users prompt. AI outputs JSON constrained
|
Dynamic, personalized UIs per user without sacrificing reliability.
|
||||||
to your catalog. Your components render it.
|
Predefined components and actions for safe, predictable output.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<Demo />
|
<Demo />
|
||||||
@@ -65,10 +68,10 @@ export default function Home() {
|
|||||||
<div className="text-xs text-muted-foreground font-mono mb-3">
|
<div className="text-xs text-muted-foreground font-mono mb-3">
|
||||||
02
|
02
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-lg font-semibold mb-2">Users Prompt</h3>
|
<h3 className="text-lg font-semibold mb-2">Users Generate</h3>
|
||||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||||
End users describe what they want. AI generates JSON constrained
|
End users describe what they want. AI generates JSON constrained
|
||||||
to your catalog.
|
to your catalog. Every interface is unique to the user.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@@ -244,6 +247,10 @@ export default function Page() {
|
|||||||
<h2 className="text-2xl font-semibold mb-12 text-center">Features</h2>
|
<h2 className="text-2xl font-semibold mb-12 text-center">Features</h2>
|
||||||
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-8">
|
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||||
{[
|
{[
|
||||||
|
{
|
||||||
|
title: "User-Generated Interfaces",
|
||||||
|
desc: "Dynamic, personalized UIs per user powered by Generative UI",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "Guardrails",
|
title: "Guardrails",
|
||||||
desc: "AI can only use components you define in the catalog",
|
desc: "AI can only use components you define in the catalog",
|
||||||
@@ -253,20 +260,16 @@ export default function Page() {
|
|||||||
desc: "Progressive rendering as JSON streams from the model",
|
desc: "Progressive rendering as JSON streams from the model",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Code Export",
|
title: "React & React Native",
|
||||||
desc: "Export as standalone React code with no runtime dependencies",
|
desc: "Render on web and mobile from the same catalog and spec format",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Data Binding",
|
title: "Data Binding",
|
||||||
desc: "Two-way binding with JSON Pointer paths",
|
desc: "Two-way state binding with dynamic prop expressions",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Actions",
|
title: "Code Export",
|
||||||
desc: "Named actions handled by your application",
|
desc: "Export as standalone React code with no runtime dependencies",
|
||||||
},
|
|
||||||
{
|
|
||||||
title: "Visibility",
|
|
||||||
desc: "Conditional show/hide based on data or auth",
|
|
||||||
},
|
},
|
||||||
].map((feature) => (
|
].map((feature) => (
|
||||||
<div key={feature.title}>
|
<div key={feature.title}>
|
||||||
|
|||||||
+10
-6
@@ -22,11 +22,15 @@ export const metadata: Metadata = {
|
|||||||
template: "%s | json-render",
|
template: "%s | json-render",
|
||||||
},
|
},
|
||||||
description:
|
description:
|
||||||
"Let users generate dashboards, widgets, apps, and data visualizations from prompts — safely constrained to components you define.",
|
"The framework for User-Generated Interfaces (UGI). Let users generate dashboards, widgets, and apps from prompts — safely constrained to components you define.",
|
||||||
keywords: [
|
keywords: [
|
||||||
"json-render",
|
"json-render",
|
||||||
|
"UGI",
|
||||||
|
"User-Generated Interfaces",
|
||||||
"AI UI generation",
|
"AI UI generation",
|
||||||
|
"generative UI",
|
||||||
"React components",
|
"React components",
|
||||||
|
"React Native",
|
||||||
"guardrails",
|
"guardrails",
|
||||||
"structured output",
|
"structured output",
|
||||||
"dashboard builder",
|
"dashboard builder",
|
||||||
@@ -38,23 +42,23 @@ export const metadata: Metadata = {
|
|||||||
locale: "en_US",
|
locale: "en_US",
|
||||||
url: "https://json-render.dev",
|
url: "https://json-render.dev",
|
||||||
siteName: "json-render",
|
siteName: "json-render",
|
||||||
title: "json-render | AI-generated UI with guardrails",
|
title: "json-render | The framework for User-Generated Interfaces",
|
||||||
description:
|
description:
|
||||||
"Let users generate dashboards, widgets, apps, and data visualizations from prompts — safely constrained to components you define.",
|
"The framework for User-Generated Interfaces (UGI). Let users generate dashboards, widgets, and apps from prompts — safely constrained to components you define.",
|
||||||
images: [
|
images: [
|
||||||
{
|
{
|
||||||
url: "/og",
|
url: "/og",
|
||||||
width: 1200,
|
width: 1200,
|
||||||
height: 630,
|
height: 630,
|
||||||
alt: "json-render - AI-generated UI with guardrails",
|
alt: "json-render - The framework for User-Generated Interfaces",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
title: "json-render | AI-generated UI with guardrails",
|
title: "json-render | The framework for User-Generated Interfaces",
|
||||||
description:
|
description:
|
||||||
"Let users generate dashboards, widgets, apps, and data visualizations from prompts — safely constrained to components you define.",
|
"The framework for User-Generated Interfaces (UGI). Let users generate dashboards, widgets, and apps from prompts — safely constrained to components you define.",
|
||||||
images: ["/og"],
|
images: ["/og"],
|
||||||
creator: "@verabornnot",
|
creator: "@verabornnot",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -66,23 +66,27 @@ export async function renderOgImage(title: string) {
|
|||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
flexDirection: "column",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
{title.split("\n").map((line, i) => (
|
||||||
style={{
|
<span
|
||||||
fontSize: 72,
|
key={i}
|
||||||
fontFamily: "Geist",
|
style={{
|
||||||
fontWeight: 400,
|
fontSize: 72,
|
||||||
color: "white",
|
fontFamily: "Geist",
|
||||||
letterSpacing: "-0.02em",
|
fontWeight: 400,
|
||||||
textAlign: "center",
|
color: "white",
|
||||||
lineHeight: 1.2,
|
letterSpacing: "-0.02em",
|
||||||
}}
|
textAlign: "center",
|
||||||
>
|
lineHeight: 1.2,
|
||||||
{title}
|
}}
|
||||||
</span>
|
>
|
||||||
|
{line}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
export const PAGE_TITLES: Record<string, string> = {
|
export const PAGE_TITLES: Record<string, string> = {
|
||||||
// Home (no slug)
|
// Home (no slug)
|
||||||
"": "AI-generated UI with guardrails",
|
"": "The framework for\nUser-Generated Interfaces",
|
||||||
|
|
||||||
// Top-level
|
// Top-level
|
||||||
playground: "Playground",
|
playground: "Playground",
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export const { registry } = defineRegistry(catalog, {
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Standard components (Container, Row, Column, Button, TextInput, etc.) are included by default -- you only need to register custom ones.
|
Standard components (Container, Row, Column, Button, TextInput, etc.) are included by default. You only need to register custom ones.
|
||||||
|
|
||||||
### 3. Render Specs
|
### 3. Render Specs
|
||||||
|
|
||||||
|
|||||||
@@ -81,8 +81,8 @@ const finalSpec = compiler.getResult();
|
|||||||
|
|
||||||
Any prop value can be a dynamic expression resolved at render time:
|
Any prop value can be a dynamic expression resolved at render time:
|
||||||
|
|
||||||
- **`{ "$path": "/state/key" }`** -- reads a value from the state model
|
- **`{ "$path": "/state/key" }`** - reads a value from the state model
|
||||||
- **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** -- evaluates a visibility condition and picks a branch
|
- **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** - evaluates a visibility condition and picks a branch
|
||||||
|
|
||||||
`$cond` uses the same syntax as visibility conditions (`eq`, `neq`, `path`, `and`, `or`, `not`). `$then` and `$else` can themselves be expressions (recursive).
|
`$cond` uses the same syntax as visibility conditions (`eq`, `neq`, `path`, `and`, `or`, `not`). `$then` and `$else` can themselves be expressions (recursive).
|
||||||
|
|
||||||
|
|||||||
@@ -110,8 +110,8 @@ Use `Pressable` with the built-in `setState` action for interactive UIs like tab
|
|||||||
|
|
||||||
Any prop value can be a data-driven expression resolved at render time:
|
Any prop value can be a data-driven expression resolved at render time:
|
||||||
|
|
||||||
- **`{ "$path": "/state/key" }`** -- reads from data model
|
- **`{ "$path": "/state/key" }`** - reads from data model
|
||||||
- **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** -- conditional value
|
- **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** - conditional value
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -123,7 +123,7 @@ Any prop value can be a data-driven expression resolved at render time:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Components receive already-resolved props -- no changes needed to component implementations.
|
Components receive already-resolved props. No changes needed to component implementations.
|
||||||
|
|
||||||
## Built-in Actions
|
## Built-in Actions
|
||||||
|
|
||||||
|
|||||||
@@ -93,8 +93,8 @@ The React schema uses an element tree format:
|
|||||||
|
|
||||||
Any prop value can be a data-driven expression resolved by the renderer before components receive props:
|
Any prop value can be a data-driven expression resolved by the renderer before components receive props:
|
||||||
|
|
||||||
- **`{ "$path": "/state/key" }`** -- reads from data model
|
- **`{ "$path": "/state/key" }`** - reads from data model
|
||||||
- **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** -- conditional value
|
- **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** - conditional value
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
@@ -106,7 +106,7 @@ Any prop value can be a data-driven expression resolved by the renderer before c
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Components receive already-resolved props -- no changes needed to component implementations.
|
Components receive already-resolved props. No changes needed to component implementations.
|
||||||
|
|
||||||
## Event System
|
## Event System
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user