Outpaint canvasPro
Zoom out from an image and drag eight handles to extend its canvas. The area the model will fill shows as a dashed frame with its size before anything runs, with aspect presets, Zoom out 1.5× and 2×, extend by a side, undo, a size cap warning and the result revealed from the original's edges outward.
On this page
Installation
Usage
import { OutpaintCanvas } from "@/components/ui/chatcn/pro/outpaint-canvas"
<OutpaintCanvas
src={image.url}
alt={image.alt}
width={image.width}
height={image.height}
generating={job.running}
progress={job.progress}
result={job.url}
onGenerate={(frame, output) => start({ frame, output })}
/>The frame is in the original's own pixels, relative to its top left corner, and always contains it: { x: -300, y: 0, width: 1368, height: 768 } adds 300 px on each side of a 768 px square. Added sizes snap to step (8 px by default) so they suit the model. onGenerate also receives the output size, scaled down when the long edge passes maxSize. Pass the finished image of the whole frame as result; it shows until the frame changes again, so people can keep extending. The frame math (resize with ratio and symmetry, zoom out, extend, area) is exported from chatcn-pro-studio-2a-outpaint for your own controls.
Examples
States
Props
| Prop | Type | Notes |
|---|---|---|
src, alt | string | The original image |
width, height | number | The original's size in px. Required: every frame value uses it |
frame, defaultFrame, onFrameChange | { x, y, width, height } | Default the original itself. Fires once per drag, key press burst, preset or undo |
aspect, defaultAspect, onAspectChange | "free" | "1:1" | "4:3" | "3:2" | "16:9" | "9:16" | A preset locks the ratio while you drag. Default free |
aspects | OutpaintAspect[] | Which presets the toolbar offers |
onGenerate, generateLabel | (frame, output) => void, string | Shows the "Extend image" button |
generating, progress, expectedMs, onCancel | boolean, number | null, number, () => void | Locks the frame; real progress when you have it, an honest creep when you do not |
result | string | null | The finished image of the whole frame |
error, onRetry | boolean | string, () => void | Retry defaults to generating again |
maxSize | number | Long edge the model returns. Default 4096, with an amber warning past it |
step | number | Added sizes snap to it. Default 8 |
disabled, toolbar, stageHeight | boolean, boolean, number | Stage height default 440 px |
Keyboard
| Key | Action |
|---|---|
| Arrows on a handle | Move that edge or corner by 8 px; with Shift, by 64 px; with Alt, from the center |
Page Up, Page Down on a handle | Grow or shrink that side by 64 px |
Home on a handle | Remove what that side added |
| Arrows on the image | Move the image inside the frame |
+, -, 0 | Zoom the view in, out, or fit the frame |
Space and drag | Pan the view |
⌘Z or Ctrl+Z, ⇧⌘Z or Ctrl+Y | Undo and redo frame changes |
Accessibility
- Each handle is a slider named for its side, "Extend left edge", whose value is the pixels it added, read as "320 px left added".
- The image is a focusable group that says where it sits in the frame; the stage describes every key.
- Frame changes, undo, the finished result and errors are announced politely. Progress shows as a number, not color.
- Numbers stay left to right in right to left layouts. Handles take 44 px on touch screens.
Motion
- Handles, the image and pans follow the pointer with no easing.
- After a pointer edit the view refits the new frame in 280 ms; keyboard edits refit at once. Zoom buttons glide in 180 ms.
- The result reveals from the original's edges outward with a 280 ms clip path. Under reduced motion every glide is instant and the result fades in 150 ms.