Canvas
An infinite spatial board with a dot-grid background. A canvas holds placements —{ blockId, x, y, w, h, version } rows that anchor a block to a position. Canvases are workspace-owned.
You can have as many canvases as your plan allows (Free: 2, Builder: 20, Enterprise: 1000). Each canvas has its own visibility setting.
Visibility
Three states, set from the Sharing tab in the canvas Manage panel (?manage=1&tab=sharing):
private— only workspace members can open it. The default for new canvases.workspace— same access asprivatetoday; reserved for future role-based sharing.public— anyone can view it without logging in, at the stable pretty URLchatblocks.ai/<username>/<slug>. Public is the only shareable tier. Public canvases are search-indexable unless you tick the per-canvas Hide from search engines checkbox (seoNoindex), which drops the page from the sitemap and setsnoindexon its robots meta. Transitioning back toprivateorworkspacemakes the public URL stop resolving.
/<username>/<slug> path (no opaque /c/<token> URLs).
Per-block sharing. Every block has a “Copy link” (in the tile menu and the expanded view’s Share button) that yields a public deep link straight to that block: chatblocks.ai/<username>/<slug>?expanded=<placementId>. If the canvas isn’t public yet, a manager is prompted to make it public before the link is copied.
The featured homepage canvas at chatblocks.ai/ is a separate concept — site admins flip isFeatured on a public canvas to surface it as the landing page.
Block
An independent React or HTML app, rendered in a sandboxed iframe via/api/blocks/:id/render. Blocks own their visuals end-to-end — the platform provides the sandbox, not a design system. Think “hawker market stall,” not “window in an OS.”
A block has metadata (name, description, tags), a manifest (widget config, data bindings), and one or more published versions. Canvas placements pin to a specific publishedVersionId, so updating a block doesn’t silently change what’s on the canvas — you re-publish to push a new version.
Render formats
The manifest’sformat field is one of two values:
- code
- embed
The default. A virtual filesystem of source files authored in the in-app Monaco editor or by your agent via MCP
blocks.setFiles. On blocks.build, Vercel Sandbox compiles the source to a static artifact tree (HTML + JS chunks + CSS + assets), uploads it to Convex storage, and pins it to a blockPublishedVersion. The render route serves the published artifact from storage.Use this for anything beyond a fixed page — JSX, hooks, data bindings, animations, anything that runs JavaScript.code) or a valid embed.url (for embed). The canvas placement layer (canvas-host.tsx) computes this and the render route’s branching has to stay in sync with it.
Placement
AblockPlacements row: { canvasId, blockId, x, y, w, h, publishedVersionId }. A block can appear on multiple canvases, but at most one placement per block per canvas — placeBlock rejects duplicates.
Placements are created via:
- The in-app submission flow — a workspace member submits a block to a canvas; the canvas curator (workspace admin) approves; approved blocks auto-place.
- MCP
placements.create— your agent places a block directly. - Direct placement on your own canvas — no approval step needed when you own both sides.
Authoring loop
The full MCP authoring loop your agent drives:1
blocks.init
Scaffold a new block. Returns a
blockId. By default the block is unpublished and not placed anywhere.2
blocks.setFiles
Write source files. The block holds a virtual filesystem with
src/App.tsx as the entry point for code-format blocks.3
blocks.build
Run the Vercel Sandbox build. Produces an HTML bundle and uploads it to Convex storage. Counts against your monthly build quota.
4
blocks.publish
Cut a new published version. The render route now serves the bundle. Canvas placements that pin to “latest” pick it up immediately; placements pinned to an older version are unaffected.
What’s next
Manifest
The full schema for a block’s manifest — widget config, data binding, projection mapping.
Runtime
What’s available inside the iframe — render env, data injection, security boundaries.