Studio

Studio for AI Agents

Efecto Studio is a real-time web design tool that AI agents can control programmatically. Create artboards, add elements, style with Tailwind CSS, and see changes instantly in the browser — no API keys required.

Using Claude Code?

Install the MCP server and start designing immediately:
terminal
npx @efectoapp/mcp-studio install
Restart Claude Code, then ask: “Design a landing page in Efecto Studio” full details below.

How it works

Your agent creates a session via REST. The user opens the session URL in their browser. The agent pushes tool calls over HTTP, which execute in the browser in real time. The user watches the design being built live.

Agent ──POST /execute──▶ Server ──SSE──▶ Browser (live preview)
Agent ◀──poll/response── Server ◀──POST── Browser (tool results)

Quick Start

Step 1: Create a session

terminal
curl -X POST https://efecto.app/api/v1/studio/sessions \
  -H "Content-Type: application/json" \
  -d '{"label": "My design session"}'

Response:

response.json
{
  "sessionId": "abc123",
  "studioUrl": "https://efecto.app/studio?session=abc123",
  "expiresAt": "2026-02-26T12:30:00.000Z"
}

Step 2: Open the URL in a browser

Open the studioUrl from the response. The browser connects to your session via SSE and waits for tool calls.

Step 3: Push tool calls

terminal
# Create an artboard
curl -X POST https://efecto.app/api/v1/studio/sessions/abc123/execute \
  -H "Content-Type: application/json" \
  -d '{
    "tool": "studio_create_artboard",
    "input": {
      "name": "Homepage",
      "width": 1440,
      "height": 900,
      "className": "flex flex-col"
    }
  }'

The browser executes the tool and the artboard appears instantly. The response includes a callId and the tool result:

response.json
{
  "callId": "call_xyz",
  "status": "completed",
  "result": {
    "success": true,
    "message": "Created artboard \"Homepage\" (1440x900)",
    "data": { "artboardId": "art_001" }
  }
}

No API keys needed

Studio sessions are free and require no authentication. Sessions expire after 15 minutes of inactivity.

Session API

Six endpoints manage the lifecycle of a Studio session.

POST /api/v1/studio/sessions

Create a new session. Returns a session ID and a URL for the browser.

terminal
curl -X POST https://efecto.app/api/v1/studio/sessions \
  -H "Content-Type: application/json" \
  -d '{"label": "Claude Code session"}'
FieldTypeDescription
labelstring?Optional human-readable label

Response: { sessionId, studioUrl, expiresAt }

GET /api/v1/studio/sessions/:sessionId

Get session info, including whether a browser is connected.

terminal
curl https://efecto.app/api/v1/studio/sessions/abc123

Response: { session, pendingCalls, completedCalls }

DELETE /api/v1/studio/sessions/:sessionId

Close a session and disconnect the browser.

terminal
curl -X DELETE https://efecto.app/api/v1/studio/sessions/abc123

POST /api/v1/studio/sessions/:sessionId/execute

Push a tool call for the browser to execute. If the browser is connected, the tool executes immediately and the result is returned. If the browser is not connected, the call is queued (up to 100 pending calls).

terminal
curl -X POST https://efecto.app/api/v1/studio/sessions/abc123/execute \
  -H "Content-Type: application/json" \
  -d '{
    "tool": "studio_add_section",
    "input": {
      "parentId": "art_001",
      "jsx": "<nav className=\"flex items-center justify-between px-8 py-4 w-full\"><h1 className=\"text-xl font-bold\">Acme</h1></nav>"
    }
  }'
FieldTypeDescription
toolstringTool name (see Tool Reference below)
inputobject?Tool input parameters

Response: { callId, status, result? }. Status is completed when executed immediately, or pending if queued.

GET /api/v1/studio/sessions/:sessionId/stream

Server-Sent Events stream for the browser. The browser connects to this endpoint to receive tool calls in real time. You do not need to call this directly — opening the studioUrl handles it automatically.

EventDescription
connectedConfirms SSE connection is established
tool_callNew tool call to execute (includes callId, tool, input)
heartbeatKeep-alive ping (every 15s)
session_closedSession has been closed

POST /api/v1/studio/sessions/:sessionId/result

Browser submits the result of a tool call back to the server. This is handled automatically by the Studio client — agents do not call this directly.


Tool Reference

33 tools for reading, creating, and modifying Studio documents. All tools are invoked via the POST /execute endpoint.

State & Query

ToolDescriptionRequired Params
studio_get_stateReturns the full document as JSX-like markup with data-id attributes(none)
studio_list_artboardsLists all artboards with IDs, names, dimensions, positions(none)
studio_find_nodesSearch nodes by name, text content, type, or classNamequery? type? classNameContains?

Artboards

ToolDescriptionRequired Params
studio_create_artboardCreate a new artboard. Use className "flex flex-col" for vertical layout.name width height
studio_update_artboardUpdate artboard name, size, background, classNameartboardId
studio_delete_artboardDelete an artboard and all its contentsartboardId
studio_duplicate_artboardDeep-clone an artboard with fresh IDsartboardId

Nodes

ToolDescriptionRequired Params
studio_add_nodeAdd a single node (frame, text, image, button, link, icon, input, video)parentId type
studio_add_sectionAdd complex layouts from JSX-like markup (most efficient for multi-element structures)parentId jsx
studio_update_nodeUpdate any node property (className, textContent, tag, src, etc.)nodeId
studio_update_classNameUpdate only the Tailwind classes of a node (shortcut)nodeId className
studio_delete_nodeDelete one or more nodes and their childrennodeIds
studio_move_nodeReparent or reorder a node within its parentnodeId newParentId
studio_duplicate_nodeDeep-clone a node (inserted after the original)nodeId
studio_group_nodesWrap nodes in a new frame containernodeIds
studio_ungroup_nodeUnwrap a group, moving children up to the parentgroupId
studio_reorder_nodeBring to front or send to back within parentnodeId position
studio_batch_updateUpdate multiple nodes in one call (bulk styling)updates
studio_replace_sectionReplace a node and its children with new JSX in-placenodeId jsx

UI

ToolDescriptionRequired Params
studio_select_nodesHighlight nodes on the canvas for the usernodeIds
studio_set_visibilityShow or hide a node (hidden nodes remain in the tree)nodeId visible

Alignment & Distribution

ToolDescriptionRequired Params
studio_align_nodesAlign multiple nodes (left, center, right, top, middle, bottom)nodeIds alignment
studio_distribute_nodesDistribute nodes evenly (horizontal or vertical)nodeIds direction

History

ToolDescriptionRequired Params
studio_undoUndo the last action (equivalent to Cmd+Z)(none)
studio_redoRedo the last undone action (equivalent to Cmd+Shift+Z)(none)

Viewport & Document

ToolDescriptionRequired Params
studio_zoom_to_artboardZoom the viewport to show a specific artboardartboardId
studio_zoom_to_fitZoom to fit all artboards in the viewport(none)
studio_set_viewportSet viewport zoom level and pan positionzoom? panX? panY?
studio_rename_documentRename the Studio documentname
studio_new_documentCreate a new blank document (replaces current)name?

Canvas & Reading

ToolDescriptionRequired Params
studio_move_artboardReposition an artboard on the canvas for multi-screen flowsartboardId x y
studio_deselect_allClear the current node selection(none)
studio_get_node_treeGet JSX for a specific node or artboard subtree (faster than full document)nodeId

Data Model

Studio documents are trees of HTML nodes styled with Tailwind CSS. Every node maps to a real DOM element.

structure
StudioDocument
  └── Pages[]
       └── Artboards[]           # Root containers (like frames in Figma)
            ├── width, height     # Fixed dimensions in CSS pixels
            ├── backgroundColor   # Hex color (inline style)
            ├── className         # Tailwind classes ("flex flex-col")
            └── children[]        # StudioNode tree
                 ├── type         # frame | text | image | button | link | icon | input | video
                 ├── tag          # HTML tag (div, section, h1, p, img, button, a, ...)
                 ├── className    # ALL styling lives here (Tailwind CSS)
                 ├── style        # Inline CSS escape hatch (use sparingly)
                 └── children[]   # Nested nodes

className is the source of truth

All visual styling lives in className as Tailwind CSS classes. There is no node.gap, node.padding, or node.flexDirection. Use Tailwind classes like flex flex-col gap-4 p-6.

Node Types

TypeHTML TagsContent Properties
framediv, section, article, aside, main, nav, header, footer, ul, ol, li, figure(none — pure container)
texth1-h6, p, span, blockquote, labeltextContent, richText?
imageimgsrc, alt, objectFit?
buttonbuttontextContent, variant?, disabled?
linkahref, textContent, target?
iconsvgiconName, iconWeight?, iconSize?
inputinput, textarea, selectinputType, placeholder, label?
videovideosrc, poster?, autoPlay?, loop?

Common Artboard Sizes

DeviceWidthHeight
Desktop1440900
Tablet7681024
Mobile375812

Example: Build a Landing Page Hero

A complete sequence of tool calls that builds a hero section from scratch. Each call uses the POST /execute endpoint.

1. Create the artboard

execute payload
{
  "tool": "studio_create_artboard",
  "input": {
    "name": "Landing Page",
    "width": 1440,
    "height": 900,
    "backgroundColor": "#ffffff",
    "className": "flex flex-col"
  }
}

Returns: { artboardId: "art_001" }

2. Add the navigation bar

execute payload
{
  "tool": "studio_add_section",
  "input": {
    "parentId": "art_001",
    "jsx": "<nav className=\"flex items-center justify-between px-12 py-4 w-full\"><h1 className=\"text-xl font-bold text-gray-900\">Acme Inc</h1><div className=\"flex items-center gap-6\"><a className=\"text-sm text-gray-600\">Features</a><a className=\"text-sm text-gray-600\">Pricing</a><a className=\"text-sm text-gray-600\">About</a><button className=\"px-4 py-2 bg-gray-900 text-white text-sm rounded-lg\">Get Started</button></div></nav>"
  }
}

3. Add the hero section

execute payload
{
  "tool": "studio_add_section",
  "input": {
    "parentId": "art_001",
    "jsx": "<section className=\"flex flex-col items-center justify-center grow px-12 py-24 w-full\"><h1 className=\"text-6xl font-bold text-gray-900 text-center\">Build faster with Acme</h1><p className=\"text-xl text-gray-500 text-center mt-6 max-w-2xl\">The modern platform for building beautiful, responsive web applications. Ship in days, not months.</p><div className=\"flex items-center gap-4 mt-10\"><button className=\"px-8 py-3 bg-gray-900 text-white rounded-lg text-lg font-medium\">Start Free Trial</button><button className=\"px-8 py-3 border border-gray-300 text-gray-700 rounded-lg text-lg font-medium\">Watch Demo</button></div></section>"
  }
}

4. Read back the state

execute payload
{
  "tool": "studio_get_state",
  "input": {}
}

Returns the full document as JSX-like markup with data-id attributes you can use to reference nodes for updates.

5. Update styling

execute payload
{
  "tool": "studio_batch_update",
  "input": {
    "updates": [
      {
        "nodeId": "<nav-id-from-get_state>",
        "className": "flex items-center justify-between px-12 py-4 w-full border-b border-gray-100"
      },
      {
        "nodeId": "<h1-id-from-get_state>",
        "textContent": "Build 10x faster with Acme"
      }
    ]
  }
}

6. Select nodes for the user

execute payload
{
  "tool": "studio_select_nodes",
  "input": {
    "nodeIds": ["<hero-section-id>"]
  }
}

Tailwind CSS Tips

Studio renders nodes as real HTML with Tailwind classes. Follow these guidelines for best results.

  • Use named colors: bg-white, bg-gray-900, text-blue-500. Arbitrary hex values like bg-[#f9f9f9] are auto-converted to inline styles but named colors are preferred.
  • Always set display on containers: flex, flex flex-col, grid. Without it, children stack at (0,0).
  • Top-level children need w-full: Direct children of a flex artboard should include w-full to span the artboard width (auto-added by validation).
  • Use grow instead of flex-1: The flex-1 class is not inspector-safe. Use grow instead.
  • Use semantic HTML tags: header, nav, main, section, footer for better structure.
  • Text goes in text nodes: Use h1-h6, p, span for text content, not inside frame containers directly.

Claude Code Integration

The recommended way to use Studio programmatically is via the Efecto Studio MCP Server, which exposes all 33 Studio design tools as first-class MCP tools to Claude Code.

Install the MCP Server

terminal
npx @efectoapp/mcp-studio install

Restart Claude Code after installing. All 36 Studio tools (3 session + 33 design) are immediately available as first-class MCP tools — no proxy wrappers needed.

Example prompts

prompts.txt
"Open Studio and design a SaaS landing page"

"Create a mobile app login screen in Studio"

"Design a pricing table with 3 tiers in Studio"

"Build a dashboard layout with sidebar navigation"

MCP tools

The @efectoapp/mcp-studio server exposes every Studio tool as a first-class MCP tool. Claude Code creates a session, opens the browser URL, and pushes design tools directly — you just describe what you want.

Direct API Usage

You can also use the Session API directly from any HTTP client, script, or CI pipeline. The full flow is:

  1. Create a session (POST /sessions)
  2. Open the studioUrl in a browser
  3. Push tool calls (POST /sessions/:id/execute)
  4. Read results from each response
  5. Close the session when done (DELETE /sessions/:id)

Limits

LimitValue
Session TTL15 minutes of inactivity
Max sessions per IP10
Max pending tool calls100
Tool call timeout30 seconds