agent-wireframe-dsl
v0.1.3
Published
AI-friendly UI wireframe DSL with React renderer
Readme
agent-wireframe-dsl
A compact, JSON-based UI wireframe DSL designed for AI-assisted prototyping. Describe layouts and widgets in terse JSON; the React renderer turns them into a live visual preview instantly.
Installation
npm install agent-wireframe-dsl
# or
pnpm add agent-wireframe-dslPeer dependencies — make sure these are already in your project:
npm install react react-dom zodUsage
WireframeViewer — the simplest way
Drop WireframeViewer anywhere in your React tree and pass a DSL object (or anything — invalid input is shown as a friendly error list):
import { WireframeViewer } from 'agent-wireframe-dsl';
const dsl = {
t: 'page',
label: 'My App',
children: [
{
t: 'card',
children: [
{ t: 'text', label: 'Hello World', variant: 'primary' },
{ t: 'button', label: 'Click me', variant: 'primary' },
],
},
],
};
export default function App() {
return <WireframeViewer dsl={dsl} />;
}renderToPng — export to PNG
Renders a DSL definition to a base64 PNG data URL. Useful for generating preview images, sharing wireframes, or saving them to disk.
Requires a browser environment — this function uses
documentand the DOM.
import { renderToPng } from 'agent-wireframe-dsl';
const dataUrl = await renderToPng(dsl);
// dataUrl: "data:image/png;base64,..."
// download it
const a = document.createElement('a');
a.href = dataUrl;
a.download = 'wireframe.png';
a.click();Options:
await renderToPng(dsl, {
width: 1440, // rendered width in px (default: 1280)
pixelRatio: 3, // device pixel ratio / resolution (default: 2)
backgroundColor: '#f0f0f0', // PNG background color (default: '#ffffff')
});validateDsl + renderNode — lower-level control
import { validateDsl, renderNode } from 'agent-wireframe-dsl';
const result = validateDsl(rawJson);
if (!result.success) {
console.error(result.errors); // string[]
} else {
const element = renderNode(result.data); // ReactNode
}Zod schema — extend or compose
import { dslNodeSchema } from 'agent-wireframe-dsl';
// Use as a building block inside your own Zod schema
const mySchema = z.object({
version: z.string(),
ui: dslNodeSchema,
});Custom component registry — replace default components
Override the default components with custom ones (e.g., for theming or design system integration):
import { WireframeViewer, defaultRegistry, type ComponentRegistry, type DslNode } from 'agent-wireframe-dsl';
// Define a custom button component
function MyCustomButton({ node }: { node: DslNode }) {
return (
<button style={{ background: '#ec4899', color: 'white' }}>
{node.label}
</button>
);
}
// Create a custom registry with the custom button
const customRegistry: ComponentRegistry = {
...defaultRegistry,
button: MyCustomButton, // override just the button
// all other components use defaults
};
// Use it with WireframeViewer
<WireframeViewer
dsl={myDsl}
registry={customRegistry} // optional; uses defaults if omitted
/>If no registry prop is provided, WireframeViewer uses defaultRegistry, ensuring backward compatibility.
API Reference
| Export | Kind | Description |
|--------|------|-------------|
| WireframeViewer | React component | Validates dsl: unknown and renders, or shows errors |
| renderToPng | Async function | (dsl: unknown, opts?: RenderToPngOptions) => Promise<string> — renders to a PNG data URL |
| RenderToPngOptions | Type | Options for renderToPng: width, backgroundColor, pixelRatio |
| renderNode | Function | (node: DslNode, key?: number) => ReactNode — low-level renderer |
| defaultRegistry | Object | Default component registry mapping all NodeTypes to components |
| validateDsl | Function | (input: unknown) => ValidationResult \| ValidationError |
| dslNodeSchema | Zod schema | Schema for a single DSL node (recursive) |
| dslRootSchema | Zod schema | Alias for the root node schema |
| ComponentRegistry | Type | Record<NodeType, React.ComponentType<{ node: DslNode }>> — custom component mapping |
| ComponentRegistryContext | React context | Provides custom registry through render tree |
| createRegistry | Function | (base: ComponentRegistry, overrides: Partial<ComponentRegistry>) => ComponentRegistry — merge registries |
| DslNode | Type | TypeScript interface for any DSL node |
| ValidationResult | Type | { success: true; data: DslNodeSchema } |
| ValidationError | Type | { success: false; errors: string[] } |
| NodeType, LayoutType, WidgetType | Types | Union literals for node t values |
| VariantValue, SizeValue, WidthValue, GapValue, AlignValue | Types | Prop value unions |
| DslNodeSchema | Type | Zod-inferred type for a validated DSL node |
DSL Reference
Every node requires exactly one field: t (the node type). All other fields are optional. Unknown keys are rejected at validation time.
Layout nodes
| t | Description | Key props |
|-----|-------------|-----------|
| page | Root page container | label, children |
| section | Labelled section with vertical stack | label, gap, children |
| row | Horizontal flex row | gap, align, children |
| col | Vertical flex column | w, gap, children |
| grid | CSS grid | cols, gap, children |
| stack | Vertical stack with alignment | gap, align, children |
| card | Rounded bordered card | label, children |
Widget nodes
| t | Description | Key props |
|-----|-------------|-----------|
| text | Paragraph or heading | label / value, size, variant |
| button | Clickable button | label, variant, size |
| input | Single-line text input | label, hint, value |
| textarea | Multi-line text input | label, hint, value |
| select | Dropdown selector | label, items |
| checkbox | Checkbox | label |
| radio | Radio group | label, items |
| switch | Toggle switch | label |
| tabs | Tab bar | items |
| list | Bulleted list | label, items |
| table | Data table | label, columns, rows |
| avatar | Avatar circle (initials) | label, size |
| image | Image placeholder | label |
| badge | Pill badge | label / value, variant |
| divider | Horizontal rule | — |
| chart | Chart placeholder | label |
Shared props
| Prop | Type | Values |
|------|------|--------|
| variant | string | primary secondary danger success warning ghost outline |
| size | string | xs sm md lg xl |
| w | string | xs sm md lg xl full auto half |
| gap | string | none xs sm md lg xl |
| align | string | start center end stretch |
| h | string | xs sm md lg xl |
| cols | number | 1 – 12 |
| span | number | 1 – 12 |
| comment | string | Freeform annotation — ignored by the renderer |
Example — dashboard card
{
"t": "page",
"label": "Dashboard",
"children": [
{
"t": "row",
"gap": "md",
"children": [
{
"t": "card",
"label": "Users",
"children": [
{ "t": "text", "label": "1,024", "size": "xl", "variant": "primary" },
{ "t": "text", "label": "Total registered users", "size": "sm" }
]
},
{
"t": "card",
"label": "Revenue",
"children": [
{ "t": "text", "label": "$48,300", "size": "xl", "variant": "success" },
{ "t": "text", "label": "Month to date", "size": "sm" }
]
}
]
},
{
"t": "section",
"label": "Recent Orders",
"children": [
{
"t": "table",
"columns": ["Order", "Customer", "Status", "Amount"],
"rows": [
["#1001", "Alice", "Shipped", "$120"],
["#1002", "Bob", "Pending", "$85"]
]
}
]
}
]
}Design principles
- AI-friendly — the terse
t-keyed schema is easy for LLMs to generate reliably. - Validated at runtime — Zod strict-object schemas reject unknown keys immediately with clear error messages.
- Inline styles only — no CSS framework dependency; the renderer works out of the box in any React environment.
- Composable —
validateDsl,renderNode, and the Zod schemas are all individually exportable so you can integrate at whatever level fits your app.
License
MIT
