Chicken coop
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.
6×
Get 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 — 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 0The last lines. submit declares the canvas and lists the variants the renderer exports.
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 — 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.