Part 1
A catalog, not free-form HTML
The model composes from a fixed list of components, each with a schema for its props, so a generated page can only render components you approved, with props the schema accepts.
Study first
- json-render: a spec is a root, a map of elements with a type, props and children, and optional state; the model streams it as JSON patches, and
useUIStreamapplies them. defineCatalog: components with Zod props, slots for children, and a description the model reads;catalog.prompt()turns the catalog into the instructions.
Build
pnpm add @json-render/core @json-render/reactandpnpm dlx shadcn@latest add alert progress tabs.src/lib/catalog.ts: 22 components. Layout (Page,Stack,Grid,Card), text (Heading,Text), numbers (Metric,Progress), labels (Badge,Alert), data (Table,BarChart,LineChart,PieChart,Timeline),Tabs, and a form (Form,Input,Textarea,Select,Checkbox,Button) with one action,submit_request.- Descriptions that say when to use a component, and narrow props: a tone enum for badges and alerts, 2 to 4 columns for a grid.
- A test that the catalog has every component the renderer implements, and that
catalog.prompt()names them.
Done when
pnpm testpasses, andcatalog.prompt()printed in a test lists the 22 components with their props.
Technical notes
- Nullable rather than optional props: the model sends every prop, with
nullwhere there is nothing. - A
Metrictakes a string or a number as its value, so "$1,240" and 17 both render. - The catalog is the contract between the prompt and the renderer; a component added to one without the other is caught by the test.

