Frames
Container frames that group sections, and placeholder (image-mask) frames that clip an image to a shape.
"Frame" covers two distinct, additive features that share a name. Both are optional - documents authored before frames existed load and render unchanged.
- Container frames group other sections into a movable unit with an optional background.
- Placeholder frames are shaped image slots - an image clipped to a rectangle, circle, or line.
Pages are unchanged by either: a frame lives on a page, and each page still exports to exactly one PDF page.
Container frames
A container frame is a FrameSection (type: 'frame') - a box that owns other sections. It draws an optional fill, stroke, and radius, and everything dropped inside it becomes a child.
import type { FrameSection } from '@docmosaic/core';
const frame: FrameSection = {
id: 'card',
type: 'frame',
x: 40,
y: 40,
width: 300,
height: 200,
page: 1,
zIndex: 0,
fill: '#ffffff', // 'transparent' (default) → invisible grouping box
stroke: '#e5e5e5', // 'transparent' (default) → no border
radius: 8, // corner radius in points; default 0
};Parenting is flat
Children are not nested under the frame. They stay in the same flat Document.sections array and link back to their frame by a single parentFrameId field. This keeps the tree flat (the document-model design choice) while still letting a frame behave as a unit:
- Adopt on drop - dragging a section so its center lands inside a frame stamps
parentFrameId; dragging it back out clears it. The pure rule isresolveFrameParent(section, sections)from@docmosaic/core. - Move with children - dragging the frame translates every child with it.
- Cascade - deleting a frame deletes its children; duplicating a frame clones its children, re-pointed at the new frame.
Frames render behind their children
A container frame is a backdrop, so it must paint behind the sections it holds. Render order is zIndex ascending, then frames before non-frames at equal zIndex, then array order - the shared orderSectionsForRender helper that the canvas, the PDF generator, and the PNG generator all use. A filled or bordered frame therefore never covers its contents, regardless of the order sections were added. See Layers.
The tool
Editor.FrameToolButton arms a draw-to-size tool: while armed, dragging on an empty part of the page rubber-bands a new frame at that size. Press Escape or pick the Select tool to disarm. It is mutually exclusive with the shape, image-frame, and drawing tools.
Placeholder frames
A placeholder frame is an ImageSection with a maskShape:
import type { ImageSection } from '@docmosaic/core';
const slot: ImageSection = {
id: 'avatar',
type: 'image',
x: 40,
y: 40,
width: 120,
height: 120,
page: 1,
zIndex: 0,
maskShape: 'circle', // 'rect' | 'circle' | 'line'
// imageUrl is filled in when the user drops/uploads an image
};When maskShape is set the image is clipped to the shape on render - a circle clips to the inscribed ellipse in both the PDF and PNG pipelines. An empty slot (no imageUrl) shows the upload placeholder; drop or pick an image to fill it, and swap it any time. The mask composes with the existing non-destructive crop. Without maskShape, an image takes the unchanged, byte-stable draw path.
Editor.ImageFrameToolButton arms the matching draw-to-size tool, with a dropdown to pick the slot shape.
See also
- Document model - where
parentFrameIdandmaskShapelive - Layers - the shared render order and
orderSectionsForRender - Editor.FrameToolButton · Editor.ImageFrameToolButton