image#
A static image, sized into a box with a choice of fit modes and optional color filters. Inherits common fields.
interface ImageElement extends BaseElement { type: 'image'; source: string; fit?: 'cover' | 'contain' | 'fill' | 'none'; crop_x?: number; crop_y?: number; crop_width?: number; crop_height?: number; brightness?: number; contrast?: number; saturation?: number; blur?: number; }
Required#
| Field | Type | Default | Description |
|---|---|---|---|
source | string (URL) | required | HTTP(S) URL of the image. PNG, JPEG, WebP, and animated GIF (first frame only) are supported. Local file paths fail in the render service today; see render-service docs. |
Layout#
| Field | Type | Default | Description |
|---|---|---|---|
fit | 'cover' | 'contain' | 'fill' | 'none' | 'cover' | How the image fills the element's box. Same semantics as CSS object-fit. |
cover— fill the box, crop overflow.contain— fit the whole image inside the box, letterbox if needed.fill— stretch to the box's aspect ratio.none— render at the image's natural pixel size, anchored.
Crop#
A normalized sub-rectangle of the source image, applied before fit. The element's box is unchanged — crop just chooses which part of the source fills it. Omit the fields (or leave the identity 0,0,1,1) for no crop. In the editor, the Crop widget in the Media section gives you both the numeric fields and a drag-to-resize frame over the image.
| Field | Type | Default | Description |
|---|---|---|---|
crop_x | number (0–1) | 0 | Left edge of the kept region, as a fraction of source width. |
crop_y | number (0–1) | 0 | Top edge, as a fraction of source height. |
crop_width | number (0–1) | 1 | Width of the kept region, as a fraction of source width. |
crop_height | number (0–1) | 1 | Height of the kept region, as a fraction of source height. |
Each component is keyframeable — animate the origin to pan and the size to zoom for a Ken Burns move that never touches the element's layout.
Filters#
All filter values are percentages on a 0–200 scale: 100 is neutral, 0 is fully removed, 200 is doubled. Blur is in pixels.
| Field | Type | Default | Description |
|---|---|---|---|
brightness | number | 100 | Luminance multiplier. 0 = black; 100 = neutral; 200 = double brightness. |
contrast | number | 100 | Contrast multiplier. 0 = solid mid-grey; 200 = high-contrast. |
saturation | number | 100 | Saturation multiplier. 0 = grayscale; 200 = oversaturated. |
blur | number | 0 | Gaussian blur radius in pixels. |
Examples#
Full-bleed background with darkening#
{ "type": "image", "source": "https://images.unsplash.com/photo-...", "x": 960, "y": 540, "width": 1920, "height": 1080, "fit": "cover", "brightness": 60 }
Subtle blur for a depth-of-field effect#
{ "type": "image", "source": "https://example.com/backdrop.jpg", "fit": "cover", "blur": 8 }
Grayscale logo#
{ "type": "image", "source": "https://example.com/logo.png", "fit": "contain", "saturation": 0 }
Crop to the center half of the source#
{ "type": "image", "source": "https://example.com/photo.jpg", "fit": "cover", "crop_x": 0.25, "crop_y": 0.25, "crop_width": 0.5, "crop_height": 0.5 }
Notes#
- Aspect-ratio mismatch — when
fitiscover, the image is centered on its anchor and cropped to fit. To control which side gets cropped, setx_anchor/y_anchor. - Animated GIFs render at frame 0 only; use a
videoelement for moving image content. - Asset caching — the runtime caches fetched images by URL within a render. The hosted render API also caches across renders for the same URL.