Drawing

The editor's tools as commands — the GUI tools dispatch exactly these. Color, brush and tool options you leave out come from the editing context. Painting ignores the selection and symmetry unless you pass respectSelection = true and symmetry = app.getContext().symmetry. (24 functions)

app.blur(layerId, frameId, points, opts?) — changes, undoable, refused on a locked layer

Blurs the pixels under the brush along the points — exactly the GUI blur tool.

  • layerId (string)
  • frameId (string)
  • points (table) — List of { x = n, y = n } (or { n, n }) points; gaps between consecutive points are interpolated like a real drag.
  • opts (table, optional) Also takes the Painting options and Brush options (see "Option groups"), and:
    • strength (integer 0–8; default context.blurStrength) — Blur radius in pixels.

Returns nothing.

app.dodgeBurn(layerId, frameId, points, opts?) — changes, undoable, refused on a locked layer

Lightens (dodge) or darkens (burn) the pixels under the brush along the points, in OKLCH lightness — exactly the GUI dodge/burn tool. Hue and chroma are kept unless hueShift is set. Each pixel changes once per call; transparent pixels are untouched.

  • layerId (string)
  • frameId (string)
  • points (table) — List of { x = n, y = n } (or { n, n }) points; gaps between consecutive points are interpolated like a real drag.
  • opts (table, optional) Also takes the Painting options and Brush options (see "Option groups"), and:
    • strength (integer 1–100; default context.dodgeBurnStrength) — How far each touched pixel's OKLCH lightness moves: 100 = half of black-to-white, 25 = 0.125.
    • hueShift (integer 0–60; default context.dodgeBurnHueShift) — Degrees each touched pixel's OKLCH hue turns toward warm yellow (dodge) or cool blue (burn), never past it, with chroma lessened (dodge) or deepened (burn) by 0.5% per degree. 0 keeps hue and chroma.
    • burn (boolean; default false) — Darken (burn) instead of lighten (dodge).

Returns nothing.

app.drawContour(layerId, frameId, points, opts?) — changes, undoable, refused on a locked layer

Fills the closed path through the points, the path pixels included (Aseprite's contour) — exactly the GUI contour tool.

  • layerId (string)
  • frameId (string)
  • points (table) — The freehand path as a list of { x = n, y = n } points; it is auto-closed and filled.
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.

Returns nothing.

app.drawCurve(layerId, frameId, anchors, opts?) — changes, undoable, refused on a locked layer

Draws a path of cubic Bezier curves through the anchors — exactly the GUI curve tool. Pass closed = true for a closed shape (and fill = "filled" to fill it).

  • layerId (string)
  • frameId (string)
  • anchors (table) — The path's anchors in order: { x = n, y = n } (or { n, n }), each optionally with Bezier handles inX/inY (the control point of the segment arriving) and outX/outY (of the segment leaving). An anchor without handles is a sharp corner; two in a row are joined by a straight line.
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.
    • closed (boolean; default false) — Join the last anchor back to the first.
    • fill (FillMode: "outline" | "filled"; default context.shapeFillMode) — Closed paths: draw the outline, or fill the inside too.
    • width (integer 1–64; default context.lineWidth) — Stroke thickness in pixels (1 = a hard 1px curve); wider strokes get round ends.
    • pixelPerfect (boolean; default context.curvePixelPerfect) — Remove the L-shaped corners a 1px curve picks up, for clean pixel-art lines (ignored for wider strokes).

Returns nothing.

app.drawEllipse(layerId, frameId, x0, y0, x1, y1, opts?) — changes, undoable, refused on a locked layer

Draws an ellipse inscribed in the box spanning the two corners — exactly the GUI ellipse tool.

  • layerId (string)
  • frameId (string)
  • x0 (number) — First corner.
  • y0 (number)
  • x1 (number) — Opposite corner (inclusive).
  • y1 (number)
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.
    • fill (FillMode: "outline" | "filled"; default context.shapeFillMode) — Outline only, or filled.

Returns nothing.

app.drawGradient(layerId, frameId, x0, y0, x1, y1, opts?) — changes, undoable, refused on a locked layer

Fills the region the bucket would fill from (x0, y0) — the connected area of its colour (or every matching pixel when not contiguous), inside the selection — with a gradient from startColor at (x0, y0) to endColor at (x1, y1), or along stops — exactly the GUI gradient tool. Under symmetry the mirrored regions get the same gradient. A zero-length drag, or a start off the canvas or outside the selection, is a no-op.

  • layerId (string)
  • frameId (string)
  • x0 (number) — Gradient start (where startColor sits).
  • y0 (number)
  • x1 (number) — Gradient end (where endColor sits).
  • y1 (number)
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • startColor (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The color at the first point.
    • endColor (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.backgroundColor) — The color at the second point.
    • stops ({ color, color, ... } or { { color = c, position = 0-1 }, ... }; default When gradientColors is "stops" and neither startColor nor endColor is given, the gradientStops list.) — A multi-stop ramp of 2-32 colors from the first point to the second, instead of startColor and endColor. Plain colors are spread evenly; positions run 0-1 in order, and two stops at one position make a hard edge.
    • gradientType (GradientType: "linear" | "radial"; default context.gradientType) — A straight ramp between the points, or radiating from the first.
    • dithering (GradientDithering: "none" | "bayer2" | "bayer4" | "bayer8" | "dots" | "lines-h" | "lines-v" | "diagonal" | "noise"; default context.gradientDithering) — Ordered dithering applied to the ramp (none = smooth).
    • snap (GradientSnap: "free" | "palette"; default context.gradientSnap) — Free blends, or only palette colors (dithering then steps between neighbouring palette colors).
    • contiguous (boolean; default context.bucketFillMode (true for the context's contiguous mode, false for global)) — Only the connected region (true), or every matching pixel on the canvas (false).
    • tolerance (integer 0–255; default context.bucketTolerance) — The largest per-channel color difference that still counts as a match.
    • diagonal (boolean; default context.bucketDiagonal) — Contiguous only: also spread to diagonal neighbours (8-connected), so the region leaks through 1px diagonal lines.
    • stopAtGrid (boolean; default context.bucketStopAtGrid) — Confine the region to the grid cell the click lands in (an isometric grid's cell is the diamond it draws, with the line pixels of its two upper edges).
    • closeGap (integer 0–5; default context.bucketCloseGap) — Contiguous fills: treat gaps in the outline up to this many pixels wide as closed, so the fill stops at them instead of leaking out. 0 = off.

Returns nothing.

app.drawHexagon(layerId, frameId, x0, y0, x1, y1, opts?) — changes, undoable, refused on a locked layer

Draws a flat-top hexagon filling the box spanning the two corners — exactly the GUI hexagon tool.

  • layerId (string)
  • frameId (string)
  • x0 (number) — First corner.
  • y0 (number)
  • x1 (number) — Opposite corner (inclusive).
  • y1 (number)
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.
    • fill (FillMode: "outline" | "filled"; default context.shapeFillMode) — Outline only, or filled.

Returns nothing.

app.drawIsoShape(layerId, frameId, x, y, width?, depth?, height?, opts?) — changes, undoable, refused on a locked layer

Draws an isometric solid (box, ramp, stairs, pyramid, prism, cylinder, cone, sphere or dome) in pixel-art projection — exactly the GUI Iso Shape tool. Edges are clean staircases (2 px across per 1 px down at 2:1), faces are filled with the top / left / right colors, inner edges separate them and the silhouette is outlined. The footprint's back corner sits at (x, y); x runs down-right and y down-left on screen, and height raises the top. The round solids (cylinder, cone, sphere, dome) take width as their diameter and ignore depth; the sphere also ignores height.

  • layerId (string)
  • frameId (string)
  • x (number) — Anchor: the leftmost pixel of the cap at the footprint's back (top) corner, on the ground.
  • y (number)
  • width (number, optional) — Footprint along x (down-right), in iso units: each unit is one row of the 2:1 edge staircase. nil = the context's isoWidth.
  • depth (number, optional) — Footprint along y (down-left), in iso units. nil = the context's isoDepth.
  • height (number, optional) — Height in pixels (0 = a flat diamond). nil = the context's isoHeight.
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The base color: the top face when auto-shading.
    • shape (IsoShape: "box" | "ramp" | "stairs" | "pyramid" | "prism" | "cylinder" | "cone" | "sphere" | "dome"; default context.isoShape) — Which solid to draw.
    • cap (integer 2–4; default context.isoCap) — The flat run of pixels at the top and bottom vertices: 2 (even widths), 3 (odd) or 4 (multiples of four). Ratios above 2 have a wider natural cap.
    • bevel (integer 0–1024; default context.isoBevel) — Box only: chamfers the four top edges by this many pixels, a 45-degree slope between the top and the sides (0 = square edges). Clamped to the height and half the footprint.
    • style (IsoShapeStyle: "filled" | "outline" | "filled-outline"; default context.isoStyle) — Faces, outline, or both.
    • hiddenEdges (boolean; default context.isoHiddenEdges) — Also draw the edges behind the solid, in the inner-edge color (a see-through wireframe with style outline).
    • direction (IsoDirection: "+x" | "-x" | "+y" | "-y"; default context.isoDirection) — Ramp and stairs: the way they descend. Prism: the way one slope faces (+x and -x give the same roof). Ignored by the other shapes.
    • ratio (integer 1–8; default the sprite's isometric grid ratio (run / rise, rounded), else 2) — Pixels across per pixel down along the iso axes.
    • colors ({ outline =, innerEdge =, top =, left =, right = } colors; default auto-shaded from color, or the context's isoColors when isoAutoShade is off) — All five colors at once (left is the face toward +y, down-left; right the face toward +x). Overrides auto-shading.
    • autoShade (boolean; default context.isoAutoShade) — Derive the colors from color: top = color, the sides one and two steps darker along ramp (or computed), inner edges darker still, the outline darkest. false uses the context's isoColors. Ignored when colors is given.
    • ramp (a list of colors ("#rrggbb[aa]" or { r, g, b, a }); default context.shades) — The ramp auto-shading steps along when it contains color (the darker end is found by brightness). Otherwise the shades are computed, and snapped to the palette on an indexed sprite.

Returns nothing.

app.drawLine(layerId, frameId, x0, y0, x1, y1, opts?) — changes, undoable, refused on a locked layer

Draws a straight line between the two points — exactly the GUI line tool (width thickens it with round ends).

  • layerId (string)
  • frameId (string)
  • x0 (number)
  • y0 (number)
  • x1 (number)
  • y1 (number)
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.
    • width (integer 1–64; default context.lineWidth) — Line thickness in pixels (1 = a hard 1px line); wider lines get round ends.

Returns nothing.

app.drawPolygon(layerId, frameId, vertices, opts?) — changes, undoable, refused on a locked layer

Draws a closed polygon through the vertices — exactly the GUI polygon tool.

  • layerId (string)
  • frameId (string)
  • vertices (table) — List of { x = n, y = n } (or { n, n }) vertices, at least 2; the polygon closes back to the first automatically.
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.
    • fill (FillMode: "outline" | "filled"; default context.shapeFillMode) — Outline only, or filled.

Returns nothing.

app.drawRectangle(layerId, frameId, x0, y0, x1, y1, opts?) — changes, undoable, refused on a locked layer

Draws an axis-aligned rectangle spanning the two corners — exactly the GUI rectangle tool (radius rounds the corners, together or one by one). Ignores the selection unless respectSelection = true.

  • layerId (string)
  • frameId (string)
  • x0 (number) — First corner.
  • y0 (number)
  • x1 (number) — Opposite corner (inclusive).
  • y1 (number)
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.
    • fill (FillMode: "outline" | "filled"; default context.shapeFillMode) — Outline only, or filled.
    • radius (an integer 0–1024 for every corner, or a list of four { topLeft, topRight, bottomRight, bottomLeft }; default context.cornerRadius) — Rounds the corners, in pixels (0 = square): one radius for all four, or one per corner going clockwise from the top-left. Each is clamped to half the smaller side.

Returns nothing.

app.drawStar(layerId, frameId, x0, y0, x1, y1, opts?) — changes, undoable, refused on a locked layer

Draws a 5-point star (point up) whose outer points touch every side of the box spanning the two corners — exactly the GUI star tool.

  • layerId (string)
  • frameId (string)
  • x0 (number) — First corner.
  • y0 (number)
  • x1 (number) — Opposite corner (inclusive).
  • y1 (number)
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.
    • fill (FillMode: "outline" | "filled"; default context.shapeFillMode) — Outline only, or filled.

Returns nothing.

app.drawStroke(layerId, frameId, points, opts?) — changes, undoable, refused on a locked layer

Freehand brush stroke through the points — exactly the GUI pencil (or, with erase = true, the eraser; with dither, the dither brush).

  • layerId (string)
  • frameId (string)
  • points (table) — List of { x = n, y = n } (or { n, n }) points; gaps between consecutive points are interpolated like a real drag.
  • opts (table, optional) Also takes the Painting options, Brush options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.
    • erase (boolean; default false) — Erase to transparent instead of painting (the eraser); color is ignored.
    • pixelPerfect (boolean; default context.pixelPerfect) — Remove doubled corner steps from the stroke path (any brush size).
    • matchColor (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default nil (every pixel)) — Only paint (or erase) pixels that are exactly this color; others are untouched. With color = the background color and matchColor = the foreground color this is Aseprite's right-click eraser.
    • dither ({ pattern = "bayer2" | "bayer4" | "bayer8" | "dots" | "lines-h" | "lines-v" | "diagonal" | "noise", density = 0-100 }; default nil (every pixel)) — Only paint (or erase) the pixels of an ordered pattern at a density in percent, leaving the rest untouched: the dither brush (50 with bayer2 is a checkerboard). The pattern tiles from the sprite's top-left corner, so overlapping strokes stay aligned.
    • dynamics ({ stabilizer = 0-64, pressure = { size, angle, gradient (booleans), min, max (0-100) }, velocity = { same }, minSize, minAngle, maxAngle, dither, curve = 25-400 }; default built from the context's stabilizer, pressure*/velocity* and dynamics* fields; pass {} for a plain stroke) — Brush dynamics: a stabilizer (moving average of the points) and pressure / velocity sensors that drive the stamp size (from minSize up to the brush size), angle (minAngle to maxAngle) and a color gradient from color to endColor (dither = true picks one or the other per pixel; indexed sprites snap to the nearest palette color). min/max are the sensor range in percent (min > max inverts); curve is the sensitivity in percent (100 = linear). With pixelPerfect and a varying size, elbows are still removed along the center path. Custom brushes only get the stabilizer and gradient.
    • pressures (list of numbers 0-1, one per point; default 1 (full pressure) for every point) — Per-point pen pressure read by the pressure sensor. A mouse has none, so it counts as full.
    • velocities (list of numbers >= 0, one per point; default 0 for every point) — Per-point pointer speed in sprite pixels per millisecond (0.5 = the sensor's maximum) read by the velocity sensor.
    • endColor (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.backgroundColor) — The gradient's end color when a sensor drives the gradient; color is the start.

Returns nothing.

app.drawTriangle(layerId, frameId, x0, y0, x1, y1, opts?) — changes, undoable, refused on a locked layer

Draws an isosceles triangle (apex top-centre, base along the bottom) filling the box spanning the two corners — exactly the GUI triangle tool.

  • layerId (string)
  • frameId (string)
  • x0 (number) — First corner.
  • y0 (number)
  • x1 (number) — Opposite corner (inclusive).
  • y1 (number)
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.
    • fill (FillMode: "outline" | "filled"; default context.shapeFillMode) — Outline only, or filled.

Returns nothing.

app.floodFill(layerId, frameId, x, y, opts?) — changes, undoable, refused on a locked layer

Paint-bucket fill starting at (x, y) — exactly the GUI bucket tool.

  • layerId (string)
  • frameId (string)
  • x (number)
  • y (number)
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.
    • contiguous (boolean; default context.bucketFillMode (true for the context's contiguous mode, false for global)) — Only the connected region (true), or every matching pixel on the canvas (false).
    • tolerance (integer 0–255; default context.bucketTolerance) — The largest per-channel color difference that still counts as a match.
    • diagonal (boolean; default context.bucketDiagonal) — Contiguous only: also spread to diagonal neighbours (8-connected), so the region leaks through 1px diagonal lines.
    • stopAtGrid (boolean; default context.bucketStopAtGrid) — Confine the region to the grid cell the click lands in (an isometric grid's cell is the diamond it draws, with the line pixels of its two upper edges).
    • closeGap (integer 0–5; default context.bucketCloseGap) — Contiguous fills: treat gaps in the outline up to this many pixels wide as closed, so the fill stops at them instead of leaking out. 0 = off.
    • pattern (FillPattern: "solid" | "checker" | "dither25" | "dither75" | "hstripes" | "vstripes" | "diagonal" | "grid" | "dots" | "bricks"; default context.bucketPattern) — Fill with a repeating pattern of color and patternColor, tiled from the canvas's top-left corner. "solid" = just color.
    • patternColor (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.backgroundColor) — The pattern's second color (ignored when pattern is "solid").

Returns nothing.

app.isoProject(layerId, frameId, projection, opts?) — changes, undoable, refused on a locked layer

Projects the selected pixels (the marquee follows) — or the whole cel when nothing is selected — onto a face of an isometric cube: "left" and "right" shear the columns along the slope, "floor" turns the region into the top face (a square becomes a diamond). Pixel-exact: every edge comes out as a clean staircase (2 across per 1 down at 2:1) and no colors are blended. Content landing outside the canvas and the cel bounds is cut (the Background layer is cut to the canvas).

  • layerId (string)
  • frameId (string)
  • projection (IsoProjection: "left" | "right" | "floor")
  • opts (table, optional)
    • run (integer 1–16; default The sprite's isometric grid ratio, or 2 (2:1) when the grid is rectangular.) — Pixels across per rise pixels down (the slope, in lowest terms). Give rise too.
    • rise (integer 1–16; default The sprite's isometric grid ratio, or 1 (2:1) when the grid is rectangular.) — Pixels down per run pixels across. Give run too.

Returns nothing.

app.jumble(layerId, frameId, points, opts?) — changes, undoable, refused on a locked layer

Randomized smudge: scrambles pixels under the brush with random neighbors along the points — exactly the GUI jumble tool.

  • layerId (string)
  • frameId (string)
  • points (table) — List of { x = n, y = n } (or { n, n }) points; gaps between consecutive points are interpolated like a real drag.
  • opts (table, optional) Also takes the Painting options and Brush options (see "Option groups"), and:
    • strength (integer 0–100; default context.jumbleStrength) — Percent chance each touched pixel is scrambled. A 1px brush has no neighbors to scramble with, so use brushSize 2 or more.
    • seed (integer 0–4294967295; default random) — Random seed: the same seed and points give the same result.

Returns nothing.

app.movePixels(layerId, frameId, dx, dy) — changes, undoable, refused on a locked layer

Moves the selected pixels (per the current selection; the marquee follows) — or the whole cel when nothing is selected — by (dx, dy). Exactly the GUI move tool. Without a selection the whole cel moves and keeps everything, past the canvas edge too; moved selection pixels are kept within the canvas and the cel's bounds, and cut beyond. The Background layer is cut to the canvas.

  • layerId (string)
  • frameId (string)
  • dx (number) — Pixels to move right (negative = left).
  • dy (number) — Pixels to move down (negative = up).

Returns nothing.

app.outline(layerId, frameIds, opts?) — changes, undoable, refused on a locked layer

Filter > Outline, as in Aseprite: draws an outline around (or just inside) the shapes on a layer's cels, as a single undo step. A pixel is part of a shape unless it is transparent (or matches bgColor). Outside outlines grow the cel, clipped to the canvas. Image layers only.

  • layerId (string)
  • frameIds (table) — Array of frame ids whose cels on this layer are outlined (one frame for the active cel, every frame for all of them).
  • opts (table, optional)
    • cels (Array of { layerId = ..., frameId = ... }) — Outline these cels, across layers and frames, instead of layerId/frameIds (pass nil for both).
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The outline color. On an indexed sprite it snaps to the nearest palette entry unless colorIndex is given.
    • colorIndex (integer 0–255; default Taken from color.) — Indexed sprites: the palette index to paint, used as-is. Not the transparent index.
    • place (OutlinePlace: "outside" | "inside"; default "outside") — Outline outside the shape (it grows) or inside it (its edge pixels are repainted).
    • shape (OutlineShape: "circle" | "square"; default "circle") — Preset for the neighbor matrix. Ignored when matrix is given.
    • matrix (9 booleans, row-major 3x3 (top-left first): which neighbors count as touching. The center entry is ignored.) — A custom neighbor matrix, like Aseprite's 3x3 toggle grid.
    • bgColor (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default Only transparent pixels are background.) — An opaque color that also counts as background, besides fully transparent pixels.
    • bgIndex (integer 0–255) — Indexed sprites: a palette index that also counts as background.
    • respectSelection (boolean; default false) — Pass true to outline only inside the current selection. By default the selection is ignored.

Returns nothing.

app.pastePixels(layerId, frameId, image, opts?) — changes, undoable, refused on a locked layer

Pastes an image onto a layer/frame's cel like the GUI's floating paste: transparent pixels leave the cel alone, partly transparent ones blend over it, and the pasted pixels become the selection. The optional transform distorts it (corners), then scales, rotates and/or skews the image about its center (unless pivotX/pivotY are given), then shifts it by dx/dy. Needs an editable (unlocked) image layer; a movement lock does not apply. What lands outside the canvas and the cel's bounds is cut (the Background layer is cut to the canvas).

  • layerId (string)
  • frameId (string)
  • image (table) — { x, y, width, height, pixels } — pixels is a list of width*height colors ("#rrggbb[aa]" or { r, g, b, a }), row by row; x, y is where the top-left lands.
  • opts (table, optional)
    • scaleX (number -256–256; default 1) — Horizontal scale about the pivot; negative flips. Not 0.
    • scaleY (number -256–256; default 1) — Vertical scale about the pivot; negative flips. Not 0.
    • rotation (number; default 0) — Degrees clockwise about the pivot.
    • skewX (number -80–80; default 0) — Degrees of horizontal shear (the top leans one way, the bottom the other, about the pivot).
    • skewY (number -80–80; default 0) — Degrees of vertical shear.
    • dx (number; default 0) — Pixels to shift right after transforming.
    • dy (number; default 0) — Pixels to shift down after transforming.
    • pivotX (number; default The center of the selection (or of the cel when nothing is selected).) — X of the fixed point for rotate/scale/skew, in canvas pixels.
    • pivotY (number; default The center of the selection (or of the cel when nothing is selected).) — Y of the fixed point for rotate/scale/skew, in canvas pixels.
    • interpolation (TransformInterpolation: "nearest" | "rotsprite" | "bilinear"; default "nearest") — How pixels are resampled. Use rotsprite for clean rotations of pixel art, bilinear for smooth (blended) results.
    • corners ({ {x=,y=}, {x=,y=}, {x=,y=}, {x=,y=} }; default The region's own corners (no distortion).) — Free distort / perspective: where the region's top-left, top-right, bottom-right and bottom-left corners land, in canvas pixels (fractions allowed), before the scale/skew/rotation/shift above. Must form a convex shape. Pinning the two top corners closer together than the bottom ones gives a floor-like perspective.

Returns nothing.

app.scatter(layerId, frameId, points, opts?) — changes, undoable, refused on a locked layer

Scatter brush: stamps the brush along the points, one step per brush width, each stamp nudged by a random offset — exactly the GUI scatter tool.

  • layerId (string)
  • frameId (string)
  • points (table) — List of { x = n, y = n } (or { n, n }) points; gaps between consecutive points are interpolated like a real drag.
  • opts (table, optional) Also takes the Painting options, Brush options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.
    • offsetX (integer 0–64; default context.scatterX) — How far each stamp can land left or right of the path, in pixels.
    • offsetY (integer 0–64; default context.scatterY) — How far each stamp can land above or below the path, in pixels.
    • count (integer 1–16; default context.scatterCount) — Stamps placed at each step along the path.
    • seed (integer 0–4294967295; default random) — Random seed: the same seed and points give the same result.

Returns nothing.

app.spray(layerId, frameId, points, opts?) — changes, undoable, refused on a locked layer

Airbrush: scatters random dots around each point — exactly the GUI spray tool. Each point is one tick, so repeat a point to keep spraying in place.

  • layerId (string)
  • frameId (string)
  • points (table) — List of { x = n, y = n } (or { n, n }) points; gaps between consecutive points are interpolated like a real drag.
  • opts (table, optional) Also takes the Painting options and Ink options (see "Option groups"), and:
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The paint color.
    • radius (integer 1–128; default twice the context's brushSize, at least 2) — How far from each point the dots scatter, in pixels.
    • rate (integer 1–64; default context.sprayRate) — Dots scattered per point.
    • seed (integer 0–4294967295; default random) — Random seed: the same seed and points give the same result.

Returns nothing.

app.strokeSelection(layerId, frameId, width, opts?) — changes, undoable, refused on a locked layer

Edit > Stroke Selection: paints a line of the given width along the current selection's edge (inside, centered or outside it) on one cel, as a single undo step. Does nothing when nothing is selected. Image layers only.

  • layerId (string)
  • frameId (string)
  • width (number) — Pixels, 1 to 256.
  • opts (table, optional)
    • position (StrokePosition: "inside" | "center" | "outside"; default "center") — Where the stroke sits relative to the selection's edge.
    • color (color ("#rgb", "#rrggbb[aa]" or { r, g, b, a }); default context.foregroundColor) — The stroke color. On an indexed sprite it snaps to the nearest palette entry unless colorIndex is given.
    • colorIndex (integer 0–255; default Taken from color.) — Indexed sprites: the palette index to paint, used as-is. Not the transparent index.
    • shape (SelectionModifyShape: "circle" | "square"; default "circle") — How distance from the edge is measured (round or square corners).

Returns nothing.

app.transformPixels(layerId, frameId, opts?) — changes, undoable, refused on a locked layer

Scales, rotates, skews and/or distorts (perspective, via corners) the selected pixels (the marquee follows) — or the whole cel when nothing is selected — about a pivot, exactly like the GUI move tool's transform handles. Order: scale, skew, rotate, then shift by dx/dy. On a sprite with non-square pixels (Sprite.pixelRatio) the angles and scales are in what you see on screen, so a 90 degree rotation looks like one. Without a selection the whole cel keeps what lands within the box of the canvas and the cel's bounds, both where it is and shifted by dx/dy (so a plain shift loses nothing, past the canvas edge too); transformed selection pixels are kept within the canvas and the cel's bounds and cut beyond. The Background layer is cut to the canvas. A no-op transform changes nothing.

  • layerId (string)
  • frameId (string)
  • opts (table, optional)
    • scaleX (number -256–256; default 1) — Horizontal scale about the pivot; negative flips. Not 0.
    • scaleY (number -256–256; default 1) — Vertical scale about the pivot; negative flips. Not 0.
    • rotation (number; default 0) — Degrees clockwise about the pivot.
    • skewX (number -80–80; default 0) — Degrees of horizontal shear (the top leans one way, the bottom the other, about the pivot).
    • skewY (number -80–80; default 0) — Degrees of vertical shear.
    • dx (number; default 0) — Pixels to shift right after transforming.
    • dy (number; default 0) — Pixels to shift down after transforming.
    • pivotX (number; default The center of the selection (or of the cel when nothing is selected).) — X of the fixed point for rotate/scale/skew, in canvas pixels.
    • pivotY (number; default The center of the selection (or of the cel when nothing is selected).) — Y of the fixed point for rotate/scale/skew, in canvas pixels.
    • interpolation (TransformInterpolation: "nearest" | "rotsprite" | "bilinear"; default "nearest") — How pixels are resampled. Use rotsprite for clean rotations of pixel art, bilinear for smooth (blended) results.
    • corners ({ {x=,y=}, {x=,y=}, {x=,y=}, {x=,y=} }; default The region's own corners (no distortion).) — Free distort / perspective: where the region's top-left, top-right, bottom-right and bottom-left corners land, in canvas pixels (fractions allowed), before the scale/skew/rotation/shift above. Must form a convex shape. Pinning the two top corners closer together than the bottom ones gives a floor-like perspective.

Returns nothing.

As Markdown: drawing.md.