Tessarune
Graveyard & Chapel · crypt_door.js

Crypt door

64×64 · 386 lines of JavaScript

A 64×64 floor prop facing the camera: the stone facade of a small mausoleum with a pediment carrying a carved winged skull, two columns on a stepped plinth, a keystone with a violet sigil, and heavy double doors of iron-banded planks with ring pulls. “closed” (12 frames) creeps pale fog along the doorsill while the sigil pulses; “open” (10 frames, once) flares the seal and swings the doors inward with an overshoot as grit falls from the lintel and a soulfire on an altar fades in; “open-idle” (12 frames) keeps the soulfire breathing while fog spills over the steps.

Crypt door — Rendered output6×
Rendered by this program, variant “open” · 64×64 · 10 frames
Graveyard & ChapelGet the animated sprites: Graveyard & Chapel on itch.ioVol.4 · 12 props · 33 animations

The header. The comment at the top of the file is the brief: size, view, light direction and every variant.

crypt_door.js · 1–9
// Crypt door — 64x64 floor prop, top-down 3/4, key light top-left. Camera-facing.// The stone facade of a small mausoleum: a pediment with a carved winged skull under an orb finial, a dentilled// cornice, two columns on a stepped plinth, an ashlar wall with a moulded door surround, and a keystone carrying a// violet sigil. Heavy double doors of iron-banded planks with ring pulls.// Variants://   closed     12f loop  pale fog creeps out along the doorsill, the sigil on the keystone pulses//   open       10f once  the seal flares, the doors jolt and swing inward (overshoot, settle), grit falls from the//                        lintel; the dark tomb and a soulfire on an altar fade in; ends on open-idle frame 0//   open-idle  12f loop  doors open, the soulfire breathes on its altar, fog spills out over the steps

The last lines. submit declares the canvas and lists the variants the renderer exports.

crypt_door.js · 376–386
submit(Crypt, {  size: [W, H], origin: "top-left", kind: "icon", scale: 1,  animate: { fps: 10, duration: N_IDLE / 10, loop: true },  anchor: { x: 32, y: GROUND },  args: ["closed"],  variants: [    { name: "closed", args: ["closed"] },    { name: "open", args: ["open"], animate: { fps: 10, duration: N_OPEN / 10, loop: false } },    { name: "open-idle", args: ["open-idle"] },  ],});
Show the whole program (386 lines)
crypt_door.js · 386 lines
// Crypt door — 64x64 floor prop, top-down 3/4, key light top-left. Camera-facing.// The stone facade of a small mausoleum: a pediment with a carved winged skull under an orb finial, a dentilled// cornice, two columns on a stepped plinth, an ashlar wall with a moulded door surround, and a keystone carrying a// violet sigil. Heavy double doors of iron-banded planks with ring pulls.// Variants://   closed     12f loop  pale fog creeps out along the doorsill, the sigil on the keystone pulses//   open       10f once  the seal flares, the doors jolt and swing inward (overshoot, settle), grit falls from the//                        lintel; the dark tomb and a soulfire on an altar fade in; ends on open-idle frame 0//   open-idle  12f loop  doors open, the soulfire breathes on its altar, fog spills out over the stepsconst W = 64, H = 64, CX = 31.5, GROUND = 61;const DX0 = 22, DX1 = 41, DY0 = 31, DY1 = 53;        // doorway (inclusive)const LEAF = 10, RISE = 4;                           // leaf width, how far a fully turned free edge rises (depth)const SLOPE = 2.1, APEX = 4.5;                       // pediment rakeconst N_IDLE = 12, N_OPEN = 10, REST = 80;const OPEN_TH = [0, 3, 9, 21, 37, 53, 67, 79, 85, REST];const WOOD = ["w0", "w1", "w2", "w3", "w4"], STONE = ["n0", "n1", "n2", "n3", "n4"];const clampI = (i, n) => Math.max(0, Math.min(n - 1, i));function dim(key, k) {  // step a key down its own ramp  if (!k) return key;  const r = key[0] === "w" ? WOOD : key[0] === "n" ? STONE : null;  if (!r) return key;  const i = r.indexOf(key);  return i < 0 ? key : (i - k < 0 ? "ink" : r[i - k]);}const BAYER = [[0, 8, 2, 10], [12, 4, 14, 6], [3, 11, 1, 9], [15, 7, 13, 5]];const thr = (x, y) => (BAYER[y & 3][x & 3] + 0.5) / 16;// ---- facade regions ----------------------------------------------------------------------------------------const pedEdge = (x) => APEX + Math.abs(x + 0.5 - 32) / SLOPE;      // top edge of the raking cornicefunction region(x, y) {  if (y <= 5 && x >= 29 && x <= 34) return "finial";  if (y >= 5 && y <= 16 && y >= pedEdge(x) - 0.2) return "pediment";  if (y >= 17 && y <= 21 && x >= 5 && x <= 58) return y >= 20 && (x < 7 || x > 56) ? null : "entablature";  if (y >= 54 && y <= 57 && x >= 9 && x <= 54) return "steps";  if (y >= 58 && y <= 60 && x >= 5 && x <= 58) return "steps";  const inCol = (a) => (y >= 22 && y <= 24 && x >= a - 2 && x <= a + 6) || (y >= 50 && y <= 53 && x >= a - 2 && x <= a + 6) ||    (y >= 25 && y <= 49 && x >= a && x <= a + 4);  if (inCol(10) || inCol(49)) return "columns";  if (y >= 22 && y <= 53 && x >= 15 && x <= 48) {    if (x >= DX0 && x <= DX1 && y >= DY0) return null;             // doorway: interior / leaves    return "wall";  }  return null;}function finialTone(x, y) {  if (y === 5) return x === 30 || x === 33 ? null : x === 31 ? "n3" : "n2";  const i = litIndex(x, y, 32, 2.7, 2.6, 2.6, 4, 0.1);  if (i < 0) return null;  return x === 31 && y === 1 ? "n5" : STONE[i + 1];}function pedTone(x, y) {  const dv = y + 0.5 - pedEdge(x), left = x < 32;  if (dv < 1.1) return left ? "n4" : "n3";                          // top of the raking cornice  if (dv < 2.4) return left ? "n3" : "n2";                          // its front fascia  if (dv < 3.3) return "n0";                                        // shadow cast into the recessed tympanum  if (y === 16) return "n0";  return (x + y * 3) % 17 === 0 ? "n0" : "n1";                      // tympanum, a few pits}function entTone(x, y) {  if (y === 17) return x < 8 || x > 55 ? "n4" : x < 32 ? "n4" : "n3";  if (y === 18) return x === 5 ? "n4" : x === 58 ? "n2" : "n3";  if (y === 19) return x < 7 || x > 56 ? "n1" : (x & 1) ? "n1" : "n3"; // dentils  if (y === 20) return x === 7 ? "n4" : "n3";  return x === 56 ? "n1" : "n2";}function colTone(x, y) {  const a = x < 32 ? 10 : 49, u = x - a;  if (y <= 24) {                                                    // capital: abacus + echinus    if (y === 22) return u === -2 ? "n4" : u === 6 ? "n2" : "n3";    if (y === 23) return u <= 0 ? "n4" : u <= 3 ? "n3" : "n2";    return u < -1 || u > 5 ? null : u <= 1 ? "n2" : "n1";  }  if (y >= 50) {                                                    // base: torus + plinth    if (y === 50) return u < -1 || u > 5 ? null : u <= 1 ? "n4" : u <= 3 ? "n3" : "n2";    if (y === 51) return u <= -1 ? "n3" : u <= 3 ? "n2" : "n1";    if (y === 52) return u === -2 ? "n4" : u === 6 ? "n1" : "n3";    return u === 6 ? "n0" : "n2";  }  let k = ["n3", "n4", "n3", "n2", "n1"][u];  if (y === 25) k = dim(k, 1);                                      // shadow under the capital  if (u === 2 && (y % 6 === 3)) k = "n2";                           // weathered flute marks  return k;}function wallTone(x, y) {  if (y === 22) return "n0";                                        // deep shadow under the frieze  if (y === 23) return "n1";  if (x === 15 || (x === 16 && y > 24)) return "n1";                // the left column's shadow  // door surround: jambs and lintel with a keystone  if (y >= 25 && y <= 30 && x >= 29 && x <= 34) {    if (y === 25) return x === 29 ? "n4" : x === 34 ? "n2" : "n4";    return x === 29 ? "n4" : x === 34 ? "n1" : "n3";  }  if (y >= 27 && y <= 30 && x >= 19 && x <= 44) {    if (y === 27) return x === 44 ? "n2" : "n4";    if (y === 30) return x >= DX0 && x <= DX1 ? "n1" : "n2";    return x === 19 ? "n4" : x === 44 ? "n1" : "n3";  }  if (y >= 31 && (x === 20 || x === 21 || x === 42 || x === 43)) {    if (x === 20 || x === 42) return "n4";    return "n2";  }  if (y >= 31 && (x === 19 || x === 44)) return x === 19 ? "n2" : "n0";  // surround's shadowed return  // ashlar: 4-row courses, staggered joints  const r = Math.floor((y - 24) / 4), k = (y - 24) % 4;  if (k === 3) return "n1";  const bx = x + (r & 1) * 3;  if (bx % 7 === 0) return "n1";  const dark = hash(Math.floor(bx / 7), r) < 0.3;  if (k === 0) return dark ? "n2" : "n3";  return dark ? "n1" : "n2";}function stepTone(x, y) {  if (y === 54) return x === 9 ? "n3" : (x >= DX0 && x <= DX1) ? "n3" : "n2";   // back of the upper tread, sill  if (y === 55) return x === 54 ? "n3" : "n4";  if (y === 56) return x === 9 ? "n3" : "n2";  if (y === 57) return "n1";  if (y === 58) return x < 9 || x > 54 ? (x === 5 ? "n4" : "n4") : "n3";  if (y === 59) return x === 5 ? "n3" : x === 58 ? "n1" : "n2";  return "n1";}const TONES = { finial: finialTone, pediment: pedTone, entablature: entTone, columns: colTone, wall: wallTone, steps: stepTone };function facade(g) {  for (const name of ["finial", "pediment", "entablature", "wall", "columns", "steps"])    g.part(name, () => g.field({ x: [0, W - 1], y: [0, H - 1] }, (x, y) => (region(x, y) === name ? TONES[name](x, y) : null)));}function carvings(g) {  // winged skull in the tympanum (relief: lit upper-left edges, shadowed lower-right)  g.part("skull", () => {    const S = [      "..####..",      ".######.",      "#XX##XX#",      "#XX##XX#",      ".##NN##.",      "..TTTT..",    ];    S.forEach((row, j) => [...row].forEach((c, i) => {      const x = 28 + i, y = 10 + j;      if (c === ".") return;      let k;      if (c === "X") k = (j === 2 && (i === 1 || i === 5)) ? "n0" : "ink";      else if (c === "N") k = i === 3 ? "n1" : "n0";      else if (c === "T") k = (i & 1) ? "n2" : "n4";      else k = (i <= 2 && j <= 1) || i === 0 ? "n5" : i >= 6 || j >= 4 ? "n3" : "n4";      g.pixel(x, y, k);    }));    for (const [x, y] of [[36, 12], [36, 13], [35, 14], [34, 15], [34, 16], [33, 16], [32, 16], [31, 16], [30, 16]]) g.pixel(x, y, "n0");    const wing = (s) => {      // a swept wing of three feathers: lit top edge, relief face, hard shadow underneath      const sx = (d) => s < 0 ? 27 - d : 36 + d;      const rows = [[12, 0, 3], [13, 0, 6], [14, 0, 8], [15, 1, 7]];      for (const [y, d0, d1] of rows) for (let d = d0; d <= d1; d++) {        let k = "n3";        if (y === 12 || (y === 13 && d >= 4) || (y === 14 && d >= 7)) k = s < 0 ? "n4" : "n3";        if (y === 15) k = d === 3 || d === 6 ? "n0" : "n1";        if (y === 14 && (d === 3 || d === 6) ) k = "n2";        g.pixel(sx(d), y, k);      }      g.pixel(sx(8), 15, "n0");    };    wing(-1); wing(1);  });  g.part("weathering", () => {    // rain streaks from the cornice, a crack, moss at the feet    for (const [x, y0, n] of [[17, 24, 5], [46, 24, 3], [24, 24, 2]]) for (let i = 0; i < n; i++) g.pixel(x, y0 + i, i === n - 1 ? "n2" : "n1");    g.pixel(52, 30, "n1"); g.pixel(51, 31, "n1"); g.pixel(51, 32, "n2"); g.pixel(52, 33, "n1");  // crack in the right shaft    g.pixel(45, 14, "n2");                                             // pits in the tympanum    for (const [x, y, k] of [[8, 53, "e1"], [9, 53, "e2"], [10, 53, "e1"], [8, 52, "e1"], [47, 53, "e1"], [48, 53, "e2"],      [9, 55, "e1"], [10, 54, "e2"], [11, 54, "e1"], [53, 56, "e1"], [54, 56, "e1"], [5, 59, "e1"], [6, 58, "e2"], [7, 58, "e1"],      [57, 59, "e1"], [58, 59, "e1"], [16, 51, "e1"], [16, 52, "e2"], [15, 53, "e1"]]) g.pixel(x, y, k);    g.pixel(40, 59, "n1"); g.pixel(41, 59, "n0"); g.pixel(19, 56, "n1");                          // chips in the steps  });}function sigil(g, pulse) {  // a diamond rune cut into the keystone; the whole face tints violet at the peak  g.part("sigil", () => {    if (pulse > 0.75) for (const [x, y] of [[30, 26], [33, 26], [30, 30], [33, 30], [31, 26], [32, 30]]) g.pixel(x, y, "v0");    const rim = pulse > 0.6 ? "v2" : "v1", core = pulse > 0.75 ? "v3" : pulse > 0.35 ? "v2" : "v1";    g.pixel(31, 27, rim); g.pixel(32, 27, rim);    g.pixel(30, 28, rim); g.pixel(33, 28, rim);    g.pixel(31, 28, core); g.pixel(32, 28, core);    g.pixel(31, 29, rim); g.pixel(32, 29, rim);    if (pulse < 0.3) { g.pixel(31, 27, "v0"); g.pixel(32, 29, "v0"); }  });}// ---- inside ---------------------------------------------------------------------------------------------------function interior(g, glow, ft, R) {  // the tomb: black depth, a floor that catches the soulfire, an altar at the back wall  const fx = 31.5, fy = 37;  g.part("interior", () => g.field({ x: [DX0, DX1], y: [DY0, DY1] }, (x, y) => {    const d = Math.hypot(x + 0.5 - fx, (y + 0.5 - fy) * 1.25);    const r = R * glow;    if (y >= 47) {                                                     // floor      const fd = Math.hypot(x + 0.5 - fx, (y - 47) * 2.2);      if (glow > 0.2 && fd < r * 0.8) return y === 47 ? "b1" : chk(x, y) ? "b0" : "n0";      if (glow > 0.2 && fd < r * 1.2) return chk(x, y) ? "n0" : "ink";      return "ink";    }    if (glow > 0.05 && d < r * 0.45) return "b0";    if (glow > 0.05 && d < r * 0.75) return "v0";    if (glow > 0.05 && d < r * 0.95) return chk(x, y) ? "v0" : "ink";    return "ink";  }));  if (glow > 0.2) g.part("altar", () => {    { const k = glow > 0.6 ? "b1" : "n1"; g.rect({ x: [28, 35], y: [42, 42] }, k, { fill: k }); }    g.rect({ x: [28, 35], y: [43, 46] }, "n0", { fill: "n0" });    g.line([28, 43], [35, 43], "b0");    g.pixel(28, 42, "n2"); g.pixel(35, 42, "n1");      });  if (glow > 0.35) g.detached("soulfire", () => {    const h = Math.round((9 + 1.5 * Math.sin(TAU * ft)) * Math.min(1, glow * 1.2));    flame(g, 32, 41, 6, h, ft, 0.2, ["b1", "b2", "b3", "n5"]);    flame(g, 29, 41, 3, Math.max(2, h - 4), ft, 0.65, ["b1", "b2", "b3", "n5"]);    // a wisp drifting up    const p = ft % 1;    if (p < 0.7) g.pixel(31 + Math.round(Math.sin(TAU * p) * 2), 33 - Math.round(p * 3), p < 0.35 ? "b3" : "b2");  });}function leaves(g, th, lit) {  // two leaves hinged at the jambs, swinging inward; the free edge rises as it recedes  const a = th * Math.PI / 180;  const w = Math.max(1, Math.round(LEAF * Math.cos(a)));  const dy = RISE * Math.sin(a);  const tex = (sx, ly, left) => {    // closed texture at screen column sx, row ly    const lx = left ? sx - DX0 : DX1 - sx;                             // 0 at the hinge    if (ly === DY1) return "w0";    // strap hinges: two rows from the hinge, ending in a spear tip near the meeting stile    for (const by of [35, 47]) {      if (ly === by - 1 && lx === 7) return "n2";      if (ly === by + 2 && lx === 7) return "n0";      if ((ly === by || ly === by + 1) && lx <= 8) {        if (lx === 8) return ly === by ? "n2" : "n0";        const top = ly === by;        if (top && (lx === 1 || lx === 4)) return "n4";        if (!top && (lx === 1 || lx === 4)) return "n0";        return top ? (left ? "n3" : "n2") : "n1";      }    }    if (lx === LEAF - 1) return left ? "w1" : "w0";                    // meeting stiles    // ring pulls on round back-plates    const rx = left ? 29 : 34, ry = 42, ddx = sx - rx, ddy = ly - ry;    if (ddy === -3 && ddx === 0) return "n3";    if (ddy === -2 && Math.abs(ddx) <= 1) return ddx < 0 ? "n3" : ddx === 0 ? "n4" : "n1";    if (ddy >= -1 && ddy <= 2 && Math.abs(ddx) <= 1) {      if (ddx === 0 && (ddy === 0 || ddy === 1)) return "w0";      if (ddx === -1) return ddy === 2 ? "n2" : "n4";      if (ddx === 1) return "n1";      return ddy === -1 ? "n4" : "n1";    }    // planks: 3px each from the left edge of the doorway    const p = (sx - DX0) % 3, pi = Math.floor((sx - DX0) / 3);    let k = p === 0 ? "w1" : p === 1 ? "w3" : "w2";    if (!left && p === 1) k = "w2";                                     // the right leaf sits a touch darker    if (p === 2 && ly % 7 === 3 && hash(pi, ly) < 0.5) k = "w1";          // a few grain marks    if (sx === 31 || sx === 32) k = "w1";    if (ly <= DY0 + 2) k = dim(k, ly === DY0 ? 2 : 1);                   // the lintel's shadow    if (ly >= DY1 - 1) k = dim(k, 1);    return k;  };  const leafDim = (left) => (left ? (th > 55 ? 2 : th > 25 ? 1 : 0) : (th > 45 ? 1 : 0));  g.part("doors", () => g.field({ x: [DX0, DX1], y: [DY0 - 1, DY1] }, (x, y) => {    for (const left of [true, false]) {      const i = left ? x - DX0 : DX1 - x;      if (i < 0 || i >= w) continue;      const sh = w > 1 ? Math.round(dy * i / (w - 1)) : 0;      const ly = y + sh;      if (y < DY0 || ly > DY1 || ly < DY0) continue;      const lx = Math.min(LEAF - 1, Math.floor((i + 0.5) * LEAF / w));      const sx = left ? DX0 + lx : DX1 - lx;      let k = dim(tex(sx, ly, left), leafDim(left));      if (th > 30 && i === w - 1) k = lit > 0.5 && (ly & 1) ? "b1" : "w0";   // free edge, rimmed by the soulfire      if (th > 30 && ly === DY1) k = "ink";      return k;    }    return null;  }));}// ---- fog ----------------------------------------------------------------------------------------------------------function puff(g, cx, cy, rx, ry, dens) {  if (dens <= 0.02) return;  for (let y = Math.floor(cy - ry); y <= Math.ceil(cy + ry); y++) for (let x = Math.floor(cx - rx); x <= Math.ceil(cx + rx); x++) {    const nx = (x + 0.5 - cx) / rx, ny = (y + 0.5 - cy) / ry, r2 = nx * nx + ny * ny;    if (r2 > 1) continue;    const v = dens * (1 - r2);    if (v > 0.5) g.pixel(x, y, "n5");    else if (v > thr(x, y) * 0.55) g.pixel(x, y, "n4");  }}function fogSill(g, t, amt) {  // low wisps squeezing out under the doors and creeping along the sill  if (amt <= 0) return;  g.detached("fog", () => {    for (const s of [-1, 1]) for (let k = 0; k < 3; k++) {      const p = (t + k / 3 + (s > 0 ? 0.17 : 0)) % 1;      const x = CX + s * (3 + p * 16), y = 54 + p * 2.5;      puff(g, x, y, 3.2 + p * 3, 1.5 + p * 0.8, amt * Math.min(1, Math.sin(Math.PI * p) * 1.2));    }    puff(g, CX, 54, 6 + Math.sin(TAU * t), 1.5, amt * (0.75 + 0.15 * Math.cos(TAU * t)));  });}function fogSpill(g, t, amt) {  // open: fog pours over the sill and rolls down the steps, spreading outwards  if (amt <= 0) return;  g.detached("fog", () => {    for (let k = 0; k < 5; k++) {      const p = (t + k / 5) % 1, s = (k & 1) ? 1 : -1;      const x = CX + s * (1 + p * 17) + (k === 2 ? -3 : 0), y = 51.5 + p * 7.5;      puff(g, x, y, 3.5 + p * 4, 1.7 + p * 1, amt * Math.min(1, Math.sin(Math.PI * p) * 1.3));    }    puff(g, CX, 53, 8 + Math.sin(TAU * t) * 0.8, 2, amt * (0.7 + 0.12 * Math.cos(TAU * t)));  });}function grit(g, f) {  if (f < 2 || f > 6) return;  g.detached("grit", () => {    for (const [x, ph] of [[25, 0], [30, 1], [36, 0], [39, 2]]) {      const y = DY0 + (f - 2 - ph) * 4;      if (y >= DY0 && y <= DY1 - 1) { g.pixel(x, y, "n3"); if (y - 1 >= DY0) g.pixel(x, y - 1, "n1"); }    }  });}// ---- states -------------------------------------------------------------------------------------------------------function stateAt(state, t) {  t = ((t % 1) + 1) % 1;  const breathe = (tt) => 0.5 + 0.5 * Math.cos(TAU * tt);  if (state === "closed") {    const f = Math.round(t * N_IDLE) % N_IDLE, tt = f / N_IDLE;    return { th: 0, glow: 0, pulse: breathe(tt), sill: 1, spill: 0, ft: tt, st: tt, R: 8, f: -1 };  }  if (state === "open-idle") {    const f = Math.round(t * N_IDLE) % N_IDLE, tt = f / N_IDLE;    return { th: REST, glow: 1, pulse: breathe(tt), sill: 0, spill: 1, ft: tt, st: tt, R: 8 + 1.2 * Math.cos(TAU * tt), f: -1 };  }  const f = Math.min(N_OPEN - 1, Math.round(t * N_OPEN));  if (f === 0) return stateAt("closed", 0);  if (f === N_OPEN - 1) return stateAt("open-idle", 0);  const tt = (((f - (N_OPEN - 1)) / N_IDLE) % 1 + 1) % 1;              // run the idle clock backwards from the end  const k = Math.min(1, f / 7);  const glow = Math.max(0, Math.min(1, (f - 2) / 6));  return { th: OPEN_TH[f], glow, pulse: 1, sill: 1 - k, spill: k, ft: tt, st: f / N_IDLE, R: 9.2, f, flare: f <= 3 };}const Crypt = sprite(pal, (g, t, state) => {  const S = stateAt(state, t);  contactShadow(g, 32, GROUND, 28, 2);  g.outlined("ink", () => {    facade(g);    interior(g, S.glow, S.ft, S.R);    leaves(g, S.th, S.glow);  });  carvings(g);  sigil(g, S.pulse);  if (S.flare) g.detached("flare", () => {    for (const [x, y] of [[28, 27], [35, 27], [31, 24], [32, 32]]) g.pixel(x, y, S.f === 2 ? "v3" : "v2");  });  if (S.glow > 0.5) g.part("spill", () => {                           // soulfire light on the sill    for (let x = 27; x <= 36; x++) if (chk(x, 54) || Math.abs(x - 31.5) < 2) g.pixel(x, 54, "b1");  });  if (S.f > 0) grit(g, S.f);  fogSill(g, S.st, S.sill);  fogSpill(g, S.ft, S.spill);});submit(Crypt, {  size: [W, H], origin: "top-left", kind: "icon", scale: 1,  animate: { fps: 10, duration: N_IDLE / 10, loop: true },  anchor: { x: 32, y: GROUND },  args: ["closed"],  variants: [    { name: "closed", args: ["closed"] },    { name: "open", args: ["open"], animate: { fps: 10, duration: N_OPEN / 10, loop: false } },    { name: "open-idle", args: ["open-idle"] },  ],});

These excerpts omit the boilerplate prepended by the asset pack build script: a single-line runtime header, the shared palette, and common helper utilities (contactShadow, litIndex, flame, hash, chk, TAU). The displayed line numbers match the original source files. Each program was authored by an AI coding agent and adjusted after visual inspection of the rendered frames.

Have your agent write programs like this.

Tessarune gives it the drawing API reference, 25 production manuals and a renderer to check its work against.