Zoom regions
Punch-ins as one object with in, hold, and out timing, a target, easing, and motion blur.
A zoom region is one punch-in on a video, image, or multicam element. It zooms
in over inMs, holds for holdMs, and zooms back out over outMs, all in
element-local time. A multicam zoom names a source key, so every slot showing
that source zooms and the other slots keep their framing. The screen can zoom
while the camera overlay stays put. A slot zooms inside its crop, so a zoom
never shows source the crop cuts away. A multicam zoom with no source zooms
the whole composite, overlays included, inside the element's frame.
Regions on one target never overlap. The zoom commands keep the region they add
or change inside the element. A split copies a region that crosses the cut into
both halves, so the picture on each side stays the same. The right half's copy
gets the id with -r appended, so no two pieces share a zoom id. A trim can
leave a region running past an edge, where it plays cut off. Growing a clip
from its start shifts the regions with the content.
addZoomRegion and updateZoomRegion take time. "element", the SDK
default, reads atMs as element-local ms. "timeline", the MCP server
default, reads it as project timeline ms. With "timeline", addZoomRegion
covers that timeline range on every abutting piece of the same media on the
element's track, so a zoom over a cut between two pieces is one command. Each
piece after the first gets a copy with -r appended to the id, and each copy
updates on its own. updateZoomRegion only needs the region to overlap the
element, so those copies stay editable. A range that starts off a piece, runs
past the last piece, or crosses a gap is rejected.
engine.dispatch({
type: 'addZoomRegion',
elementId: 'e-multicam',
zoom: { preset: 'detailZoom', source: 'screen', atMs: 12_000, focus: { x: 0.75, y: 0.3 } },
})Types
ZoomRegion
ZoomRegion is z.infer<typeof zoomRegionSchema>, one stored zoom region with every field resolved.
ZoomRegionRef
ZoomRegionRef extends ZoomRegion with elementId and the region's timeline startMs and endMs, cut at the element's edges. A region that crosses a split lists the part each piece plays.
ZoomableElement
ZoomableElement is a video, image, or multicam element, the element types that hold zoom regions.
ContentView
ContentView is { scale, focus }, how a clip or slot frames its source at one
instant. scale multiplies the fit scale. focus is the anchor point from 0 to
1 that stays fixed while it scales.
VisibleFraction
VisibleFraction is { x, y }, the share of a slot's cropped source each axis
shows at scale 1 after the slot's fit. A cover slot shows less than 1 on the
axis it cuts, and a contain slot shows more than 1 on the axis it letterboxes.
getSlotView and centeredFocus take it.
Schemas
zoomRegionSchema
| Field | Type | Meaning |
|---|---|---|
id | string | Stable id, minted as z-... when omitted |
source | string, optional | Multicam source key whose slots zoom. Absent on clips, and absent on a multicam zoom of the whole composite |
atMs | integer ms | Element-local start of the zoom-in, negative on the right half of a split through a zoom |
inMs, holdMs, outMs | integer ms | Ramp in, hold, ramp out |
focus | { x, y } from 0 to 1 | Target center, across the cropped frame of a clip or multicam slot |
scale | 1 to 8 | Scale at the hold |
easing | Easing | Applied to both ramps |
motionBlur | 0 to 1 | Shutter as a fraction of one frame while the zoom moves. 0 turns it off |
zoomCommandSchema
zoomCommandSchema is the discriminated union of addZoomRegion, updateZoomRegion, and removeZoomRegion with their type. It is the input of the MCP edit_zooms tool.
Presets
ZOOM_REGION_PRESETS
| Preset | Scale | In | Hold | Out |
|---|---|---|---|---|
subtlePunchIn | 1.15 | 700 ms | 1600 ms | 700 ms |
detailZoom | 1.3 | 600 ms | 3000 ms | 600 ms |
addZoomRegion defaults to subtlePunchIn, easeOutExpo, and motion blur 0.5.
Explicit fields override the preset. A rect aims the zoom at its center and fills it only up to the preset scale, so a region never makes a detail zoom severe. Pass focus and scale for a stronger zoom. The MCP tools warn when any zoom goes above 1.5x.
Functions
listZoomRegions
listZoomRegions(project) returns every zoom region in the project as ZoomRegionRef[], in track and element order.
isZoomable
isZoomable(element) returns true for a video, image, or multicam element and narrows it to ZoomableElement.
zoomRegionEndMs
zoomRegionEndMs(region) returns the element-local time a zoom region ends, atMs + inMs + holdMs + outMs.
getSlotView
getSlotView(element, slot, timelineMs, visible, rest) returns the ContentView of one multicam layout slot. It is the one place a renderer reads a slot's framing. visible is the VisibleFraction of the slot, which differs from 1 when the slot's shape differs from its crop, and it defaults to the full frame. rest is the focus outside a zoom, where a zoom starts and ends, and it defaults to the center. The compositor passes the reframed focus from centeredFocus for a source with a reframe track. With neither a zoom nor a track, the view is the center at scale 1, so the slot's crop alone sets its framing.
getClipView
getClipView(element, timelineMs) returns the ContentView of a video or image clip inside its crop, or of a whole multicam composite from its zooms with no source.
getZoomWindow
getZoomWindow(view, visible) returns the part of the content a ContentView shows, as a normalized rect across the content. The window covers visible / scale of the content on each axis, anchored at the view's focus. visible is the VisibleFraction the target shows at scale 1, and it defaults to the full frame. Below scale 1 the window reaches past the content. The compositor draws a clip's window of its crop. It clamps a slot's window to the slot crop, so a contain slot keeps its letterbox centered.
getZoomedRect
getZoomedRect(view, rect) maps a normalized frame rect through a whole-composite ContentView. It returns where the rect lands on the canvas when the composite shows the view's getZoomWindow window. The multicam renderer maps its whole composite through it before the crop, and flattenMulticam bakes it into each flattened clip's transform keyframes, so a flattened clip follows its slot exactly.
getZoomShutterMs
getZoomShutterMs(element, timelineMs, frameMs) returns the motion blur shutter in milliseconds while any zoom on the element ramps, and 0 while every zoom holds or rests. The compositor renders the element at views sampled across this window into a scratch canvas and composites the average once, the same path as keyframe motion blur.