Skip to main content
The DesignJS canvas is a live HTML/CSS rendering environment embedded in your browser. When you drag a block onto the canvas or when an AI agent calls add_components, the result is real HTML being rendered inside an iframe — not a vector shape, not a preview approximation. The same HTML that appears in the canvas is the HTML that ships to your application.

How the canvas renders

The canvas uses GrapesJS, an open-source web builder framework, to manage a visual editing layer over a live iframe. Inside that iframe, Tailwind CSS v4 is loaded from CDN. This means:
  • Any Tailwind utility class you or your agent writes resolves correctly in the canvas.
  • The iframe is a fully functional HTML document — you can inspect its elements in your browser’s DevTools.
  • CSS you write is actual CSS, not a style representation that gets converted later.
The editor shell (the panels, toolbars, and layer tree surrounding the canvas) is separate from the iframe. It runs as a React application and communicates with the GrapesJS instance through its API.

What a component is

In GrapesJS terminology, every element on the canvas is a component — a node in the document tree. Each component has:
  • A unique ID used by MCP tools to target specific elements.
  • A tag name (e.g., div, button, img).
  • A list of CSS classes (Tailwind utilities and custom classes).
  • Attributes (e.g., src, href, data-*).
  • Optional text content for leaf nodes.
  • A list of children, which are themselves components.
This recursive tree structure is what the get_tree MCP tool returns. You can inspect it yourself by calling get_tree from your agent, or by opening the Layers panel on the right side of the editor.

Selecting components

You select a component by clicking it in the canvas or clicking its entry in the Layers panel. The editor highlights the selection with a bounding box and populates the Style panel with that component’s current CSS properties. The get_selection MCP tool returns the component IDs of whatever is currently selected. This lets an agent check what you have selected before operating on it — useful for workflows where you select a component visually and then ask the agent to modify it.

How human edits and agent edits converge

Both your edits and the agent’s edits go through the same GrapesJS component model. There is one source of truth: the in-memory component tree managed by GrapesJS.
  • When you drag a block or change a style in the Style panel, GrapesJS updates its internal model immediately.
  • When the agent calls add_components, update_styles, or delete_nodes, the MCP server relays those calls over a WebSocket to the browser, where they execute as GrapesJS API calls — the same API that the editor UI uses.
This means there is no merge conflict model, no “agent layer” vs “human layer.” Both parties operate on the same model, and changes are reflected in real time for both.
If the agent and you edit the same component at the same time, last write wins — GrapesJS does not implement operational transforms. In practice, this is rarely an issue because agent calls are explicit tool invocations that take milliseconds to complete.

The block palette

The left panel contains a block palette with 25 pre-built blocks organized into categories: Layout, Typography, Form, and Media. Clicking a block inserts it into the canvas at the root level. These blocks are plain HTML with Tailwind classes — the same kind of HTML the add_components tool accepts.

CSS variables

Beyond per-component styles, the canvas supports CSS custom properties (variables) applied to the iframe’s :root. These act as design tokens: define --brand-primary once and reference it across all your components. The get_variables and set_variables MCP tools let an agent read and write these tokens programmatically. Variables are saved to .designjs.json and reapplied when you reload the canvas.

Saving and restoring state

The canvas saves its full state — the component tree, per-component styles, and CSS variables — to .designjs.json in your project directory. Saves happen automatically every 30 seconds and whenever you press Cmd+S (Mac) or Ctrl+S (Windows/Linux). When you reload the page, the canvas reads that file and restores exactly what you had.
Because .designjs.json is plain JSON, you can commit it to your git repository and restore any saved canvas state by checking out the file.