PixelDosa UI

Build with AI

Most teams will meet PixelDosa UI through a coding agent. Finding and installing components is the easy part — agents can already do that. The part that matters is the agent knowing how to use them: that nothing an AI proposes gets saved without review, that an approval states whether it can be undone, that the thing waiting on the user never animates. This page sets that up.

1.Add the registry

In your project's components.json:

components.json
"registries": {
  "@pixeldosa": "https://pixeldosa.akshayjayan.com/r/{name}.json"
}

2.Install the agent guide

This puts PixelDosa UI's component guide and UX rules into your repo, where your agent reads them on every task. It installs as a Claude Code skill at .claude/skills/pixeldosa/SKILL.md. For Cursor, Copilot or other agents, reference that file from your rules or AGENTS.md.

bash
npx shadcn@latest add @pixeldosa/pixeldosa-agent-guide

3.Connect the shadcn MCP server

Lets your agent search, read and install components directly. Add this to .mcp.json (Claude Code), .cursor/mcp.json (Cursor) or .vscode/mcp.json (VS Code):

json
{
  "mcpServers": {
    "shadcn": {
      "command": "npx",
      "args": ["shadcn@latest", "mcp"]
    }
  }
}

4.Or point any agent at the docs

No MCP? Every agent that can read a URL can use these. They're generated from the registry, so they're always current.

5.Render from JSON, not from generated code

The steps above are for an agent that writes code you review. Generative UI is the other shape: the model emits a payload, your app renders it, and nobody reads a diff in between. For that, a model needs the prop contract in a format it can be held to — that state is one of five words, not a free string. Every component publishes one, generated from its TypeScript at build time:

  • /r/catalog.json — every component's props, events and design guidance in one document.
  • /r/<component>.json — the same contract under meta.schema, alongside the source.
catalog.json (excerpt)
{
  "name": "run-inbox",
  "component": "RunInbox",
  "import": { "from": "@/components/ui/run-inbox", "named": "RunInbox" },
  "element": "section",
  "props": {
    "type": "object",
    "required": ["runs"],
    "properties": {
      "runs": { "type": "array", "items": { "$ref": "#/$defs/AgentRun" } }
    },
    "$defs": {
      "AgentRun": {
        "type": "object",
        "required": ["id", "title", "state"],
        "properties": {
          "state": { "enum": ["needsYou", "running", "scheduled", "done", "failed"] },
          "note": {
            "type": "string",
            "description": "Why it needs you, what it's doing, or what it produced. One line."
          }
        }
      }
    }
  },
  "events": [
    { "name": "onOpen", "required": true, "params": [{ "name": "id", "type": "string" }] }
  ]
}

The descriptions are the point. “Why it needs you, what it's doing, or what it produced. One line.” is the kind of guidance that otherwise lives in a docs page no runtime will ever read — here it reaches the model at the moment it writes the field.

Callbacks are listed separately as events, because no JSON format can carry a function. Each one gives its arguments, so a runtime can map them onto however it sends interactions home:

tsx
const registry = { RunInbox, AgentPlan, AIApprovalGate /* … */ };

// catalog.json, indexed by component name
const spec = Object.fromEntries(catalog.components.map((c) => [c.component, c]));

// The model emits { component, props }; events come back out as messages.
function Render({ node, onEvent }) {
  const Component = registry[node.component];
  if (!Component) return null; // not in the catalogue, not rendered

  const handlers = Object.fromEntries(
    (spec[node.component]?.events ?? []).map((event) => [
      event.name,
      (...args) => onEvent({ component: node.component, event: event.name, args }),
    ])
  );

  return <Component {...node.props} {...handlers} />;
}

Nothing in the catalogue names a protocol. It is plain JSON Schema, so it can back an A2UI or AG-UI component catalogue, an MCP server that returns UI, or your own renderer — the mapping lives in your adapter, where it can be changed when those specs change, rather than in the components.

Prompts that work well

Describe the job and the review you want, not the component. The guide maps the job to the right component.

  • Add an agent panel to the sidebar that shows the run's status, reasoning and any approvals, using @pixeldosa.
  • Let the AI fill in the customer form, but make the user review every field before it's saved.
  • Before the agent sends the email, show an approval with the recipient count and whether it can be undone.
  • Show a placeholder with real progress while the image generates, then fade in the result.

No AI stack required

PixelDosa UI components are plain React. They don't depend on the AI SDK, A2UI, LangGraph, MCP or any provider — your agent wires its own events to props. Each component page shows how common agent events map on. See the mapping table.