Design scripts
The JavaScript API for editing an ad's layers, modeled on Figma's Plugin API. One script is one atomic edit.
A design script is JavaScript that edits an ad's layers. Send it to
POST /v1/image-ads/:id/editsas{ "script": "..." }. It is the API our own AI Design Agent writes against, and it is free to call.
The API is Figma's Plugin API, simplified:
- Atomic. The whole script applies, or (on any error) nothing does.
- Synchronous. No font loading;
awaitis allowed but never needed. - Hex paints. Paints accept
"#RRGGBB"strings as well as paint objects. - Assignable size.
widthandheightcan be set directly. - Helpers on
docfor finding, arranging and creating layers.
Scripts run in a sandbox against a copy of the ad. If it succeeds, the result is saved as a new tree_revision and the image re-renders in the background.
Find layers
Get the layer ids, names, types, text and boxes from GET /v1/image-ads/:id/outline first, then find layers by id, name, type or text.
doc.root // the artboard (a FRAME)
doc.get(id) // one layer by id
doc.findAll(criteria?) / doc.findOne(criteria?)
node.findAll(criteria?) / node.findOne / node.findChildren / node.children / node.parent
figma.currentPage.findAll(fn) / findOne(fn) / figma.getNodeById(id)
// criteria: "TEXT" | (node) => boolean | { type, types, name, nameIncludes, text }
doc.findAll("TEXT")
doc.findOne({ name: "Headline" })
doc.findAll({ text: "shop now" })Every layer
id, type, name, visible, locked, opacity, blendMode, effects, isMask
x, y // relative to the parent frame, as in Figma (groups don't count)
width, height // assignable (resizes with the top-left fixed); or node.resize(w, h)
rotation // degrees, counter-clockwise, about the center
bounds // { x, y, width, height } on the canvas (read-only)
moveTo(x, y) · moveBy(dx, dy) · scaleBy(factor, { origin?, text? }) · rescale(f)
rotateBy(deg) · flip("horizontal" | "vertical") · clone() · remove()
bringToFront() · sendToBack() · bringForward() · sendBackward()
appendChild(node) · insertChild(index, node) // keeps the canvas positionAuto-layout children also have layoutSizingHorizontal, layoutSizingVertical, layoutPositioning, layoutGrow, layoutAlign and min/max sizes.
Shapes and frames
fills, strokes // "#RRGGBB" | paint | paint[]; [] clears
// { type: "SOLID", color: "#FF5500" | { r, g, b } (0..1), opacity? }
// { type: "IMAGE", url, scaleMode: "FILL" | "FIT" | "CROP" | "TILE" }
// { type: "GRADIENT_LINEAR", gradientStops: [{ position, color }], gradientTransform }
strokeWeight, strokeAlign, dashPattern, strokeJoin, strokeCap
cornerRadius, topLeftRadius, topRightRadius, bottomRightRadius, bottomLeftRadius
setImageCrop({ zoom, panX, panY }) // zoom 1 = cover fit; pan 0..1
effects // DROP_SHADOW, INNER_SHADOW, LAYER_BLUR, BACKGROUND_BLURFrames add clipsContent and auto layout (layoutMode, itemSpacing, padding, alignment, wrap). Auto layout re-lays out children after every change, as in Figma.
Text
characters, fontName ({ family, style }), fontSize, lineHeight, letterSpacing,
textCase, textDecoration, textAlignHorizontal, textAlignVertical, textAutoResize,
paragraphSpacing, maxLines, textTruncation, fills
setRangeFontName(start, end, font) · setRangeFontSize · setRangeFills · setRangeStyle(start, end, { ... })
getStyledTextSegments() · insertCharacters(i, text) · deleteCharacters(start, end) · replaceText(find, replacement)
doc.fonts.families() · doc.fonts.styles(family) // only these fonts existMixed text reads its dominant style; setting a style applies to all of it.
Icons and vectors
A library of about 1,500 Phosphor icons in five weights (thin, light, regular, bold, fill).
icons.search("delivery truck", { limit?, weight? }) // best matches first
node.setIcon("truck", "bold") // swap an icon layer's drawing
doc.createIcon("leaf", { size: 48, weight: "bold", x, y, fills: "#000000" })
doc.createFromSvg(svg, { size, x, y, color }) // draw your own when no icon fitsCreate and arrange
figma.createRectangle() / createEllipse() / createFrame() / createLine() / createText()
doc.createText(characters, { fontName, fontSize })
figma.group(nodes) · figma.ungroup(group) · doc.frame(nodes) · doc.mask(nodes)
doc.autoLayout(nodesOrFrame, { itemSpacing, paddingTop, ... })
doc.align(nodes, "left" | "center" | "right" | "top" | "middle" | "bottom", { to? })
doc.distribute(nodes, "horizontal" | "vertical", { gap? })
doc.stack(nodes, { axis: "vertical", gap: 24, align?: "start" | "center" | "end" })
doc.center(nodes, { axis?, within? })
doc.rebalance(nodes, { axis: "vertical" }) // re-centers a column between its neighbors
doc.moveBy(nodes, dx, dy) · doc.scale(nodes, factor) · doc.rotate(nodes, deg)
doc.images() // photos and logos you may place: [{ handle, label, url, width, height }]Results and errors
returna value to see it in the response; layers come back as{ id, type, name }.- After each script you get what changed, layers created and removed, and warnings it introduced: off canvas, text overflowing its box, font fallback, overlapping text, text too small to read, low contrast, and text where Stories and Reels UI covers it.
- A property that does not exist throws with a hint, and nothing is applied.
Examples
// Left-align all text, nudge it up 10px and keep the column balanced
const texts = doc.findAll("TEXT");
for (const t of texts) t.textAlignHorizontal = "LEFT";
doc.align(texts, "left");
doc.moveBy(texts, 0, -10);
doc.rebalance(texts, { axis: "vertical" });// Headline 10% bigger and bold, with the first line in a brand color
const h = doc.findOne({ name: "Headline" });
h.fontSize = Math.round(h.fontSize * 1.1);
h.fontName = { family: h.fontName.family, style: "Bold" };
const end = h.characters.indexOf("\n");
h.setRangeFills(0, end > 0 ? end : h.characters.length, "#C2410C");// Stack three feature rows 24px apart and center the block
const features = ["Feature 1", "Feature 2", "Feature 3"].map((name) => doc.findOne({ name }));
doc.stack(features, { axis: "vertical", gap: 24, align: "start" });
doc.center(features, { axis: "horizontal" });
return features.map((f) => f.bounds);Layer names vary from ad to ad. Read them from the outline rather than assuming them.