Skip to content

Language and CLI reference

A concise reference for the common Anim syntax, scene constructors, collection functions, CLI subcommands, and diagnostic codes used throughout these docs.


1. Lexicon, Literals & Dimensional Units

1.1 Identifiers & Comments

  • Identifiers: Match [a-zA-Z_][a-zA-Z0-9_]*.
  • Line Comments: // comment until end of line
  • Block Comments: /* multi-line block comment */
  • Reserved words: export, let, param, fn, if, else, true, false, and every builtin that uses keyword syntax (composition, rect, step, stack, translate, clip, tween, opacity, repeat, cubic_bezier, mask, sequence, ellipse, scale, rounded_rect, rotate, triangle, map, range, flat_map, filter, fold, scan, zip, enumerate, reverse, sort_by). A reserved word cannot be a binding name or a record field name.

1.2 Dimensional Unit Literals

Anim requires explicit dimensional units for physical domain types:

UnitCategoryDescriptionExample
pxLength / SubpixelScreen space coordinates and dimensions1920px, -45.5px
sTimeTimeline seconds (rational fraction)2s, 0.5s
msTimeTimeline milliseconds500ms, 16.66ms
fpsFrame RatePresentation frequency60fps, 120fps
degAngleRotation angles in degrees90deg, -180deg
unitlessScalar / RatioPure numbers, opacity, scale factors1.0, 0.5, 42

1.3 Text Literals

Double-quoted text names host-supplied assets. \" and \\ are the only escapes, and a literal may not span lines. Text has no arithmetic or concatenation; it exists to address declared inputs.

  • "ball.png", "sprites/frame.png"

1.4 Hexadecimal Color Literals

Source colors use straight 8-bit sRGB channels. The CPU renderer converts them to its linear-light premultiplied working representation during compositing.

  • #RRGGBB (e.g. #1e293b, with implicit full opacity)
  • #RRGGBBAA (e.g. #1e293b80)

2. Expressions & Primitive Constructs

2.1 Bindings & Functions

anim
// Variable binding
let width = 800px;

// Named pure function
let add(a, b) = a + b;

// Anonymous callable
let double = fn(x) => x * 2;

// Block body: name intermediate values before the result expression.
// `{` opens a block only when it is followed by `let`; every other `{` is a
// record literal. Locals bind values, evaluate in order, and may shadow
// outward. See docs/specs/0047-local-binding-blocks.md.
let badge(size) = {
  let half = size / 2;
  let inset = half / 2;
  rect(x: inset, y: inset, width: half, height: half, fill: #ffffff)
};

// Public parameter: a constant a host may replace at compile time
param accent = #f472b6;
param scale_factor = { default: 1.0, min: 0.5, max: 2.0, increment: 0.05,
                       label: "Scale" };

// Exported composition entrypoint
export let main = composition( ... );

2.1.1 Public Parameters

A param declares a constant the host may replace, so one source can drive a slider or a colour picker without being edited. See docs/specs/0051-host-overridable-parameters.md.

  • The right-hand side is a literal, a negated literal, or a record of literals holding default and optionally min, max, increment, and label. It may not reference another binding, which is what lets a host list the parameters without evaluating anything.
  • Types are Scalar, Length, Angle, Duration, Boolean, and Color, inferred from default. min, max, and increment must share that type and are not accepted on Boolean or Color. Text and FrameRate are not overridable.
  • Parameters share the top-level namespace with let and may be referenced in any order. A parameter cannot be exported.
  • A supplied value outside the declared range is rejected, never clamped.
  • A Length or Duration parameter may feed composition, so an override can change the header a host must then re-read.

2.2 Control Flow & Records

anim
// Branching expression
let bg = if is_dark { #000000 } else { #ffffff };

// Record literal & field access
let point = {x: 10px, y: 20px};
let px = point.x;

3. Built-in Scene Node Constructors

3.1 rect

Creates an axis-aligned rectangle primitive.

anim
rect(
  x: Length,
  y: Length,
  width: Length,
  height: Length,
  fill: Color
) -> Scene

3.2 ellipse

Creates a filled ellipse bounded by specified coordinates and dimensions.

anim
ellipse(
  x: Length,
  y: Length,
  width: Length,
  height: Length,
  fill: Color
) -> Scene

3.3 rounded_rect

Creates a rectangle with rounded corners (rx, ry corner radii).

anim
rounded_rect(
  x: Length,
  y: Length,
  width: Length,
  height: Length,
  rx: Length,
  ry: Length,
  fill: Color
) -> Scene

3.4 triangle

Creates a filled 2D triangle from three vertices.

anim
triangle(
  x1: Length, y1: Length,
  x2: Length, y2: Length,
  x3: Length, y3: Length,
  fill: Color
) -> Scene

3.5 image

Draws a decoded raster asset into a whole-pixel destination rectangle.

anim
image(
  src: Text,
  x: Length, y: Length,
  width: Length, height: Length,
  fit: Text,        // optional: "fill" (default) | "contain" | "cover"
  smoothing: Text   // optional: "linear" (default) | "nearest"
) -> Scene

src names an asset the host resolved before compiling. The CLI resolves each name relative to the directory holding the .anim file; a name may not be absolute or escape that directory. PNG with straight alpha is the supported input format.

An image composes exactly like the vector primitives: put it in a stack, wrap it in translate, scale, or rotate, and animate those wrappers with any signal. Rotation and general affines resample through an exact inverse map, and destination edges antialias on the same lattice the vector shapes use.

  • fit: "contain" preserves the source aspect ratio inside the box and centres the result.
  • fit: "cover" preserves the aspect ratio, fills the box, and clips the overflow to the requested rectangle.
  • smoothing: "nearest" keeps hard texel edges for pixel art.
anim
let sprite = translate(x: 160px, y: 48px,
  scene: rotate(angle: swing,
    scene: image(src: "ball.png", x: -22px, y: 0px, width: 44px, height: 44px)));

3.6 stack

Composites a list of child scenes in painter's order (first index at back, last index on top).

anim
stack(children: List<Scene>) -> Scene

3.7 translate

Applies continuous subpixel 2D offset to a target scene.

anim
translate(x: Length | Signal<Length>, y: Length | Signal<Length>, scene: Scene | Signal<Scene>) -> Scene | Signal<Scene>

scene may itself be Signal<Scene>. If any accepted input is a signal, the result is Signal<Scene>.

3.8 scale

Applies axis-aligned scaling around local origin (0, 0).

anim
scale(x: Scalar | Signal<Scalar>, y: Scalar | Signal<Scalar>, scene: Scene | Signal<Scene>) -> Scene | Signal<Scene>

3.9 rotate

Applies clockwise rotation around local origin (0, 0).

anim
rotate(angle: Angle | Signal<Angle>, scene: Scene | Signal<Scene>) -> Scene | Signal<Scene>

3.10 opacity

Applies uniform alpha multiplier (0.0 to 1.0) to a target scene hierarchy.

anim
opacity(value: Scalar | Signal<Scalar>, scene: Scene | Signal<Scene>) -> Scene | Signal<Scene>

3.11 clip

Clips a scene subtree to an axis-aligned rectangular boundary.

anim
clip(x: Length, y: Length, width: Length, height: Length, scene: Scene | Signal<Scene>) -> Scene | Signal<Scene>

3.12 mask

Masks content using the retained alpha coverage of another scene.

anim
mask(alpha: Scene | Signal<Scene>, content: Scene | Signal<Scene>) -> Scene | Signal<Scene>

4. Signal & Timeline Constructors

4.1 step

Creates a discrete signal that switches value at exact time at. Both branches observe composition time; only the selection changes. T is Scene, Length, Scalar, or Angle, and constants are lifted, so step is also the shortest way to promote a static value into a signal.

anim
step(before: T | Signal<T>, after: T | Signal<T>, at: Time) -> Signal<T>

4.2 tween

Creates a continuous interpolation signal between from and to over time interval [start, end].

anim
tween(
  from: Length | Scalar | Angle,
  to: Length | Scalar | Angle,
  start: Time,
  end: Time,
  easing: Easing (optional)
) -> Signal<Length | Scalar | Angle>

Both endpoints must have the same type. The signal clamps to from before start and to to after end, so a stage that outlives its tween rests on the endpoint — that is how a hold is written.

4.3 keyframes

Builds a scalar, length, angle, point, or compatible path signal from strictly increasing exact times. Values hold before the first frame and after the last.

anim
let ease = cubic_bezier(x1: 0.2, y1: 0.8, x2: 0.3, y2: 1);
let turn = keyframes(frames: [
  {time: 0s, value: -20deg, easing: ease, hold: false},
  {time: 1s, value: 20deg, easing: ease, hold: false}
]);

4.4 sequence

Concatenates two signals sequentially at exact timestamp at.

anim
sequence(first: Signal<T>, second: Signal<T>, at: Time) -> Signal<T>

T is Length, Scalar, Angle, or Scene. The second branch restarts local time at zero, which is the only difference from step. Constants are not lifted. Longer timelines nest to the right.

4.5 repeat

Repeats a finite time signal periodically every duration every.

anim
repeat(signal: Signal<T>, every: Duration) -> Signal<T>

T is Length, Scalar, Angle, or Scene. The child observes local time t - floor(t / every) * every.

4.6 cubic_bezier

Defines a cubic Bézier velocity/easing curve with control points ((x_1, y_1)) and ((x_2, y_2)).

anim
cubic_bezier(x1: Scalar, y1: Scalar, x2: Scalar, y2: Scalar) -> Easing

5. Exact Rounding

Quantize an exact constant so it satisfies a whole-pixel geometry field. round is nearest with half ties away from zero, matching the sampled Q16 boundary rule.

anim
round(value: Scalar | Length) -> Scalar | Length
floor(value: Scalar | Length) -> Scalar | Length
ceil(value: Scalar | Length)  -> Scalar | Length
anim
let w = 45px;
rounded_rect(
  x: 0px - round(value: w / 2), y: 0px,
  width: round(value: w), height: ceil(value: w * 0.66),
  rx: round(value: w * 0.1), ry: round(value: w * 0.1),
  fill: #ffffff,
)

These are identifier builtins, so a user binding of the same name shadows them. Signals cannot be rounded. See docs/specs/0049-exact-rounding-builtins.md.


6. Collection Operations API

Function SignatureDescription
range(from: Scalar, to: Scalar) -> List<Scalar>Generates a whole-scalar range [from, to)
map(items: List<T>, transform: fn(T) => U) -> List<U>Maps elements via a transformation
flat_map(items: List<T>, transform: fn(T) => List<U>) -> List<U>Maps and flattens lists
filter(items: List<T>, predicate: fn(T) => Bool) -> List<T>Keeps matching elements
fold(items: List<T>, initial: U, combine: fn(U, T) => U) -> ULeft-fold reduction
scan(items: List<T>, initial: U, combine: fn(U, T) => U) -> List<U>Returns the initial and every accumulated state
zip(left: List<T>, right: List<U>) -> List<{first: T, second: U}>Pairs items through the shorter input
enumerate(items: List<T>) -> List<{index: Scalar, value: T}>Pairs items with zero-based indices
reverse(items: List<T>) -> List<T>Reverses list order
sort_by(items: List<T>, key: fn(T) => Key) -> List<T>Stable-sorts by an exact quantity key

7. CLI Command Specification

anim check <INPUT>

Parses, type-checks, and validates an .anim file without rendering.

  • --set <NAME=VALUE>: Override one declared param; repeatable.
  • Exit Code 0: Valid file.
  • Exit Code 1: Source diagnostics reported to stderr.
  • Exit Code 2: An operational error, such as an unreadable input.

anim inspect <INPUT> [--json]

Prints composition names, dimensions, frame rates, durations, frame counts, and any parameters the source declares with their effective values.

  • --json: Output machine-readable JSON format (schema version 2).
  • --set <NAME=VALUE>: Override one declared param; repeatable.

anim render <INPUT> -o <OUTPUT>

Renders target frames, sequences, or video.

  • --frame <N>: Render exact zero-based frame index (N).
  • --range <A..B>: Render half-open frame range (A \dots B-1).
  • --force: Overwrite existing output files.
  • --video <raster|vector>: Specify video rendering pipeline.
  • --video-codec <CODEC>: Set FFmpeg codec (e.g. libx264, libvpx-vp9).
  • --background <#HEX>: Opaque video background color (default #ffffff).
  • --ffmpeg <PATH>: Explicit path to ffmpeg binary.
  • --set <NAME=VALUE>: Override one declared param; repeatable. The value is written in ordinary literal syntax, such as --set width=180px, --set tilt=-30deg, or --set tint=#09131f80.

anim import-lottie <INPUT.json> -o <OUTPUT.anim> [--force]

Converts a Lottie JSON document to standalone .anim source code.


8. Selected Compiler Diagnostic Codes

CodeCategorySummary Description
A0001LexerUnrecognized source character
A0100SyntaxUnexpected syntax token
A0205CompositionDimension is nonpositive or not a whole pixel
A0206CompositionDuration is nonpositive
A0207CompositionFrame rate is nonpositive
A0400Type CheckingUnresolved identifier
A0402Type CheckingDependency cycle detected
A0403Type CheckingType mismatch in expression
A0405EvaluatorDivision by zero in constant expression
A0504SceneRectangle dimension is nonpositive
A0603SignalNegative switch time in step signal
A1103SignalInvalid tween time interval
A1203SceneOpacity value out of [0.0, 1.0] range
A1703SceneEllipse geometry is not whole pixels
A1903SceneRounded-rectangle geometry is not whole pixels
A2700SyntaxBlock has no result expression
A2701ScopingDuplicate local binding in one block
A2702ScopingLocal binding declares parameters
A2800BuiltinInvalid field on round, floor, or ceil
A3000ParameterDeclaration is not a literal or a record of literals
A3001ParameterSpec field value is not a literal
A3002ParameterRecord spec has no default field
A3003ParameterUnknown spec field
A3005ParameterBound does not have the type of default
A3007Parametermin is greater than max
A3008Parameterdefault is outside the declared range
A3011ParameterDeclaration is exported
A3012ParameterOverride names an undeclared parameter
A3013ParameterOverride does not have the declared type
A3014ParameterOverride is outside the declared range
A3015ParameterDeclared type cannot be supplied by a host

Anim 0.1 preview · Documentation and examples are MIT licensed · Runtime binaries are proprietary