Tessarune
Harvest Festival · chicken_coop.js

Chicken coop

48×48 · 354 lines of JavaScript

This 48×48 floor prop features a wooden hen house with a red roof, a ramp, scattered grain, and a white hen beside a straw nest. In the 16-frame idle loop, the hen pecks the ground twice with a bobbing head and flicking tail. The 16-frame roost loop places her in the doorway as another hen peeks from the window, while the 8-frame egg one-shot reveals an egg in the nest.

Chicken coop — Rendered output6×
Rendered by this program, variant “egg” · 48×48 · 8 frames
Harvest FestivalGet the animated sprites: Harvest Festival on itch.ioVol.6 · 12 harvest-fair props · 37 animations

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

chicken_coop.js · 1–11
// Chicken coop — 48x48 floor prop, top-down 3/4, key light top-left.// A little wooden hen house on four short legs: vertical planks with a lit left side, a barn-red shingled roof with// a wooden ridge cap and barge boards, an arched door with straw spilling over the sill, a square window, and a// cleated plank ramp running down to the ground. In front: a straw nest, scattered grain, and a white hen with a// brown barred wing, dark brown tail, red comb and wattle, yellow beak and legs.// Variants://   idle   16f loop  the hen pecks the ground twice, her head bobs between pecks, her tail flicks//   roost  16f loop  the hen sits in the doorway and breathes, blinks once; a second hen's head peeks out of the//                    window and ducks back//   egg     8f once  the hen fluffs up and rises, an egg is revealed in the straw nest under her, she settles back//                    onto it; the last frame equals idle frame 0

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

chicken_coop.js · 344–354
submit(Coop, {  size: [W, H], origin: "top-left", kind: "icon", scale: 1,  animate: { fps: 10, duration: N_IDLE / 10, loop: true },  anchor: { x: CX, y: GROUND },  args: ["idle"],  variants: [    { name: "idle", args: ["idle"] },    { name: "roost", args: ["roost"], animate: { fps: 10, duration: N_ROOST / 10, loop: true } },    { name: "egg", args: ["egg"], animate: { fps: 10, duration: N_EGG / 10, loop: false } },  ],});
Show the whole program (354 lines)
chicken_coop.js · 354 lines
// Chicken coop — 48x48 floor prop, top-down 3/4, key light top-left.// A little wooden hen house on four short legs: vertical planks with a lit left side, a barn-red shingled roof with// a wooden ridge cap and barge boards, an arched door with straw spilling over the sill, a square window, and a// cleated plank ramp running down to the ground. In front: a straw nest, scattered grain, and a white hen with a// brown barred wing, dark brown tail, red comb and wattle, yellow beak and legs.// Variants://   idle   16f loop  the hen pecks the ground twice, her head bobs between pecks, her tail flicks//   roost  16f loop  the hen sits in the doorway and breathes, blinks once; a second hen's head peeks out of the//                    window and ducks back//   egg     8f once  the hen fluffs up and rises, an egg is revealed in the straw nest under her, she settles back//                    onto it; the last frame equals idle frame 0const W = 48, H = 48, CX = 24, GROUND = 45;const N_IDLE = 16, N_ROOST = 16, N_EGG = 8;const HB = ["n2", "n3", "n4", "n5"];                    // white plumage rampconst BX = 32, BY = 45;                                  // ground hen: feet column / ground row// ---- a tiny layered raster: each layer is emitted as named fields; a layer may carry its own ink ring ----------function Layer(name, clip) {  const px = new Map();  return {    name, px, clip,    set(x, y, k, part) {      if (!k || x < 0 || y < 0 || x >= W || y >= H) return;      if (clip && !clip(x, y)) return;      px.set(y * W + x, [k, part || name]);    },    has(x, y) { return px.has(y * W + x); },  };}function emitParts(g, entries) {  const parts = new Map();  for (const [i, [k, p]] of entries) {    if (!parts.has(p)) parts.set(p, { m: new Map(), x0: W, x1: -1, y0: H, y1: -1 });    const P = parts.get(p), x = i % W, y = (i - x) / W;    P.m.set(i, k); P.x0 = Math.min(P.x0, x); P.x1 = Math.max(P.x1, x); P.y0 = Math.min(P.y0, y); P.y1 = Math.max(P.y1, y);  }  for (const [p, P] of parts) g.part(p, () => g.field({ x: [P.x0, P.x1], y: [P.y0, P.y1] }, (x, y) => P.m.get(y * W + x) ?? null));}// ring: ink on every 4-neighbour of the layer that the layer itself does not cover (separates it from what's behind)function emitLayer(g, L, ring) {  emitParts(g, L.px);  if (!ring) return;  const edge = new Map();  for (const i of L.px.keys()) {    const x = i % W, y = (i - x) / W;    for (const [dx, dy] of [[1, 0], [-1, 0], [0, 1], [0, -1]]) {      const nx = x + dx, ny = y + dy;      if (nx < 0 || ny < 0 || nx >= W || ny >= H || L.has(nx, ny)) continue;      if (L.clip && !L.clip(nx, ny)) continue;      edge.set(ny * W + nx, ["ink", L.name + "Edge"]);    }  }  emitParts(g, edge);}function fillEll(L, cx, cy, rx, ry, fn) {  for (let y = Math.floor(cy - ry - 1); y <= Math.ceil(cy + ry + 1); y++)    for (let x = Math.floor(cx - rx - 1); x <= Math.ceil(cx + rx + 1); x++) {      const nx = (x + 0.5 - cx) / rx, ny = (y + 0.5 - cy) / ry;      if (nx * nx + ny * ny <= 1) L.set(x, y, fn(x, y, nx, ny));    }}function inPoly(pts, x, y) {  let c = false;  for (let i = 0, j = pts.length - 1; i < pts.length; j = i++) {    const [xi, yi] = pts[i], [xj, yj] = pts[j];    if ((yi > y) !== (yj > y) && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) c = !c;  }  return c;}function fillPoly(L, pts, fn) {  const xs = pts.map((p) => p[0]), ys = pts.map((p) => p[1]);  for (let y = Math.floor(Math.min(...ys)); y <= Math.ceil(Math.max(...ys)); y++)    for (let x = Math.floor(Math.min(...xs)); x <= Math.ceil(Math.max(...xs)); x++)      if (inPoly(pts, x + 0.5, y + 0.5)) L.set(x, y, fn(x, y));}function disc(L, cx, cy, r, fn) { fillEll(L, cx, cy, r, r, fn); }// ---- the coop ------------------------------------------------------------------------------------------------const roofL = (y) => Math.round(11 - ((y - 8) * 3) / 10);const roofR = (y) => 48 - roofL(y);const DOOR = { x0: 16, x1: 21, y0: 23, y1: 32 };        // door interiorconst WIN = { x0: 28, x1: 32, y0: 24, y1: 27 };         // window interiorconst inDoor = (x, y) => x >= DOOR.x0 && x <= DOOR.x1 && y >= DOOR.y0 && y <= DOOR.y1 &&  !(y === DOOR.y0 && (x === DOOR.x0 || x === DOOR.x1));const inWin = (x, y) => x >= WIN.x0 && x <= WIN.x1 && y >= WIN.y0 && y <= WIN.y1;function coop(L) {  // weathervane: a little iron rooster on a pole at the ridge  for (let y = 3; y <= 6; y++) L.set(24, y, "n2", "vane");  for (const [x, y, k] of [[22, 1, "n3"], [23, 1, "n2"], [22, 2, "n2"], [23, 2, "n2"], [24, 2, "n1"], [25, 2, "n2"], [26, 1, "n1"],    [23, 3, "n1"], [24, 3, "n1"], [25, 3, "n1"], [21, 2, "g1"], [22, 0, "r1"]]) L.set(x, y, k, "vane");  // legs: back pair (deeper in shadow, shorter), front pair  for (let y = 35; y <= 39; y++) { L.set(17, y, "w0", "legs"); L.set(31, y, "w0", "legs"); }  for (let y = 35; y <= 42; y++) {    L.set(13, y, "w3", "legs"); L.set(14, y, "w2", "legs");    L.set(33, y, "w2", "legs"); L.set(34, y, "w1", "legs");  }  L.set(13, 35, "w1", "legs"); L.set(14, 35, "w0", "legs"); L.set(33, 35, "w0", "legs"); L.set(34, 35, "w0", "legs");  // floor beam under the wall: lit top edge, shaded face, dark underside  for (let x = 11; x <= 37; x++) {    L.set(x, 33, x < 26 ? "w3" : "w2", "sill");    L.set(x, 34, x < 26 ? "w2" : "w1", "sill");  }  L.set(11, 33, "w4", "sill"); L.set(12, 33, "w4", "sill");  for (let x = 15; x <= 31; x++) L.set(x, 35, "w0", "sill");  // front wall: vertical planks  for (let y = 20; y <= 32; y++) for (let x = 12; x <= 36; x++) {    const c = (x - 12) % 3, pl = Math.floor((x - 12) / 3);    let k = pl < 3 ? "w3" : pl < 6 ? "w3" : "w2";    if (pl >= 6 && c === 0) k = "w3";                     // far planks keep a thin lit edge    if (pl < 2 && c === 0) k = "w4";    if (c === 2) k = "w1";                                // seam    const gy = 25 + ((pl * 5) % 6);                       // one grain streak per plank    if (c === 1 && (y === gy || y === gy + 1)) k = pl < 6 ? "w2" : "w1";    if (y === 20) k = "w0";                               // eave shadow    else if (y === 21) k = c === 2 ? "w0" : "w1";    if ((y === 22 || y === 31) && c === 1) k = "n3";      // nail heads    if (x === 36) k = "w1";    L.set(x, y, k, "wall");  }  // door: trim, dark interior, straw on the floor spilling over the sill  for (let y = DOOR.y0 - 1; y <= DOOR.y1; y++) for (let x = DOOR.x0 - 1; x <= DOOR.x1 + 1; x++) {    if (inDoor(x, y)) continue;    const near = inDoor(x + 1, y) || inDoor(x - 1, y) || inDoor(x, y + 1) || inDoor(x + 1, y + 1) || inDoor(x - 1, y + 1);    if (!near) continue;    const left = x <= DOOR.x0 || (y < DOOR.y0 + 1 && x < 19);    L.set(x, y, left ? "w4" : x > DOOR.x1 ? "w1" : "w3", "door");  }  for (let y = DOOR.y0; y <= DOOR.y1; y++) for (let x = DOOR.x0; x <= DOOR.x1; x++) {    if (!inDoor(x, y)) continue;    let k = y < DOOR.y0 + 2 ? "ink" : "n0";    if (x === DOOR.x1 && y > DOOR.y0 + 1) k = "w0";       // the far jamb's inner face catches a little light    if (y === 30) k = x % 3 === 0 ? "g1" : "g0";         // straw bedding: dark at the back, lit strands in front    if (y === 31) k = x % 2 === 0 ? "g1" : "g0";    if (y === 32) k = x === 17 || x === 20 ? "g2" : "g1";    if (y === 29 && x === 18) k = "g0";    L.set(x, y, k, "door");  }  for (const [x, y, k] of [[16, 33, "g2"], [18, 33, "g3"], [19, 33, "g2"], [21, 33, "g2"], [17, 34, "g1"], [20, 34, "g2"]]) L.set(x, y, k, "straw");  // window: lit top/left frame, dark inside, sill board, straw poking over the sill  for (let y = WIN.y0 - 1; y <= WIN.y1 + 1; y++) for (let x = WIN.x0 - 1; x <= WIN.x1 + 1; x++) {    if (inWin(x, y)) L.set(x, y, y === WIN.y0 ? "ink" : "n0", "window");    else L.set(x, y, x === WIN.x0 - 1 || y === WIN.y0 - 1 ? (x < WIN.x1 + 1 ? "w4" : "w3") : "w1", "window");  }  for (let x = WIN.x0 - 2; x <= WIN.x1 + 2; x++) { L.set(x, WIN.y1 + 2, x < WIN.x1 ? "w3" : "w2", "window"); L.set(x, WIN.y1 + 3, "w0", "window"); }  for (const [x, y, k] of [[29, 27, "g0"], [30, 27, "g1"], [32, 27, "g0"]]) L.set(x, y, k, "straw");  // roof: fascia board, front slope of staggered shingles, ridge cap, barge boards  for (let x = roofL(19) + 1; x <= roofR(19) - 1; x++) L.set(x, 19, x < 22 ? "w4" : x < 33 ? "w3" : "w2", "roof");  for (let y = 8; y <= 18; y++) {    const r = Math.floor((y - 8) / 3), line = (y - 8) % 3;    for (let x = roofL(y); x <= roofR(y); x++) {      const u = (x - roofL(y)) / (roofR(y) - roofL(y));      let k = "r1";      if (line === 0) k = "r0";                            // shadow under the row above      else if ((x + r * 2) % 4 === 0) k = line === 1 ? "r0" : "r1";   // gaps between tabs      else if (line === 1 && u < 0.6 && (x + r * 2) % 4 <= 2) k = "r2";   // lit top-left corner of each tab      else if (line === 2 && u > 0.75) k = "r0";      if (y === 18) k = u < 0.5 ? "r2" : u < 0.85 ? "r1" : "r0";       // the eave edge      if (x === roofL(y)) k = "w3";                         // barge boards      if (x === roofR(y)) k = "w1";      L.set(x, y, k, "roof");    }  }  // a weathered tab and a patch of moss  for (const [x, y, k] of [[30, 12, "r0"], [31, 12, "r0"], [15, 15, "e1"], [16, 15, "e2"], [17, 16, "e1"], [35, 9, "e1"]]) L.set(x, y, k, "roof");  for (let x = 11; x <= 37; x++) {    L.set(x, 7, x < 20 ? "w3" : x < 32 ? "w2" : "w1", "ridge");    if (x > 11 && x < 37) L.set(x, 6, x < 20 ? "w4" : x < 32 ? "w3" : "w2", "ridge");  }}function leaves(L) {  // two fallen leaves resting on the roof (static detail that ties the pack's autumn theme together)  for (const [x, y, k] of [[20, 11, "r3"], [21, 11, "r2"], [28, 15, "g2"], [29, 15, "g1"]]) L.set(x, y, k, "leaves");}function ramp(L) {  const P = [[16, 34], [22, 34], [12, 44], [6, 44]];  fillPoly(L, P, (x, y) => {    const t = (y - 34) / 10, l = 16 - t * 10, r = 22 - t * 10;    const u = (x + 0.5 - l) / (r - l);    let k = u < 0.2 ? "w4" : u < 0.7 ? "w3" : "w2";    if (y === 44) k = u < 0.5 ? "w1" : "w0";    return k;  });  // cleats: a raised slat with a lit top and a shadowed foot  for (const cy of [36, 39, 42]) {    const t = (cy - 34) / 10, l = Math.round(16 - t * 10), r = Math.round(21 - t * 10);    for (let x = l; x <= r; x++) { L.set(x, cy, x < l + 2 ? "w4" : "w3", "cleats"); L.set(x, cy + 1, "w1", "cleats"); }  }}function nest(L) {  // a low heap of straw behind the hen  fillEll(L, 34, 41.5, 5.6, 2.2, (x, y, nx, ny) => {    const a = -0.6 * nx - 0.8 * ny;    let k = a > 0.45 ? "g2" : a > -0.35 ? "g1" : "g0";    if ((x * 3 + y * 2) % 7 === 0 && a > -0.2) k = "g2";   // a few strands    return k;  });  for (const [x, y, k] of [[28, 40, "g2"], [40, 40, "g1"]]) L.set(x, y, k, "nest");}function nestLip(L) {  // straw strands in front of the egg's lower half  for (const [x, y, k] of [[33, 41, "g1"], [34, 41, "g2"], [35, 41, "g1"], [36, 41, "g3"], [37, 41, "g1"]]) L.set(x, y, k, "nestLip");}function egg(L) {  L.set(35, 37, "n5", "egg");  for (let y = 38; y <= 40; y++) for (let x = 34; x <= 36; x++) L.set(x, y, x === 34 ? (y === 40 ? "n3" : "n5") : x === 36 ? "n3" : "n4", "egg");  L.set(35, 38, "n5", "egg"); L.set(36, 40, "n2", "egg");}// ---- the hen ---------------------------------------------------------------------------------------------------// pose: { bx, by, peck 0..1, hd (head x nudge), tail 0/1, fluff 0..1, lift px, blink, sit, br (breath 0..1), face -1 }function hen(L, p) {  const cx = p.bx + 1, cy = p.by - (p.sit ? 3.4 : 6) - p.lift - (p.br || 0) * 0.4;  const rx = 5.6 + p.fluff * 1.2, ry = 3.6 + p.fluff * 0.7 + (p.br || 0) * 0.4;  // legs (behind the body)  if (!p.sit) for (const [lx, lit] of [[p.bx - 2, true], [p.bx, false]]) {    for (let y = Math.floor(cy + 1); y < p.by; y++) L.set(lx, y, lit ? "g2" : "g1", "legs");    L.set(lx - 1, p.by - 1, "g1", "legs"); L.set(lx, p.by - 1, lit ? "g2" : "g1", "legs"); L.set(lx + 1, p.by - 1, "g0", "legs");  }  // tail: a dark brown fan raised behind  const tf = p.tail;  fillPoly(L, [[cx + 2, cy - 1], [cx + 3 + tf, cy - 7], [cx + 5 + tf, cy - 8], [cx + 7 + tf, cy - 5], [cx + 7, cy + 1]], (x, y) => {    const along = (x - cx) + (cy - y);    if (along > 11 + tf) return "w0";    if ((x - cx) <= 3 + tf && y < cy - 2) return "w2";      // lit leading edge of the sickle feathers    return (x + y) % 3 === 0 ? "w0" : "w1";  });  // body  const fl = p.fluff;  fillEll(L, cx, cy, rx, ry, (x, y, nx, ny) => {    const i = litIndex(x, y, cx, cy, rx, ry, 4, 0.22);    return HB[Math.max(0, i)];  });  if (fl > 0.5) for (const [dx, dy] of [[-2, -1], [0, -1], [2, -1], [4, 0], [-4, 0]]) {    // ruffled feather tips break the outline    const x = Math.round(cx + dx * rx / 4), y = Math.round(cy - ry + dy + (Math.abs(dx) === 4 ? ry * 0.6 : 0));    L.set(x, y, dx < 0 ? "n5" : "n4", "body");  }  // wing: brown with darker bars, folded over the flank  fillEll(L, cx + 1.2, cy - 0.1, 3.4 + fl * 0.6, 2.1 + fl * 0.3, (x, y, nx, ny) => {    if (ny < -0.45) return nx < 0.2 ? "w4" : "w3";    if ((x + y * 2) % 3 === 0 && ny < 0.6) return "w1";    return ny > 0.55 ? "w1" : "w2";  });  // neck + head  const up = [cx - 4 + (p.hd || 0), cy - 5 + (p.sit ? 0.5 : 0)], down = [cx - 7, p.by - 4];  const k = p.peck;  const hx = Math.round(up[0] + (down[0] - up[0]) * k), hy = Math.round(up[1] + (down[1] - up[1]) * k);  for (let s = 0; s <= 1.0001; s += 0.2) {    const nx0 = cx - 3 + (hx - (cx - 3)) * s, ny0 = cy - 1.5 + (hy - (cy - 1.5)) * s;    disc(L, nx0, ny0, 1.6, (x) => (x < nx0 ? "n5" : "n4"));  }  disc(L, hx + 0.5, hy + 0.5, 2.3, (x, y, nx, ny) => (nx + ny < -0.2 ? "n5" : nx + ny < 0.7 ? "n4" : "n3"));  // comb and wattle  const dn = k > 0.5;  if (!dn) {    for (const [x, y, c] of [[hx - 1, hy - 3, "r2"], [hx, hy - 3, "r1"], [hx + 1, hy - 3, "r1"], [hx - 1, hy - 4, "r2"], [hx + 1, hy - 4, "r1"],      [hx + 2, hy - 2, "r0"], [hx - 3, hy + 1, "r1"], [hx - 3, hy + 2, "r0"]]) L.set(x, y, c, "comb");    L.set(hx - 3, hy, "g2", "beak"); L.set(hx - 4, hy, "g1", "beak");    L.set(hx - 1, hy - 1, p.blink ? "n3" : "ink", "eye");    if (p.blink) L.set(hx - 2, hy - 1, "n3", "eye");  } else {    // head tipped down to the ground: comb faces forward, beak points down    for (const [x, y, c] of [[hx - 2, hy - 2, "r2"], [hx - 3, hy - 1, "r2"], [hx - 1, hy - 3, "r1"], [hx - 3, hy - 2, "r1"], [hx, hy - 3, "r0"]]) L.set(x, y, c, "comb");    L.set(hx - 2, hy + 2, "g2", "beak"); L.set(hx - 2, hy + 3, "g1", "beak");    L.set(hx, hy, "ink", "eye");  }}function henAt(L, extra) {  hen(L, Object.assign({ bx: BX, by: BY, peck: 0, hd: 0, tail: 0, fluff: 0, lift: 0, blink: 0, sit: false }, extra));}// second hen peeking out of the window (head only, facing right, clipped by the window frame)function windowHen(L, rise) {  const hx = 31, hy = 30 - rise;  disc(L, hx + 0.5, hy + 0.5, 2.3, (x, y, nx, ny) => (nx + ny < -0.2 ? "n5" : nx + ny < 0.7 ? "n4" : "n3"));  for (const [x, y, c] of [[hx, hy - 3, "r2"], [hx + 1, hy - 3, "r1"], [hx - 1, hy - 3, "r1"], [hx - 1, hy - 4, "r2"], [hx + 1, hy - 4, "r1"]]) L.set(x, y, c, "comb");  L.set(hx + 3, hy, "g2", "beak");  L.set(hx + 1, hy - 1, "ink", "eye");  L.set(hx + 2, hy + 2, "r1", "comb");}// ---- poses per variant --------------------------------------------------------------------------------------------const PECK = [0, 0, 0.5, 1, 1, 0.5, 0, 0, 0, 0.5, 1, 1, 0.5, 0, 0, 0];const HD = [0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, -1, 0];const TAIL = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0];const Coop = sprite(pal, (g, t, mode) => {  t = ((t % 1) + 1) % 1;  const base = Layer("coop");  coop(base);  contactShadow(g, 24, 42, 15, 2);  contactShadow(g, 9, 44, 4, 1);  if (mode !== "roost") contactShadow(g, 33, 45, 7, 1);  g.outlined("ink", () => emitLayer(g, base, false));  const lv = Layer("leaves"); leaves(lv); emitLayer(g, lv, false);  const rp = Layer("ramp"); ramp(rp); emitLayer(g, rp, true);  g.detached("grain", () => {    for (const [x, y, k] of [[20, 44, "g2"], [23, 46, "g3"], [25, 44, "g2"], [22, 42, "g1"], [18, 46, "g2"], [27, 46, "g2"],      [15, 45, "g3"], [26, 42, "g3"], [12, 46, "g2"], [29, 46, "g1"]]) g.pixel(x, y, k);  });  if (mode !== "roost") { const ns = Layer("nest"); nest(ns); emitLayer(g, ns, true); }  if (mode === "roost") {    const f = Math.round(t * N_ROOST) % N_ROOST;    const wl = Layer("henWindow", inWin);    const rise = [0, 0, 0, 1, 3, 4, 4, 4, 4, 4, 4, 3, 1, 0, 0, 0][f];    if (rise > 0) { windowHen(wl, rise); emitLayer(g, wl, false); }    const hl = Layer("hen");    hen(hl, { bx: 18, by: 33, peck: 0, hd: 0, tail: 0, fluff: 0, lift: 0, sit: true,      br: 0.5 - 0.5 * Math.cos(TAU * t * 2), blink: f === 9 || f === 10 ? 1 : 0 });    emitLayer(g, hl, true);    return;  }  const hl = Layer("hen");  if (mode === "egg") {    const f = Math.min(N_EGG - 1, Math.round(t * N_EGG));    const P = [[0, 0, 0], [0.6, 0, 0], [1, 2, -1], [0.8, 5, -1], [0.5, 5, 0], [0.2, 4, 0], [0, 2, 0], [0, 0, 0]][f];    if (f >= 3 && f <= 6) {      const el = Layer("egg"); egg(el); emitLayer(g, el, true);      const lp = Layer("nestLip"); nestLip(lp); emitLayer(g, lp, false);    }    henAt(hl, { fluff: P[0], lift: P[1], hd: P[2], tail: f >= 2 && f <= 4 ? 1 : 0 });  } else {    const f = Math.round(t * N_IDLE) % N_IDLE;    henAt(hl, { peck: PECK[f], hd: HD[f], tail: TAIL[f] });  }  emitLayer(g, hl, true);});submit(Coop, {  size: [W, H], origin: "top-left", kind: "icon", scale: 1,  animate: { fps: 10, duration: N_IDLE / 10, loop: true },  anchor: { x: CX, y: GROUND },  args: ["idle"],  variants: [    { name: "idle", args: ["idle"] },    { name: "roost", args: ["roost"], animate: { fps: 10, duration: N_ROOST / 10, loop: true } },    { name: "egg", args: ["egg"], animate: { fps: 10, duration: N_EGG / 10, loop: false } },  ],});

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.