Tessarune
Dungeon Mechanisms · lever.js

Floor lever

32×32 · 335 lines of JavaScript

A 32×32 floor lever: a stepped stone plinth carrying an iron mounting plate and two cheek plates, a handle of iron, leather and a brass knob pivoting on brass bosses, and a small brass lamp on the plinth’s front-left corner. The four facings are one lever turned on the floor, each lit from the top-left in world space, so right is not a mirrored left. Each facing has “off” (8 frames, a glint over the brass), “pull” (8 frames, once: wind-up, swing, overshoot with sparks, and the lamp lights) and “on” (8 frames, the lamp glows with a warm halo).

Floor lever — Rendered output6×
Rendered by this program, variant “pull-down” · 32×32 · 8 frames
Dungeon MechanismsGet the animated sprites: Dungeon Mechanisms on itch.ioVol.2 · 12 traps, doors and breakables

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

lever.js · 1–10
// Floor lever — 32x32, top-down 3/4, key light top-left.// A stepped stone plinth carries an iron mounting plate with two cheek plates; the handle (iron shaft, leather grip,// brass knob) pivots between them on brass bosses, and a small brass lamp sits on the plinth's front-left corner.// Built like chest.js: every pixel casts the oblique view ray (screen y = BASE - z - K*depth) into a few convex// solids, so the four facings are one lever turned on the floor, each lit top-left in WORLD space (right is not a// mirrored left). The handle is pulled toward its front: "off" leans away from the front, "on" leans toward it.// Variants (f = down / up / left / right)://   off-f   loop, 8f     — a glint runs over the brass and flashes on the knob//   pull-f  one-shot, 8f — wind-up, swing through, overshoot past the stop (sparks), settle; the lamp lights -> == on f0//   on-f    loop, 8f     — the lamp glows and breathes, a warm halo on the plinth

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

lever.js · 326–335
submit(Lever, {  size: [32, 32], origin: "top-left", kind: "icon", scale: 1,  animate: { fps: 10, duration: N / 10, loop: true },  anchor: { x: 16, y: GROUND },  variants: [    ...FACES.map((f) => ({ name: `off-${f}`, args: ["off", f] })),    ...FACES.map((f) => ({ name: `pull-${f}`, args: ["pull", f], animate: { fps: 10, duration: N / 10, loop: false } })),    ...FACES.map((f) => ({ name: `on-${f}`, args: ["on", f] })),  ],});
Show the whole program (335 lines)
lever.js · 335 lines
// Floor lever — 32x32, top-down 3/4, key light top-left.// A stepped stone plinth carries an iron mounting plate with two cheek plates; the handle (iron shaft, leather grip,// brass knob) pivots between them on brass bosses, and a small brass lamp sits on the plinth's front-left corner.// Built like chest.js: every pixel casts the oblique view ray (screen y = BASE - z - K*depth) into a few convex// solids, so the four facings are one lever turned on the floor, each lit top-left in WORLD space (right is not a// mirrored left). The handle is pulled toward its front: "off" leans away from the front, "on" leans toward it.// Variants (f = down / up / left / right)://   off-f   loop, 8f     — a glint runs over the brass and flashes on the knob//   pull-f  one-shot, 8f — wind-up, swing through, overshoot past the stop (sparks), settle; the lamp lights -> == on f0//   on-f    loop, 8f     — the lamp glows and breathes, a warm halo on the plinthconst CX = 16, GROUND = 29, K = 0.5, SZ = 32;const PZ = 7.5, LEN = 9.5;                         // pivot height, shaft length (grip ends at LEN, knob beyond)const OFF = 32, ON = -32;                          // handle angle, degrees (+ = leaning to the back)const N = 8;const LV = norm3([-0.6, -0.25, 0.76]);            // toward the key light (world: X right, Y away, Z up)const STONE = ["n1", "n2", "n3", "n4"], IRON = ["n0", "n1", "n2", "n3"], GOLD = ["g0", "g1", "g2", "g3"], LEATHER = ["w0", "w1", "w2", "w3"];function norm3(v) { const m = Math.hypot(v[0], v[1], v[2]); return [v[0] / m, v[1] / m, v[2] / m]; }// lever-local (x along the pivot axis, y front(-)..back(+), z up) <-> world, per facingconst FACINGS = {  down: { toL: (v) => [v[0], v[1], v[2]], toW: (v) => [v[0], v[1], v[2]], shadow: 10 },  up: { toL: (v) => [-v[0], -v[1], v[2]], toW: (v) => [-v[0], -v[1], v[2]], shadow: 10 },  right: { toL: (v) => [v[1], -v[0], v[2]], toW: (v) => [-v[1], v[0], v[2]], shadow: 8 },  left: { toL: (v) => [-v[1], v[0], v[2]], toW: (v) => [v[1], -v[0], v[2]], shadow: 8 },};// ---- solids: boxes [x0,x1,y0,y1,z0,z1], optionally cut by a quadric {c, inv2}const quad = (c, r) => ({ c, inv2: r.map((v) => (isFinite(v) ? 1 / (v * v) : 0)) });const ANY = [-99, 99, -99, 99, -99, 99];const LO = [-8.5, 8.5, -7.5, 6.5, 0, 2];           // plinth, lower stepconst HI = [-7.5, 7.5, -6.5, 5.5, 2, 5];           // plinth, upper blockconst PLATE = [-4.4, 4.4, -4.2, 4.2, 5, 6];        // iron mounting plate// the pivot axis runs front-to-back (local y): the handle swings sideways, and the front cheek faces the frontconst CHEEK_Q = quad([0, 0, PZ], [3.4, Infinity, 3.4]);const CHEEKS = [[-3.4, 3.4, -3.9, -2.5, 6, 12], [-3.4, 3.4, 2.5, 3.9, 6, 12]];// brass pivot caps: flattened domes bulging out of each cheekconst BOSSES_Q = [quad([0, -3.9, PZ], [1.35, 0.9, 1.35]), quad([0, 3.9, PZ], [1.35, 0.9, 1.35])];const SHAFT = [-1.05, 1.05, -1.05, 1.05, -1, LEN - 4.5], SHAFT_Q = quad([0, 0, 0], [1.05, 1.05, Infinity]);const GRIP = [-1.4, 1.4, -1.4, 1.4, LEN - 4.5, LEN], GRIP_Q = quad([0, 0, 0], [1.4, 1.4, Infinity]);const KNOB_Q = quad([0, 0, LEN + 1.3], [2.05, 2.05, 2.05]);// indicator lamp: a squat brass cup with a glass bead on topconst LAMP_C = [-5.6, -4.9, 5], LAMP_Q = quad(LAMP_C, [1.9, 1.9, 1.3]), LENS_Q = quad([LAMP_C[0], LAMP_C[1], 6.1], [1.15, 1.15, 1.0]);let TIN = 0, TOUT = 0, CIN = -1, COUT = -1;function convex(o, d, b, q) {  let tin = -1e9, tout = 1e9, cin = -1, cout = -1;  for (let i = 0; i < 3; i++) {    const lo = b[2 * i], hi = b[2 * i + 1], di = d[i], oi = o[i];    if (di < 1e-9 && di > -1e-9) { if (oi < lo || oi > hi) return false; continue; }    let t1 = (lo - oi) / di, t2 = (hi - oi) / di, c1 = 2 * i, c2 = 2 * i + 1;    if (t1 > t2) { const k = t1; t1 = t2; t2 = k; c1 = 2 * i + 1; c2 = 2 * i; }    if (t1 > tin) { tin = t1; cin = c1; }    if (t2 < tout) { tout = t2; cout = c2; }    if (tin > tout) return false;  }  if (q) {    const r = q.inv2, c = q.c;    const ox = o[0] - c[0], oy = o[1] - c[1], oz = o[2] - c[2];    const A = d[0] * d[0] * r[0] + d[1] * d[1] * r[1] + d[2] * d[2] * r[2];    const B = 2 * (ox * d[0] * r[0] + oy * d[1] * r[1] + oz * d[2] * r[2]);    const C = ox * ox * r[0] + oy * oy * r[1] + oz * oz * r[2] - 1;    const disc = B * B - 4 * A * C;    if (disc < 0) return false;    const sq = Math.sqrt(disc), r1 = (-B - sq) / (2 * A), r2 = (-B + sq) / (2 * A);    if (r1 > tin) { tin = r1; cin = 6; }    if (r2 < tout) { tout = r2; cout = 6; }    if (tin > tout) return false;  }  TIN = tin; TOUT = tout; CIN = cin; COUT = cout;  return true;}function normalOf(code, p, q) {  if (code < 6) { const n = [0, 0, 0]; n[code >> 1] = code & 1 ? 1 : -1; return n; }  return norm3([(p[0] - q.c[0]) * q.inv2[0], (p[1] - q.c[1]) * q.inv2[1], (p[2] - q.c[2]) * q.inv2[2]]);}// screen offset of the facing: the plinth's nearest bottom edge lands on GROUNDfunction baseOf(F) {  let ext = 0;  for (const x of [LO[0], LO[1]]) for (const y of [LO[2], LO[3]]) ext = Math.max(ext, -F.toW([x, y, 0])[1]);  return GROUND - K * ext;}// ---- one frame: cast every pixel, classify the hitfunction castLever(face, th) {  const F = FACINGS[face], BASE = baseOf(F);  const a = (th * Math.PI) / 180, ca = Math.cos(a), sa = Math.sin(a);  // the handle frame: rotated about the local y axis by th (+ leans toward local +x)  const toH = (v, z0) => [v[0] * ca - (v[2] - z0) * sa, v[1], v[0] * sa + (v[2] - z0) * ca];   // lever-local -> handle  const fromHn = (n) => [n[0] * ca + n[2] * sa, n[1], -n[0] * sa + n[2] * ca];                 // handle normal -> local  const d = F.toL([0, 1, -K]), dh = toH(d, 0);  const buf = new Array(SZ * SZ).fill(null);  for (let py = 0; py < SZ; py++) for (let px = 0; px < SZ; px++) {    const Z0 = BASE - (py + 0.5);    const o = F.toL([px + 0.5 - CX, -40, Z0 + 40 * K]), oh = toH(o, PZ);    let bt = 1e9, bid = null, bh = false, bcode = -1, bq = null;    const hit = (id, h, box, q) => {      if (convex(h ? oh : o, h ? dh : d, box, q) && TIN < bt) { bt = TIN; bid = id; bh = h; bcode = CIN; bq = q; }    };    hit("lo", false, LO, null); hit("hi", false, HI, null); hit("plate", false, PLATE, null);    for (const c of CHEEKS) hit("cheek", false, c, CHEEK_Q);    for (const q of BOSSES_Q) hit("boss", false, ANY, q);    hit("lamp", false, ANY, LAMP_Q); hit("lens", false, ANY, LENS_Q);    hit("shaft", true, SHAFT, SHAFT_Q); hit("grip", true, GRIP, GRIP_Q); hit("knob", true, ANY, KNOB_Q);    if (!bid) continue;    const oo = bh ? oh : o, dd = bh ? dh : d;    const p = [oo[0] + bt * dd[0], oo[1] + bt * dd[1], oo[2] + bt * dd[2]];    const n = normalOf(bcode, p, bq);    const nw = F.toW(bh ? fromHn(n) : n);    const c = classify(bid, p, n);    c.t = bt; c.d = nw[0] * LV[0] + nw[1] * LV[1] + nw[2] * LV[2]; c.top = n[2] > 0.5 && !bh; c.nw = nw;    buf[py * SZ + px] = c;  }  const proj = (q) => { const w = F.toW(q); return [CX + w[0] - 0.5, BASE - w[2] - K * w[1] - 0.5]; };  const projH = (qh, thDeg) => {    const b = (thDeg * Math.PI) / 180;    return proj([qh[0] * Math.cos(b) + qh[2] * Math.sin(b), qh[1], PZ - qh[0] * Math.sin(b) + qh[2] * Math.cos(b)]);  };  return { buf, proj, projH };}function classify(id, p, n) {  const [x, y, z] = p;  if (id === "lo" || id === "hi") {    // a vertical joint on each face of the upper block, one step off centre    const face = n[2] > 0.5 ? "top" : Math.abs(n[1]) > 0.5 ? "fb" : "side";    const joint = id === "hi" && face !== "top" && Math.abs((face === "fb" ? x : y) - 2.2) < 0.45;    // countable marks on the top: a hairline crack by the right rim, a chipped back-left corner    const seg = (ax, ay, bx, by) => { const vx = bx - ax, vy = by - ay, u = Math.max(0, Math.min(1, ((x - ax) * vx + (y - ay) * vy) / (vx * vx + vy * vy))); return Math.hypot(x - ax - u * vx, y - ay - u * vy); };    const crack = id === "hi" && face === "top" && (seg(7.5, -2.5, 5.8, -1.2) < 0.5 || seg(5.8, -1.2, 5.6, 0.8) < 0.5 || Math.hypot(x + 6.6, y - 4.6) < 0.7);    return { part: "plinth", mat: "stone", id, face, joint: joint || crack };  }  if (id === "plate") {    const slot = n[2] > 0.5 && Math.abs(y) < 2.5 && Math.abs(x) < 3.4;    const rivet = n[2] > 0.5 && Math.abs(Math.abs(x) - 3.6) < 0.5 && Math.abs(Math.abs(y) - 3.5) < 0.5;    return { part: "plate", mat: slot ? "slot" : "iron", rivet };  }  if (id === "cheek") return { part: "cheeks", mat: "iron" };  if (id === "boss") return { part: "bosses", mat: "brass", round: true };  if (id === "lens") return { part: "lamp", mat: "lens" };  if (id === "shaft") return { part: "shaft", mat: "iron" };  if (id === "grip") return { part: "grip", mat: "leather", k: Math.floor((z - (LEN - 4.5)) / 1.5), z };  if (id === "knob") return { part: "knob", mat: "brass", round: true };  return { part: "lamp", mat: "brass", round: true };}function level(d) { return d > 0.78 ? 3 : d > 0.45 ? 2 : d > 0.1 ? 1 : 0; }function tone(buf, fx) {  const keys = new Array(SZ * SZ).fill(null);  for (let i = 0; i < SZ * SZ; i++) {    const b = buf[i]; if (!b) continue;    const px = i % SZ, py = (i - px) / SZ;    const up = py > 0 ? buf[i - SZ] : null, dn = py < SZ - 1 ? buf[i + SZ] : null;    const lf = px > 0 ? buf[i - 1] : null, rt = px < SZ - 1 ? buf[i + 1] : null;    const samePart = (q) => q && q.part === b.part;    let key;    if (b.mat === "stone") {      let lv = b.face === "top" ? 2 : level(b.d);      const isStone = (q) => q && q.part === "plinth";      if (b.face === "top") {        if (b.id === "hi" && (!isStone(up) || !isStone(lf))) lv = 3;          // the upper block's back and left rims catch the light        if (b.id === "lo" && !isStone(lf)) lv = 3;        if (b.id === "hi" && !isStone(rt)) lv = 1;                             // right rim turns away        if (lf && !isStone(lf) && lf.t !== undefined && b.id === "hi" && isStone(up)) lv = 1;   // fittings cast a sliver of shadow to the right      } else {        if (up && up.face === "top" && up.id === b.id) lv = Math.min(3, lv + 1);                   // bevel under the lip        if (!dn || !isStone(dn) || (b.id === "hi" && dn.id === "lo")) lv = Math.max(0, lv - 1);   // foot of each block      }      if (b.joint) lv = 0;      if (fx.pool && b.face === "top") lv = Math.min(3, lv + fx.pool(px, py));      key = STONE[lv];    } else if (b.mat === "iron") {      let lv = level(b.d);      if (!samePart(lf)) lv = Math.min(3, lv + 1);      else if (!samePart(rt)) lv = Math.max(0, lv - 1);      if (!samePart(up) && b.part !== "shaft") lv = Math.min(3, lv + 1);      lv = Math.max(0, Math.min(3, lv));      key = b.rivet ? "n4" : lv === 3 && b.d > 0.85 ? "n4" : IRON[lv];    } else if (b.mat === "slot") {      key = up && up.mat === "slot" ? "ink" : "n0";    } else if (b.mat === "leather") {      let lv = b.d > 0.6 ? 3 : b.d > 0.3 ? 2 : b.d > 0.0 ? 1 : 0;      const wrap = (q) => q && q.part === "grip" && q.k !== b.k;      if (wrap(up) || wrap(lf)) lv = Math.max(0, lv - 1);      // the wrap's overlapping edge      key = LEATHER[lv];    } else if (b.mat === "brass") {      let lv;      if (b.round) lv = b.d > 0.82 ? 3 : b.d > 0.5 ? 2 : b.d > 0.15 ? 1 : 0;      else {        const same = (q) => q && q.part === b.part;        lv = b.d > 0.5 ? 2 : 1;        if (!same(up) || !same(lf)) lv = 3; else if (!same(dn) || !same(rt)) lv = 0;      }      if (b.pin) lv = 0;      if (fx.glint) lv = Math.min(3, lv + fx.glint(px, py));      key = GOLD[lv];    } else if (b.mat === "lens") {      // a glass bead: dark ruby when off (one cream catch-light), amber to white-hot when lit      const lit = fx.lamp || 0;           // 0 off, 1 catching, 2 lit, 3 flash      const spec = b.d > 0.9, rim = b.d < 0.35;      if (lit === 0) key = spec ? "n4" : rim ? "r0" : "r1";      else if (lit === 1) key = spec ? "g3" : rim ? "r1" : "r2";      else if (lit === 2) key = spec || !rim ? "g3" : "g2";      else key = rim ? "g3" : "n5";    }    keys[i] = key;  }  return keys;}const PARTS = ["plinth", "plate", "lamp", "cheeks", "bosses", "shaft", "grip", "knob"];function drawLever(g, face, th, fx) {  const fr = castLever(face, th);  if (fx.glow > 0) {    // the lit lamp pools warm light on the stone round it: solid near, dithered at the edge    const [lx, ly] = fr.proj([LAMP_C[0], LAMP_C[1], LAMP_C[2]]);    const r = 2.6 + 1.6 * fx.glow;    fx.pool = (x, y) => {      const q = Math.hypot((x + 0.5 - lx) / 1.3, y + 0.5 - ly);      return q < r ? 1 : 0;    };  }  const keys = tone(fr.buf, fx);  const seen = new Set();  for (const b of fr.buf) if (b) seen.add(b.part);  g.outlined("ink", () => {    for (const part of PARTS) if (seen.has(part)) g.part(part, () => g.field({ x: [0, SZ - 1], y: [0, SZ - 1] }, (x, y) => {      const b = fr.buf[y * SZ + x];      return b && b.part === part ? keys[y * SZ + x] : null;    }));  });  return fr;}// ---- effectsfunction visible(buf, x, y) { return x >= 0 && y >= 0 && x < SZ && y < SZ && !buf[y * SZ + x]; }function star(g, fr, x, y, size, keys) {  const put = (px, py, k) => { if (px >= 0 && py >= 0 && px < SZ && py < SZ) g.pixel(px, py, k); };  put(x, y, keys[0]);  if (size > 0) for (const [dx, dy] of [[1, 0], [-1, 0], [0, 1], [0, -1]]) put(x + dx, y + dy, keys[1]);  if (size > 1) for (const [dx, dy] of [[2, 0], [-2, 0], [0, 2], [0, -2]]) put(x + dx, y + dy, keys[2]);}// swing smear: dithered arc of the knob's path between two angles, only where nothing solid is drawnfunction smear(g, fr, th0, th1) {  g.detached("smear", () => {    const n = Math.ceil(Math.abs(th1 - th0) / 3);    for (let i = 1; i < n; i++) {      const th = th0 + ((th1 - th0) * i) / n;      for (const r of [LEN + 1.3, LEN - 1.5]) {        const [sx, sy] = fr.projH([0, 0, r], th);        const x = Math.round(sx), y = Math.round(sy);        if (visible(fr.buf, x, y) && (chk(x, y) || r > LEN)) g.pixel(x, y, i / n > 0.5 ? "n4" : "n3");      }    }  });}// ---- statesconst PULL = [  // angle, lamp, smear-from  [OFF, 0, null],  [OFF + 7, 0, null],          // wind-up: a hand takes it back a little first  [14, 0, OFF + 7],  [-16, 0, 14],  [-40, 1, -16],               // past the stop: sparks at the slot, the lamp catches  [-26, 3, null],              // rebounds, the lamp flashes  [-34, 2, null],  [ON, 2, null],               // == on, frame 0];const Lever = sprite(pal, (g, t, state, face) => {  contactShadow(g, 16, GROUND, FACINGS[face].shadow, 2);  if (state === "off") {    // a glint band sweeps the brass over the first half, then a star flashes on the knob    const gp = -4 + (t / 0.5) * 44;    const glint = t < 0.5 ? (x, y) => (Math.abs(x + y * 0.8 - gp) < 1.2 ? 1 : 0) : null;    const fr = drawLever(g, face, OFF, { glint, lamp: 0 });    const f = Math.round(t * N);    if (f === 4 || f === 5) {      const [sx, sy] = fr.projH([-0.9, -0.9, LEN + 2.4], OFF);      g.detached("glint", () => star(g, fr, Math.round(sx), Math.round(sy), f === 4 ? 1 : 0, ["n5", "g3", "g2"]));    }    return;  }  if (state === "pull") {    const f = Math.min(N - 1, Math.round(t * N));    const [th, lamp, from] = PULL[f];    const fr = drawLever(g, face, th, { lamp, glow: lamp >= 2 ? (lamp === 3 ? 1 : 0.5) : 0 });    if (from !== null) smear(g, fr, from, th);    if (f === 4) {      // the shaft slams the stop: sparks jump from the slot      const [sx, sy] = fr.proj([-3.2, 0, 6.6]);      g.detached("sparks", () => {        for (const [dx, dy, k] of [[-2, -2, "g3"], [2, -2, "g3"], [-3, 0, "g2"], [3, -1, "g2"], [0, -3, "n5"]]) {          const x = Math.round(sx) + dx, y = Math.round(sy) + dy;          if (visible(fr.buf, x, y)) g.pixel(x, y, k);        }      });    }    if (lamp === 3) {      const [lx, ly] = fr.proj([LAMP_C[0], LAMP_C[1], LAMP_C[2] + 2.6]);      g.detached("flash", () => star(g, fr, Math.round(lx), Math.round(ly) - 1, 1, ["n5", "g3", "g2"]));    }    return;  }  const breath = 0.5 - 0.5 * Math.cos(TAU * t);  const fr = drawLever(g, face, ON, { lamp: 2, glow: 0.5 + 0.5 * breath });  // the bead breathes: a gleam rises off it at the top of each breath  const [lx, ly] = fr.proj([LAMP_C[0], LAMP_C[1], 7.4]);  g.detached("gleam", () => {    const x = Math.round(lx), y = Math.round(ly);    const put = (px, py, k) => { const b = fr.buf[py * SZ + px]; if (!b || b.part === "plinth") g.pixel(px, py, k); };   // never over the handle    if (breath > 0.3) put(x, y - 1, breath > 0.75 ? "g3" : "g2");    if (breath > 0.75) { put(x, y - 3, "g2"); put(x - 2, y - 1, "g1"); put(x + 2, y - 1, "g1"); }  });});const FACES = ["down", "up", "left", "right"];submit(Lever, {  size: [32, 32], origin: "top-left", kind: "icon", scale: 1,  animate: { fps: 10, duration: N / 10, loop: true },  anchor: { x: 16, y: GROUND },  variants: [    ...FACES.map((f) => ({ name: `off-${f}`, args: ["off", f] })),    ...FACES.map((f) => ({ name: `pull-${f}`, args: ["pull", f], animate: { fps: 10, duration: N / 10, loop: false } })),    ...FACES.map((f) => ({ name: `on-${f}`, args: ["on", f] })),  ],});

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.