
Core
Define json-render schemas and catalogs so AI can emit valid JSON specs for UI or video generation.
Overview
core is an agent skill for the Build phase that teaches how to define json-render schemas, catalogs, and AI prompts so generated JSON specs validate against your UI or video component map.
Install
npx skills add https://github.com/vercel-labs/json-render --skill coreWhat is this skill?
- Core @json-render/core package for schemas, catalogs, and spec streaming
- defineSchema and defineCatalog with Zod-typed component props and descriptions
- Spec and SpecStream (JSONL) for progressive AI-built UI or video specs
- Optional custom promptTemplate hook on schema definition
- Maps AI output to structured JSON that conforms to your catalog
- Key concepts: Schema, Catalog, Spec, and SpecStream
Adoption & trust: 1.6k installs on skills.sh; 15k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You want AI-generated interfaces but get inconsistent markup instead of a strict, renderable JSON spec tied to real components.
Who is it for?
Builders implementing json-render who need Zod-backed catalogs and streaming specs for agent-driven UI generation.
Skip if: Teams who only need hand-written React components with no AI spec pipeline, or backend-only APIs with no generative UI layer.
When should I use this skill?
Working with @json-render/core, defining schemas, creating catalogs, or building JSON specs for UI/video generation.
What do I get? / Deliverables
You have a typed schema and catalog plus prompt generation path so model output streams as valid Spec/SpecStream JSON ready for your renderer.
- Schema definition via defineSchema
- Component catalog via defineCatalog
- AI prompt material and conformant JSON spec output
Recommended Skills
Journey fit
Build is where you shape renderable UI structure; this package is the foundation for AI-generated JSON specs before you wire a renderer. Frontend subphase matches component catalogs, Zod props, and prompt templates for visual spec output.
How it compares
Schema-and-catalog layer for json-render—not a full visual design system or hosted no-code builder.
Common Questions / FAQ
Who is core for?
Solo and indie frontend builders using @json-render/core who want their coding agent to define schemas, catalogs, and prompts correctly.
When should I use core?
Use it during Build while defining component catalogs, wiring defineSchema/defineCatalog, or generating AI prompts for JSON UI or video specs.
Is core safe to install?
It is documentation-style skill guidance for a library; review the Security Audits panel on this page and treat generated specs like untrusted input until validated.
SKILL.md
READMESKILL.md - Core
# @json-render/core Core package for schema definition, catalog creation, and spec streaming. ## Key Concepts - **Schema**: Defines the structure of specs and catalogs (use `defineSchema`) - **Catalog**: Maps component/action names to their definitions (use `defineCatalog`) - **Spec**: JSON output from AI that conforms to the schema - **SpecStream**: JSONL streaming format for progressive spec building ## Defining a Schema ```typescript import { defineSchema } from "@json-render/core"; export const schema = defineSchema((s) => ({ spec: s.object({ // Define spec structure }), catalog: s.object({ components: s.map({ props: s.zod(), description: s.string(), }), }), }), { promptTemplate: myPromptTemplate, // Optional custom AI prompt }); ``` ## Creating a Catalog ```typescript import { defineCatalog } from "@json-render/core"; import { schema } from "./schema"; import { z } from "zod"; export const catalog = defineCatalog(schema, { components: { Button: { props: z.object({ label: z.string(), variant: z.enum(["primary", "secondary"]).nullable(), }), description: "Clickable button component", }, }, }); ``` ## Generating AI Prompts ```typescript const systemPrompt = catalog.prompt(); // Uses schema's promptTemplate const systemPrompt = catalog.prompt({ customRules: ["Rule 1", "Rule 2"] }); ``` ## SpecStream Utilities For streaming AI responses (JSONL patches): ```typescript import { createSpecStreamCompiler } from "@json-render/core"; const compiler = createSpecStreamCompiler<MySpec>(); // Process streaming chunks const { result, newPatches } = compiler.push(chunk); // Get final result const finalSpec = compiler.getResult(); ``` ## Dynamic Prop Expressions Any prop value can be a dynamic expression resolved at render time: - **`{ "$state": "/state/key" }`** - reads a value from the state model (one-way read) - **`{ "$bindState": "/path" }`** - two-way binding: reads from state and enables write-back. Use on the natural value prop (value, checked, pressed, etc.) of form components. - **`{ "$bindItem": "field" }`** - two-way binding to a repeat item field. Use inside repeat scopes. - **`{ "$cond": <condition>, "$then": <value>, "$else": <value> }`** - evaluates a visibility condition and picks a branch - **`{ "$template": "Hello, ${/user/name}!" }`** - interpolates `${/path}` references with state values - **`{ "$computed": "fnName", "args": { "key": <expression> } }`** - calls a registered function with resolved args `$cond` uses the same syntax as visibility conditions (`$state`, `eq`, `neq`, `not`, arrays for AND). `$then` and `$else` can themselves be expressions (recursive). Components do not use a `statePath` prop for two-way binding. Instead, use `{ "$bindState": "/path" }` on the natural value prop (e.g. `value`, `checked`, `pressed`). ```json { "color": { "$cond": { "$state": "/activeTab", "eq": "home" }, "$then": "#007AFF", "$else": "#8E8E93" }, "label": { "$template": "Welcome, ${/user/name}!" }, "fullName": { "$computed": "fullName", "args": { "first": { "$state": "/form/firstName" }, "last": { "$state": "/form/lastName" } } } } ``` ```typescript import { resolvePropValue, resolveElementProps } from "@json-render/core"; const resolved = resolveElementProps(element.props, { stateModel: myState }); ``` ## State Watchers Elements can declare a `watch` field (top-level, sibling of type/props/children) to trigger actions when state values change: ```json { "type": "Select", "props": { "value": { "$bindState": "/form/country" }, "options": ["US", "Canada"] }, "watch": { "/form/country": { "action": "loadCities", "params": { "co