Dynamic Cards
Dynamic Cards
The Matter assistant composes UI cards on the fly — one per conversation moment, never templates. Cards are a recursive tree of in-library primitives, validated by Zod, streamed via the AI SDK, and rendered by a single <DynamicCard> component.
How it works
Three artifacts are the entire surface:
- Primitives — every
Card,Pill,Stat,Progress,Button, … registered in@matter/components/cards. One file per primitive: schema + few-shot + render fn. - Schema —
CardZis built at module load from the registry. Adding a primitive is one file; the schema, the AI prompt, and the renderer all update. - Gallery — the exemplar collection on this site doubles as the AI's few-shot pool. If you can't express a card cleanly with existing primitives, the build fails until a new primitive lands.
Phases
Browse the gallery by lifecycle phase:
Action contract
Every button in a card carries one CardAction. The action is the typed bridge between the rendered UI and the Matter API surface:
{ "kind": "navigate", "to": "/equity/grants/grt_…" }
{ "kind": "open_resource", "resource_id": "doc_…" }
{ "kind": "approve", "resource_id": "grt_…" }
{ "kind": "tool_call", "tool": "matter_…", "payload": { } }
{ "kind": "regenerate", "hint": "make the grant 40,000 shares" }
{ "kind": "dismiss" }tool_call.tool resolves against the generated MCP catalog at apps/mcp/src/tools/generated.ts — a card click and an agent-driven MCP call go through the same dispatcher.
Forward-compat
Unknown primitive names, unknown action kinds, unknown schema_version values all degrade to a labeled fallback card. The renderer never throws — failed parses surface in telemetry, not in user-facing crashes.
CodeBlock
Geist Mono code surface with 5-token syntax coloring. Optional header slot composes any V2 primitive — the V1 CodeCard role. Always translucent white, never dark slate. Bare mode renders <pre>; header mode wraps in <figure>.
Create — Dynamic Cards
Cards the assistant emits while bringing an entity into existence.