The middle column of the editor — the canvas where the page renders. This folder spells out how the canvas is structured, the device/breakpoint/zoom machinery, and the interactions that hang off it.
The middle column of the editor — the canvas where the page renders. This folder spells out how the canvas is structured, the device/breakpoint/zoom machinery, and the interactions that hang off it.
docs/is gitignored — these notes are local-only.
┌──────────────────────────────────────────────────────────┐
│ ⋮ 💾 📐 👁 [📺▼] ↶ ↷ + ← Header (canvas mode + zoom)
├──────────────────────────────────────────────────────────┤
│ ┌──────────────────────────────────────────────┐ │
│ │ │ │
│ │ <iframe-like page render> │ │
│ │ (clamped/centered per mode) │ │
│ │ │ │
│ └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
The canvas has three orthogonal modes that combine to produce what the user sees:
ViewAtom): desktop, mobile, sm, md, lg, xl, 2xl.
Determines width/clamp behavior AND the write scope (canvas viewport =
edit scope). Default is device-aware — desktop (fluid full-width)
when the editor loads on a viewport ≥ 768px, mobile when loading on a
touch/narrow device. Both desktop and mobile write to the base
Tailwind layer. Switching to md sets the canvas to 768 px and directs
all class writes to md:. (Defined at the ViewAtom declaration; see
atoms.ts. Full scope
logic: responsive-editor.md.)DeviceAtom): boolean. When true + view === "mobile", renders
inside a phone bezel with width/height from DeviceDimensionsAtom.zoom scale applied to the canvas wrapper. Two
atoms — one for breakpoint/desktop view, one for device-mobile view.Plus a fourth toggle:
PreviewAtom): hides editor chrome and disables CraftJS
selection — pure visitor render.BreakpointZoomAtom / DeviceZoomAtom, CanvasZoom component, fit-to-window, persistence, the icon-vs-percentage trigger.(Add more files here as we document other viewport areas — canvas modes, preview, header chrome, breadcrumb, etc.)
| Concern | File |
|---|---|
| Top header — canvas mode dropdown, undo/redo, preview, insert | packages/sdk/src/chrome/viewport/ViewportTopBar/ |
| Canvas wrapper — applies view classes, device bezel, CSS zoom | packages/sdk/src/chrome/viewport/Viewport/ |
| Zoom UI primitive (+/−, dropdown, fit-to-window, reset) | packages/sdk/src/chrome/viewport/CanvasZoom.tsx |
Atoms — ViewAtom, DeviceAtom, *ZoomAtom, etc. | packages/sdk/src/chrome/viewport/atoms.ts |
Breakpoint pixel widths + isEditorCanvasBreakpointView | packages/sdk/src/utils/tailwind/className.ts |
| Device dimensions / phone picker | packages/sdk/src/chrome/viewport/DeviceSelector.tsx |
| Selected node breadcrumb (top of canvas in some modes) | packages/sdk/src/chrome/viewport/NodeBreadcrumb.tsx |
| Right-click contextual menu on canvas | packages/sdk/src/chrome/viewport/ToolboxContextual/ |
| Mode | View | Device | Width behavior | Centered? | Zoom atom |
|---|---|---|---|---|---|
| Responsive (default) | desktop | off | Fluid — fills column | No (flex-row) | BreakpointZoomAtom |
| Breakpoint | sm … 2xl | off | Clamped to fixed px width | Yes (bg-neutral/50 letterbox) | BreakpointZoomAtom |
| Device | mobile | on | Phone width + bezel | Yes (centered) | DeviceZoomAtom |
Switching is via the canvas-mode dropdown in the header. The dropdown trigger icon swaps based on view (desktop icon / mobile icon / SM-MD-LG-XL-2XL label), and when zoom ≠ 100% it shows the percentage instead — see zoom.md.