Scripting API

The node library as functions inside the JavaScript node. Generate, filter, and blend images in code.

Inside a JavaScript node, magerie.generators and magerie.ops put the node library at your fingertips as plain functions. Anything you can wire up as nodes, you can also write as a line of code:

//@output image out

let { noise } = magerie.generators
let { mul, blur } = magerie.ops

let a = noise("voronoi", 234234)
let b = noise("simplex", { scale: 2.4 })
out.value = blur(mul(a, b), 4)

Results are images. Pass them to other ops, assign one to an image output to feed the graph, or ctx.drawImage(img, x, y) it inside a draw recipe. The editor autocompletes every function with its full signature and options.

Calling ops#

Every function follows one convention:

  1. Images first. Filters take one (blur(img, ...)), blends and warps take two (mul(a, b)).
  2. A kind string, when the op has modes: noise("voronoi"), blend(a, b, "screen"), invert(img, "g").
  3. A primary number: the seed for noise, radius for blur, opacity for blends, gamma for levels.
  4. An options object for everything else: noise("voronoi", 7, { scale: 4, octaves: 6 }). Options are validated: unknown names and bad enum values throw with the valid choices listed, numbers clamp to their slider ranges.

Ops with a -> { ... } in their signature produce several images at once. Destructure the result: let { r, g, b } = channelSplit(img). Each member is a normal image you can pass along or dispose() independently.

Calls are cached per node: the same call with the same inputs reuses its texture instead of re-rendering, so calling ops inside a per-frame draw recipe is free as long as the parameters hold still. Everything a script creates is freed automatically the next time the node runs.

Errors land on the node itself: a typo like noise({ sclae: 2 }) shows the message on the node's error strip when you press Run.

magerie.generators#

noise(type?, seed?, opts?)#

Generates procedural noise textures using various algorithms

option type default range / options notes
type select "simplex" perlin, simplex, voronoi, white Noise algorithm to use
scale slider 8 0.1..100 X-axis frequency (higher = more detail). Y uses the same value unless Scale Y is set.
scaleY slider 0.1..100 Y-axis frequency. When equal to Scale the noise is isotropic; set higher than Scale for vertical streaks (grass blades, wood grain), lower for horizontal stripes (ripples, sediment).
aspect select "square" square, stretch Square: same proportions at any output size. Stretch: follows the output's shape.
voronoiMode select "f1" f1, f2, f2-f1, cell Voronoi sub-mode: F1 = distance to nearest cell point (default). F2 = distance to second-nearest. F2-F1 = the gap; dark at cell boundaries (the 'cracks' pattern for ice / concrete). Cell = the nearest cell's own value, giving flat facets for scales, tiles and stone slabs.
fractal select "standard" standard, ridged, billow Per-octave shaping. Standard is plain fBm. Ridged folds each octave at its midpoint and squares it - veins, creases, fibres, cracked rock. Billow takes the absolute fold - puffed lobes for clouds, blotches, rust. Folding per octave is what makes these read as their own families; a downstream Curves node cannot reproduce it.
offsetX number 0 Horizontal offset (driven by Time node for animation)
offsetY number 0 Vertical offset (driven by Time node for animation)
octaves slider 4 1..8 Number of noise layers for fractal detail
persistence slider 0.5 0..1 Amplitude reduction per octave
warp slider 0 0..2 Domain warp strength. Displaces each sample by a second noise field before evaluating, turning round blobs into torn, capillary shapes. 0 is off. The single biggest lever for grunge.
lacunarity slider 2 1.1..4 Frequency multiplier per octave. 2 is the classic value. Below ~1.7 the octaves overlap into soft cloud; above ~2.5 they separate into distinct scales.
seed number 0 Random seed for reproducibility
width stepped auto 1..8192 Output width in pixels (Auto uses document default)
height stepped auto 1..8192 Output height in pixels (Auto uses document default)

gradient(type?, opts?)#

Generates color gradients in various styles

option type default range / options notes
type select "linear" linear, radial, angular Gradient style
colors gradient stops Start and end colors of the gradient (multi-stop coming in a future release)
angle slider 0 0..360 Gradient angle in degrees (for linear)
centerX slider 0..1 Horizontal center position (for radial/angular)
centerY slider 0..1 Vertical center position (for radial/angular)
width number 1024 1..8192 Output width in pixels
height number 1024 1..8192 Output height in pixels

solidColor(color?, opts?)#

Generates a solid color fill

option type default range / options notes
color color "#808080" Fill color
width number 1024 1..8192 Output width in pixels
height number 1024 1..8192 Output height in pixels

sdfShape(shape?, size?, opts?)#

Generates signed distance field shapes with configurable geometry and colors as a colored image

option type default range / options notes
shape select "circle" circle, box, roundedBox, ellipse, capsule, trapezoid, parallelogram, equilateralTriangle, pentagon, hexagon, octagon, pie, arc, ring, heart, cross, moon, egg, vesica Shape type to generate
size slider 1.5 0.01..2 Overall scale of the shape
rotation slider 0 0..360 Rotation in degrees
offsetX number 0 -1..1 Horizontal offset
offsetY number 0 -1..1 Vertical offset
shapeWidth slider 0.5 0.1..1 Width for rectangular shapes
shapeHeight slider 0.5 0.1..1 Height for rectangular shapes
capsuleLength slider 0.6 0.1..1.5 Total length of the capsule
capsuleThickness slider 0.3 0.05..1 Thickness (diameter) of the capsule
cornerRadius slider 0.05 0..0.5 Corner radius for rounded shapes
angle slider 270 0..360 Angle for pie/arc shapes (degrees)
thickness slider 0.05 0.01..0.5 Thickness for arc/ring shapes
eggHeight slider 0.45 0.1..2 Height of the egg
eggBottomRadius slider 0.3 0.05..1 Width at the bottom of the egg
eggTopRadius slider 0.1 0.01..0.5 Width at the top of the egg (smaller = pointier)
eggBulge slider 0.75 0.1..2 Controls the curve smoothness
moonDistance slider 0.2 0..2 Distance between the two circles
moonOuterRadius slider 0.45 0.1..1.5 Radius of the outer circle
moonInnerRadius slider 0.32 0.1..1.5 Radius of the inner (cut-out) circle
vesicaWidth slider 0.5 0.1..2 Width of the vesica
vesicaHeight slider 0.8 0.1..2 Height of the vesica
fillColor color "#ffffff" Color inside the shape
edgeColor color "#ff6b6b" Color at the shape edge
edgeBand slider 0 0..0.1 Width of colored edge band (0 = no edge color)
backgroundColor color "#000000" Color outside the shape
transparentBackground checkbox false Force the background fully transparent (alpha 0) - cut the shape out for compositing.
width stepped auto 1..8192 Output width in pixels (Auto uses document default)
height stepped auto 1..8192 Output height in pixels (Auto uses document default)

pattern(type?, scale?, opts?)#

Generates procedural patterns like checkerboard, stripes, dots, and grid

option type default range / options notes
type select "checkerboard" checkerboard, stripes, dots, grid Pattern type to generate
scale slider 8 1..32 Pattern scale / repeat count
angle slider 0 0..360 Rotation in degrees
thickness slider 0.5 0.01..0.99 Line or dot thickness (0-1)
colorA color "#ffffff" First color
colorB color "#000000" Second color
width stepped auto 1..8192 Output width in pixels (Auto uses document default)
height stepped auto 1..8192 Output height in pixels (Auto uses document default)

scatter(stamp, layout?, count?, opts?) -> { image, id }#

Stamps copies of an input image across the output (random or grid layout), with per-instance random scale / rotation / opacity. Also emits a per-instance ID map for downstream variation.

option type default range / options notes
layout select "random" random, grid Placement strategy. Grid = SD Tile Sampler style; Random = legacy organic scatter.
count slider 20 1..200 Number of stamps (random layout). Grid layout uses Grid X x Grid Y instead.
gridX slider 8 1..64 Grid columns (grid layout).
gridY slider 8 1..64 Grid rows (grid layout).
positionJitter slider 0.5 0..1 Per-cell offset as a fraction of cell size. 0 = aligned grid; 1 = up to ±half-cell.
seed number 42 0..99999 Random seed for reproducibility
scaleMin slider 0.5 0.1..2 Minimum random scale
scaleMax slider 1 0.1..2 Maximum random scale
rotationRange slider 360 0..360 Max random rotation in degrees
opacityMin slider 0.5 0..1 Minimum random opacity
opacityMax slider 1 0..1 Maximum random opacity
bgColor color "#00000000" Background fill color
width stepped auto 1..8192 Output width in pixels (Auto uses document default)
height stepped auto 1..8192 Output height in pixels (Auto uses document default)

magerie.ops#

blend(a, b, mode?, opacity?, opts?)#

Combines two images using various blend modes

option type default range / options notes
mode select "normal" normal, multiply, screen, overlay, softLight, hardLight, add, darken, lighten, colorDodge, colorBurn, linearBurn, vividLight, linearLight, pinLight, difference, exclusion, subtract, hue, saturation, color, luminosity Blend mode
opacity slider 1 0..1 Blend opacity (0 to 1)

mul(a, b, opacity?, opts?)#

Blend a and b with mode "multiply" (fixed: mode="multiply")

option type default range / options notes
opacity slider 1 0..1 Blend opacity (0 to 1)

add(a, b, opacity?, opts?)#

Blend a and b with mode "add" (fixed: mode="add")

option type default range / options notes
opacity slider 1 0..1 Blend opacity (0 to 1)

sub(a, b, opacity?, opts?)#

Blend a and b with mode "subtract" (fixed: mode="subtract")

option type default range / options notes
opacity slider 1 0..1 Blend opacity (0 to 1)

screen(a, b, opacity?, opts?)#

Blend a and b with mode "screen" (fixed: mode="screen")

option type default range / options notes
opacity slider 1 0..1 Blend opacity (0 to 1)

overlay(a, b, opacity?, opts?)#

Blend a and b with mode "overlay" (fixed: mode="overlay")

option type default range / options notes
opacity slider 1 0..1 Blend opacity (0 to 1)

darken(a, b, opacity?, opts?)#

Blend a and b with mode "darken" (fixed: mode="darken")

option type default range / options notes
opacity slider 1 0..1 Blend opacity (0 to 1)

lighten(a, b, opacity?, opts?)#

Blend a and b with mode "lighten" (fixed: mode="lighten")

option type default range / options notes
opacity slider 1 0..1 Blend opacity (0 to 1)

difference(a, b, opacity?, opts?)#

Blend a and b with mode "difference" (fixed: mode="difference")

option type default range / options notes
opacity slider 1 0..1 Blend opacity (0 to 1)

blur(img, radius?, opts?)#

Applies Gaussian blur to soften an image

option type default range / options notes
radius slider 5 0..100 (unbounded above) Blur radius in pixels
quality select "medium" low, medium, high No longer used: the blur kernel is separable and always runs at full quality

levels(img, gamma?, opts?)#

Adjusts input/output black and white points with gamma correction

option type default range / options notes
inputBlack slider 0 0..1 Input black point (0-1)
inputWhite slider 1 0..1 Input white point (0-1)
gamma slider 1 0.1..10 Gamma correction (0.1-10)
outputBlack slider 0 0..1 Output black point (0-1)
outputWhite slider 1 0..1 Output white point (0-1)

colorAdjust(img, opts?)#

Adjusts brightness and contrast (legacy hue/saturation in the collapsed group; prefer HSL Adjust for those)

option type default range / options notes
brightness slider 0 -1..1 Brightness adjustment (-1 to 1)
contrast slider 1 0..2 Contrast multiplier (0 to 2)
saturation slider 1 0..2 Saturation multiplier (0 to 2). Prefer HSL Adjust for hue/saturation work.
hue slider 0 -180..180 Hue rotation in degrees (-180 to 180). Prefer HSL Adjust for hue/saturation work.

sharpen(img, amount?, opts?)#

Enhances edge detail using unsharp mask

option type default range / options notes
amount slider 0.5 0..2 Sharpening strength (0 to 2)
radius slider 1 0.1..16 Sharpening radius in pixels - the width of the detail band it enhances

transform(img, opts?)#

Applies geometric transformations to an image

option type default range / options notes
translateX number 0 Horizontal offset in pixels
translateY number 0 Vertical offset in pixels
scale slider 1 0.1..4 Scale factor (1.0 = 100%)
rotation slider 0 -180..180 Rotation angle in degrees
flipX checkbox false Flip horizontally
flipY checkbox false Flip vertically

invert(img, channels?, opts?)#

Inverts image colors to create a negative

option type default range / options notes
channels select "rgb" rgb, r, g, b Which color channels to invert

threshold(img, threshold?, opts?)#

Converts image to black and white based on brightness threshold

option type default range / options notes
threshold slider 0.5 0..1 Brightness cutoff (0-1)
smooth checkbox false Enable anti-aliased transition
smoothness slider 0.02 0..0.2 Width of smooth transition zone

gradientMap(img, opts?)#

Remaps image luminance to a user-defined color gradient

option type default range / options notes
colors gradient stops
alphaFromInput select "off" off, luma, alpha Take the output alpha from the input so the ramp foot outside a shape goes transparent instead of flooding the canvas. Off = opaque (default).

hslAdjust(img, hue?, opts?)#

Adjusts hue, saturation, and lightness with optional per-hue targeting

option type default range / options notes
hue slider 0 -180..180 Hue rotation in degrees (-180 to 180)
saturation slider 0 -1..1 Saturation adjustment (-1 to 1, negative desaturates)
lightness slider 0 -1..1 Lightness adjustment (-1 to 1)
targetHue slider 0 0..360 Center of targeted hue range (0-360 degrees)
targetRange slider 180 0..180 Width of hue range (0-180, 180 = affect all hues)
targetFalloff slider 0.5 0..1 Edge softness of hue range (0-1)

tile(img, repeatX?, opts?)#

Tiles/repeats an image across the output

option type default range / options notes
repeatX slider 2 1..16 Horizontal tile count
repeatY slider 2 1..16 Vertical tile count
offsetX slider 0 0..1 Horizontal offset (fraction of tile width)
offsetY slider 0 0..1 Vertical offset (fraction of tile height)
mirror checkbox false Mirror alternate tiles for seamless patterns

crop(img, opts?)#

Crops image to a rectangular sub-region

option type default range / options notes
left slider 0 0..1 Left edge position (0-1)
top slider 0 0..1 Top edge position (0-1)
right slider 1 0..1 Right edge position (0-1)
bottom slider 1 0..1 Bottom edge position (0-1)

warp(src, displacement, strength?, opts?)#

Displaces pixels using a displacement map

option type default range / options notes
strength slider 10 0..100 (unbounded above) Displacement strength in pixels

mask(img, mask, opts?)#

Uses a grayscale mask to modulate the alpha channel

option type default range / options notes
invert checkbox false Invert the mask (white becomes transparent)

channelSplit(img) -> { r, g, b, a }#

Splits an image into its R, G, B, A channels as separate grayscale images

colorSpaceDecompose(img, colorSpace?, opts?) -> { c1, c2, c3, a }#

Splits an image into channels of HSL, HSV, LAB, or OKLCH color spaces

option type default range / options notes
colorSpace select "hsl" hsl, hsv, lab, oklch Color space to decompose into

magerie.anim#

Pure motion helpers for scripted animation. Every function is a pure function of the stepped clock, so an Image to Video bake reproduces Play exactly (no Math.random / Date.now). Read the clock from a draw recipe's time argument.

ease.<curve>(t)#

Easing curves, each mapping a clamped 0..1 progress to an eased value: linear, inQuad, outQuad, inOutQuad, inCubic, outCubic, inOutCubic, outBack, outElastic (the last two overshoot within a bounded range).

const p = magerie.anim.ease.outCubic(time / 0.5)   // ease in over the first 0.5s

envelope(t, { fadeIn?, fadeOut?, duration }) -> 0..1#

An opacity ramp: fades up from 0 over fadeIn seconds, holds at 1, then fades back to 0 over the last fadeOut seconds ending at duration. fadeIn and fadeOut default to 0 (no ramp on that side).

shake(t, { freq?, amp?, seed? }) -> { x, y }#

Deterministic 2D jitter: per axis, the mean of three seeded, incommensurate sinusoids. Bounded by amp (default 1); freq sets the rate (default 15); distinct seeds stay out of phase so parallel shakes do not sync.

typewriter(text, t, { cps?, delay? }) -> string#

The leading substring of text visible at time t, revealing cps characters per second (default 20) after delay seconds (default 0).

spring(t, { frequency?, damping? }) -> number#

Analytic damped-spring step response: 0 at t <= 0, settling at 1. damping (default 0.55) below 1 overshoots and rings (bouncy entrances); 1 or above is critically damped (no overshoot). frequency (default 3) sets the oscillation rate in Hz. Closed-form, so it is a pure function of t.

const p = magerie.anim.spring(time - 0.2, { frequency: 2.2, damping: 0.5 })
ctx.fillRect(40, 240, 420 * Math.max(0, p), 90)   // panel boings open at t=0.2

stagger(t, index, { each?, duration?, delay?, ease? }) -> 0..1#

Eased progress of item index in a staggered sequence: item i starts at delay + i * each (each default 0.06) and animates over duration (default 0.35) with ease (a curve name like "outBack", default "outCubic", or a custom (t) => number). THE primitive for per-char / per-word / per-line reveals - pair it with magerie.text.layout slot indices.

cycle(t, { period, mode? }) -> 0..1#

Normalized phase of a repeating cycle: "loop" (sawtooth, default), "pingpong" (triangle 0->1->0), "sine" (smooth 0->1->0). For pulsing underlines, looping accents, breathing panels.

cueAt(t, cues) -> { index, progress }#

The active cue at time t from an array of { start, end, ... } spans: index into the array (-1 when no cue covers t - gaps count) and progress 0..1 inside the cue. The karaoke primitive: highlight word cues[index] while drawing all words.

spreadCues(text, { start?, duration, by? }) -> [{ start, end, text }]#

Split text into word (default) or char cues spread across duration seconds from start, each unit's share proportional to its character count (longer words hold longer). Word indices line up with magerie.text.layout(..., { by: "word" }) slot indices, so cueAt(...).index maps straight onto layout slots. For real speech timing, pass hand-timed cues to cueAt instead.

magerie.text#

Measurement/layout helpers for text effects. Positions are computed with the ctx's CURRENT font - set ctx.font before calling. Per-unit widths ignore kerning between neighbours (each unit measured alone); use letterSpacing to tune rhythm.

layout(ctx, text, { x, y, by?, align?, letterSpacing?, wordSpacing?, maxWidth?, lineHeight? }) -> slots#

Measures and places each char (by: "char", default) or word (by: "word") of text, returning { text, x, y, width, index, line } slots. Explicit \n breaks lines and maxWidth word-wraps (an over-wide single word keeps its own line; wrapping collapses runs of spaces). x,y anchor the FIRST line's baseline per align ("left" default, "center", "right", applied per line); further lines step by lineHeight (default 1.25x the px size parsed from ctx.font). Whitespace advances the cursor but produces no slot, so index is contiguous across the whole block and feeds anim.stagger / anim.cueAt directly; use line to stagger line-by-line (anim.stagger(t, slot.line, { each: 0.25 })). Draw a slot with ctx.fillText(slot.text, slot.x + dx, slot.y + dy).

ctx.font = "bold 56px sans-serif"
const slots = magerie.text.layout(ctx, "HELLO WORLD", { x: out.width / 2, y: 200, align: "center" })
for (const s of slots) {
    const p = magerie.anim.stagger(time, s.index, { each: 0.05, duration: 0.4, ease: "outBack" })
    ctx.globalAlpha = p
    ctx.fillText(s.text, s.x, s.y + 24 * (1 - p))   // rise-in, char by char
}
ctx.globalAlpha = 1

Next#

  • Code Nodes: the JavaScript node's execution model, directives, and draw recipes