Your users just describe the page they want, and AI builds it for them on the spot. You stay in control: it can only use the data and actions you allow.
Declare the data and actions your app allows in plain natural language. Pass the real implementations; they remain completely private to your server.
Your users just say how they want the page to look. No settings to dig through, no templates to memorize—Veneer invents the layout on the fly.
“Show me a board of my tasks grouped by due date, with high priority tasks at the top”
Generated code runs in a sandboxed interpreter that can only describe what to draw. The model can style anything, but can only invoke the native functions you exposed.
Below is an ordinary task app built with the @veneer/react. Click the button in the corner and tell the AI how you want it to look. Everything it invents runs inside the sandboxed canvas.
// 1) Declare what the AI may see and do. This registry is the contract. const registry = { dataSources: [ { id: 'tasks', description: "The user's tasks.", fields: [ { name: 'id', type: 'string' }, { name: 'title', type: 'string' }, { name: 'status', type: '"todo" | "doing" | "done"' }, ] }, ], actions: [ { id: 'createTask', description: 'Create a task.' }, { id: 'updateTask', description: "Update a task's fields." }, { id: 'archiveTask', description: 'Archive a task.' }, // no deleteTask → no generated UI can ever delete ], }; // 2) Pass the REAL implementations + live data. Veneer wires the rest. const actions = { createTask: ({ title }) => setTasks(...), updateTask: ({ id, ...changes }) => setTasks(...), archiveTask: ({ id }) => setTasks(...), }; // 3) Drop in two components. The canvas is the sandbox; your chat redesigns it. <VeneerProvider registry={registry} actions={actions} data={{ tasks }}> <VeneerCanvas minHeight={560} /> <YourChatBox /> // built on useVeneerGenerate() </VeneerProvider>
A manager wants a dashboard; a teammate just wants today’s checklist. Instead of building both, you ship the pieces — and each person shapes the page to fit how they work, while you stay in control of what’s possible.
Change the UI to your liking with AI
An interpreter with no browser in it, an allowlisted renderer, a validated bridge — three independent layers.
A typed, described capability surface the model composes against.
Each person's layout is saved to their own browser. Nobody else sees it.
A provider, a canvas, a hook. Drop them in and you're live. (Note: Package naming is a placeholder subject to change on release.)
One endpoint returns { code, reply }. Use any LLM you like.
The model can write anything. It still can’t do anything you didn’t allow. Three independent layers enforce the same contract, plus a static scan before any code runs, a CPU deadline on every entry, and a watchdog that terminates the worker and resets the canvas if a generation ever hangs.
QuickJS (WebAssembly) · Web WorkerGenerated code runs in a JavaScript interpreter inside a Web Worker. There is no window, document, fetch, location or cookie in there — not blocked, simply nonexistent. All it can do is describe what to draw.
ops → allowlist → your DOMYour page redraws that description with its own React. Only safe elements, attributes and styles pass; links, images, scripts, url() and anything that could escape the canvas are dropped. Tailwind is compiled per view and scoped to the canvas.
veneer.action(id) → registry.actions[id]Every action is checked against the registry — id, declared args, types, rate — before the real implementation runs. Only declared return values and registered data cross back into the interpreter.
deleteTask→rejected on every layerNo deleteTask is registered, so the scanner refuses the code before it runs, the interpreter has no network to reach your API, and the bridge rejects the call. Deletion fails on every layer.
No new backend, no source-code delivery, no rebuild. Register what your app can do in plain natural language, hand over the functions, and drop in the open-source package.
// 1. Register the capabilities your app exposes const registry = { dataSources: [ { id: 'tasks', description: 'The user’s tasks.' } ], actions: [ { id: 'createTask', description: 'Create a task.' }, { id: 'updateTask', description: 'Update a task.' }, // no deleteTask → generated UIs can never delete ], }; // 2. Pass the REAL implementations + live data <VeneerProvider registry={registry} actions={actions} data={{ tasks }}> <VeneerCanvas minHeight={620} /> <YourChatBox /> // built on useVeneerGenerate() </VeneerProvider>
That’s the whole integration. The registry is the contract; the sandbox is the guarantee.
MCP gives an AI model a typed, described set of capabilities to work with. Veneer is the same idea — just pointed at your interface.
Lets a model use the tools and data your systems expose — through one typed, described surface. It can only ever call what’s on it.
The exact same shape — but the surface is your interface. The model composes a real UI against your registered data and actions, inside a sandbox.
That’s the core of the product. Generated code runs in a JavaScript interpreter (QuickJS compiled to WebAssembly) inside a Web Worker, where window, document, fetch, location and cookies simply do not exist. It can only describe what to draw; your page redraws that through an allowlist that drops links, images, scripts and url() styles, and a bridge that only runs actions you registered with the args you declared. Code is statically scanned before it runs, every entry has a CPU deadline, and if a generation ever hangs the worker is terminated, the canvas is reset and your app is notified. Only push data you would show that user on screen anyway — the SDK docs spell out every residual.
No. You keep your code and pass the real action implementations into the provider. The model only ever sees the registry’s plain-English descriptions and ids — never your implementations.
Whichever you want. Your generator endpoint returns { code, reply }, so you can wire up Gemini, Claude, or any other model. The demo uses gemini-2.5-flash.
Only if you registered an action for it. If there is no deleteTask in the registry, the scanner refuses code that calls it and the bridge rejects the call at runtime. Registered actions are validated against their declared args and rate-limited before your implementation runs.
Veneer is in private beta. Join the waitlist and we’ll send an invite as access opens up in batches — no spam, just your invite.
Rethink the last mile of software delivery. Ship the primitives — let your users design the interface they actually want. Join the waitlist for early access.