Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The language layer

Everything so far has been static text. manic also has a small computation layer that runs before the animation — variables, arithmetic, loops, and macros. It lets one rule draw a hundred shapes.

These are resolved at build time. By the time the animation plays, they’ve expanded into plain calls — so they cost nothing at render.

Variables — let

let r = 120;
let gap = r * 2 + 40;
circle(a, (cx - gap, cy), r);
circle(b, (cx + gap, cy), r);

Arithmetic is what you’d expect: + - * / ^, parentheses, and functions like sin, cos, sqrt. Constants pi, tau, e are built in, as are the canvas vars w, h, cx, cy.

Loops — for

for i in 0..5 {
  dot(p{i}, (200 + i*180, cy), 8);   // p0 … p4
}

p{i} is id interpolation{expr} glued to a name makes each entity unique. Use i in the body to compute positions, sizes, hues…

// one for-loop paints a full rainbow ring.
title("One loop");  canvas("16:9");
text(t, (cx, 90), "one loop, 24 dots, every hue");  color(t, cyan);  size(t, 28);  hidden(t);

let n = 24;
for i in 0..n {
  dot(p{i}, (cx + 300*cos(tau*i/n), cy + 300*sin(tau*i/n)), 14);
  hue(p{i}, 360*i/n);      // colour by angle -> a rainbow
  hidden(p{i});
}

show(t, 0.5);
stagger(0.05) { for i in 0..n { show(p{i}); } }
wait(1.4);

▶ See it play:

Conditionals — if

if depth > 0 {
  line(seg{k}, (x, y), (x2, y2));
}

Macros — def

A def is a reusable rule. Its parameters are numbers; build ids inside with interpolation. It can even call itself (recursion) — that’s how the fractal tree in the gallery is one page of code:

def branch(k, x, y, ang, len, depth) {
  if depth > 0 && len > 2 {
    let x2 = x + len*cos(ang);
    let y2 = y - len*sin(ang);
    line(seg{k}, (x, y), (x2, y2));
    branch(2*k,     x2, y2, ang + 0.4, len*0.72, depth - 1);
    branch(2*k + 1, x2, y2, ang - 0.4, len*0.72, depth - 1);
  }
}
branch(1, cx, h - 40, 1.5708, 150, 12);

Reductions

Fold a range into one number with sum, prod, min, max:

let total = sum(i in 1..n : i);   // 1 + 2 + … + (n-1)

That’s the whole language. The rest is kits — bundles of higher-level figures → Kits.