> ## Documentation Index
> Fetch the complete documentation index at: https://docs.avocadostudio.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Puck mode

> Enable a visual drag-and-drop editing experience alongside AI chat using the Puck editor.

<div className="relative w-full rounded-xl overflow-hidden border border-gray-200 dark:border-gray-800 my-6" style={{ aspectRatio: "1916 / 1080" }}>
  <video className="absolute inset-0 h-full w-full" width="1916" height="1080" src="https://mintcdn.com/avocadostudioai/_mYaYtn4Ff5sj25R/images/puck-demo.mp4?fit=max&auto=format&n=_mYaYtn4Ff5sj25R&q=85&s=247f1222be4e16cd060abd55d0aba9a5" poster="/images/puck-demo-thumb.jpg" preload="none" controls playsInline data-path="images/puck-demo.mp4" />

  <button
    type="button"
    aria-label="Play the Puck mode demo"
    className="group absolute inset-0 flex h-full w-full cursor-pointer items-center justify-center border-0 bg-transparent p-0"
    onClick={(e) => {
  const overlay = e.currentTarget;
  const video = overlay.parentElement.querySelector("video");
  overlay.style.display = "none";
  Promise.resolve(video.play()).catch(() => { overlay.style.display = ""; });
}}
  >
    <span className="flex h-16 w-16 items-center justify-center rounded-full bg-black/55 backdrop-blur-sm transition-transform duration-150 group-hover:scale-110">
      <svg viewBox="0 0 24 24" fill="white" className="ml-1 h-7 w-7" aria-hidden="true">
        <path d="M8 5v14l11-7z" />
      </svg>
    </span>
  </button>
</div>

## Overview

Puck mode is an alternative editing experience that replaces the default chat-driven editor with a visual drag-and-drop canvas powered by [Puck](https://puckeditor.com/). AI chat remains available as a sidebar plugin, so users get both: direct manipulation **and** natural-language editing.

It is experimental. Turning it on is a per-site setting anyone with access to
Site settings can flip; the sections after [Enabling per site](#enabling-per-site)
are for developers.

### No extra integration, with one catch

<Info>
  Puck mode requires **no additional integration work** from the site developer. If your site is already integrated with Avocado Studio, Puck mode opens on it.
</Info>

The catch is what the canvas can draw. It renders blocks with Avocado's built-in
block components, not with your site's own components or its theme. A block
type your site defines itself, with no built-in renderer, appears on the canvas
as a dashed placeholder — *No renderer is registered for this block in the
editor runtime* — though its fields still edit in the sidebar. On a site built
mostly from its own blocks, the default chat editor, which previews the real
site, is the better tool.

Your site talks to the orchestrator — not to the editor UI. Whether the user edits via chat or via the Puck canvas, the orchestrator receives the same operations through the same endpoints (`/ops`, `/draft/pages`, `/chat`). The site never knows which editor produced the changes.

This is possible because Puck mode runs entirely inside the editor app, with an **adapter layer** that translates between Puck's data model and ours:

```mermaid theme={null}
flowchart LR
    Chat["AI chat editor"] --> Ops["operations"]
    Puck["Puck visual editor"] --> Adapter["adapter layer"] --> Ops
    Ops --> Orch["Orchestrator"] --> Site["Your site"]
```

| Adapter function | What it does |
| - | - |
| `pageToPuckData()` | Converts PageDoc → PuckData so the Puck canvas can render it |
| `buildOpsFromPuckDiff()` | Converts Puck state changes back into standard operations |
| `createPuckConfig()` | Converts the block manifest into Puck field definitions |

This means you integrate once with Avocado Studio and get both editing experiences — chat-driven AI editing and visual drag-and-drop — without any extra work on your site.

## Enabling per site

Puck mode is controlled per-site via the site settings panel.

<Steps>
  <Step title="Open the Sites page">
    Navigate to `/sites` in the editor.
  </Step>

  <Step title="Open site settings">
    Press the gear button on the site's card. (From inside the editor, the
    site menu in the top bar has **Site settings** too.)
  </Step>

  <Step title="Enable Puck">
    In the **General** tab, check **Use visual editor (Puck)**.
  </Step>

  <Step title="Open the editor">
    Click **Open editor** on the card — the site opens at `/editor/puck?siteId=<id>` instead of the chat editor.
  </Step>
</Steps>

Sites without the flag continue to open the default chat editor at `/editor`.

## How it works

### Block registration

When Puck mode loads, it fetches the block manifest from your site's `/api/editor/blocks` endpoint — the same manifest the chat editor uses. `createPuckConfig()` converts each block definition into a Puck-compatible component with appropriate field controls:

| Block field type | Puck field control |
| - | - |
| `number` | Number input |
| `enum` | Select dropdown |
| `headingLevel` | Select (h1–h6) |
| `richtext` | Puck `richtext` field (`contentEditable: false`) |
| `text` with `multiline: true` | Textarea |
| `image` | Custom image picker |
| default | Text input |

Blocks render using the same `SharedBlockRenderer` from `@avocadostudio-ai/blocks`, so what you see in Puck matches what renders on the live site.

### AI chat integration

Chat is registered as a Puck **plugin panel** in the right sidebar. It uses the same chat engine, endpoints, and AI planning as the main editor:

* `/chat` for standard planning and ops
* `/agent/start` + `/agent/stream` for agent mode (when enabled)
* Selection context is passed automatically — the AI knows which block is selected

### Auto-save

Edits are persisted automatically with a 600ms debounce:

1. User drags, reorders, or edits a field in the Puck canvas
2. The system diffs the previous and current state
3. Operations (`add_block`, `remove_block`, `update_props`, `move_block`) are generated
4. Ops are sent to `POST /ops` on the orchestrator

### Agent mode

If `AGENT_API_KEY` is set in the standalone orchestrator's `.env`, the editor detects agent mode availability from `GET /status/planner`. When enabled, the chat sidebar can run multi-step autonomous editing via the agent loop. Library mode (`createOrchestrator()`) always reports agent mode off, and in production the standalone server mounts the agent routes only with `AGENT_SURFACE=on` — see [environment variables](/reference/environment).

## Comparison with the AI chat editor

| Aspect | AI chat editor | Puck mode |
| - | - | - |
| Primary interaction | Natural language | Drag-and-drop |
| Preview | Iframe + postMessage bridge | In-canvas rendering |
| Chat location | Left sidebar | Right sidebar (plugin) |
| Block editing | Custom property panel | Puck's native field sidebar |
| Drag-and-drop | Custom handler | Puck's native DnD |
| Publishing | Full publish flow | Full publish flow |

## Publishing

Puck's built-in "Publish" button triggers the full publish workflow:

1. Pending draft edits are flushed immediately
2. `POST /publish` is called on the orchestrator (same endpoint as the chat editor)
3. The Puck button shows a loading state while the publish is in progress
4. A **"View deploy"** link appears in the header after a successful deployment

Publishing uses the same `usePublish` hook as the main editor — it supports Git-based deploy, Vercel deploy hooks, and site contract publishing.

## Architecture

```mermaid theme={null}
graph TD
    subgraph "Editor App (Vite :4100)"
        Router{"/editor/puck?"}
        ChatEditor["Chat-Only Editor<br/>(default)"]
        PuckRoute["PuckPrototypeRoute.tsx<br/>injects HostApi"]
    end

    Router -->|No| ChatEditor
    Router -->|Yes| PuckRoute

    subgraph "Puck Editor Instance"
        PuckCore["&lt;Puck&gt; Editor Canvas<br/>drag & drop, inline editing"]

        subgraph "Plugins (right sidebar)"
            AIChat["AI Chat Plugin<br/>ai-site-editor-chat"]
            History["History Plugin<br/>ai-site-editor-history"]
            Blocks["blocksPlugin()"]
            Fields["fieldsPlugin()"]
            Outline["outlinePlugin()"]
        end

        subgraph "Overrides"
            Iframe["iframe override<br/>CSS vars, layout"]
            Header["headerActions override<br/>page selector, undo/redo"]
        end

        CustomFields["Custom Field Types<br/>image picker"]
    end

    PuckRoute --> PuckCore

    subgraph "Adapters Layer (packages/editor-puck)"
        Config["createPuckConfig()<br/>manifest → Puck fields"]
        Diff["buildOpsFromPuckDiff()<br/>PuckData → ops"]
        Convert["pageToPuckData()<br/>PageDoc → PuckData"]
    end

    PuckCore -->|"onPuckChange<br/>(debounce 600ms)"| Diff
    Config --> PuckCore
    Convert --> PuckCore

    subgraph "Orchestrator (Fastify :4200)"
        Ops["POST /ops"]
        Draft["GET /draft/pages"]
        ChatSSE["POST /chat (SSE)"]
    end

    Diff -->|"add_block, update_props,<br/>remove_block, move_block"| Ops
    Draft -->|PageDoc| Convert

    AIChat -->|user message + selection context| ChatSSE
    ChatSSE -->|"op_applied events"| PuckCore

    subgraph "Site (Next.js :3000)"
        Preview["Live Preview<br/>renders BlockInstances"]
    end

    Ops --> Preview
```

## Current limitations

<Warning>
  Puck mode is experimental. The following features are not yet available:
</Warning>

* **No live site preview** — blocks render in the Puck canvas with the built-in renderers, not inside your site's preview, so your theme and your own block components do not show
* **Custom blocks render as placeholders** — see [the catch](#no-extra-integration-with-one-catch) above
* **Chat attachments are not sent** — the attach button works, but files are not yet passed to the planner from Puck's chat panel
* **No nested zones** — only flat `content` arrays; nested layout zones are not yet supported
* **Image upload** — basic URL picker only, no upload progress or validation

## What to read next

<CardGroup cols={2}>
  <Card title="A tour of the editor" icon="pen-to-square" href="/editing">
    The chat editor Puck mode sits alongside, on the same blocks and the same publishing pipeline.
  </Card>

  <Card title="Block system" icon="cubes" href="/integration/block-system">
    What Puck is dragging: manifests, field metadata and validation.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.