← Basics3D assetfogon/serrucho
Serrucho
Drag to turn it// «Serrucho» · gpt-6-sol (medium)
// Hand saw («Serrucho»).
// Hand saw: a thin, rising steel blade with a chunky wooden loop handle.
const bladeFront = 20;
const bladeBack = 24;
function topEdge(x) { return Math.round(18 + (x - 4) * 0.5); }
function bottomEdge(x) { return Math.round(8 + (x - 4) * 0.43); }
// Solid blade, with a brighter front face and a dark lower cutting edge.
for (let x = 4; x <= 36; x++) {
const lo = bottomEdge(x), hi = topEdge(x);
for (let z = lo; z <= hi; z++) {
for (let y = bladeFront; y <= bladeBack; y++) {
const t = (z - lo) / (hi - lo);
let c;
if (z === lo) c = "#64787e";
else if (z === hi) c = "#aab8b9";
else if (y === bladeFront) {
c = t > 0.69 ? "#a9b8ba" : t > 0.34 ? "#91a5aa" : "#7e939a";
if (rand() < 0.065) c = t > 0.5 ? "#bdc9c8" : "#71878f";
} else {
c = t > 0.65 ? "#84999d" : "#6e838a";
}
set(x, y, z, c);
}
}
}
// A narrow bevel follows the upper edge; staggered chips texture the steel.
for (let x = 6; x <= 34; x++) {
const hi = topEdge(x), lo = bottomEdge(x);
set(x, 19, hi - 2, x % 5 === 0 ? "#c4cfcc" : "#aabbbd");
if (x % 4 !== 1) set(x, 19, hi - 3, "#a3b5b7");
if (x % 5 < 3) {
const z = lo + 4 + Math.floor((hi - lo - 8) * (x % 3) / 3);
set(x, 19, z, x % 2 ? "#9aadb0" : "#859ba2");
if (x % 3 === 0) set(x + 1, 19, z, "#a3b5b7");
}
}
// Small, regular steel teeth along the sloping upper and lower edges.
for (let x = 8; x <= 32; x += 3) {
const z = topEdge(x);
set(x, 21, z + 1, "#63787f");
set(x + 1, 21, z + 1, "#879b9f");
set(x + 1, 21, z + 2, "#8fa3a6");
set(x + 1, 20, z + 2, "#aab8b8");
}
for (let x = 5; x <= 34; x += 3) {
const z = bottomEdge(x);
set(x, 21, z - 1, "#687d84");
set(x, 21, z - 2, "#748990");
set(x + 1, 21, z - 1, "#82969a");
set(x, 20, z - 1, "#8da0a3");
}
// Squared-off nose and its first prominent tooth.
box(3, 20, 8, 4, 23, 18, "#84979c");
box(3, 19, 9, 3, 19, 18, "#a7b6b7");
box(4, 20, 6, 4, 22, 8, "#75898f");
// The handle is a thick wooden ring; its opening goes all the way through.
function handleShape(x, z) {
const left = x >= 34 && x <= 38 && z >= 28 && z <= 39;
const crown = x >= 36 && x <= 42 && z >= 38 && z <= 40;
const topStep = x >= 37 && x <= 40 && z === 41;
const right = x >= 42 && x <= 44 && z >= 30 && z <= 38;
const heel = x >= 40 && x <= 43 && z >= 27 && z <= 32;
const bottom = x >= 37 && x <= 42 && z >= 25 && z <= 28;
const lowerNeck = x >= 35 && x <= 39 && z >= 27 && z <= 31;
const opening = x >= 39 && x <= 41 && z >= 31 && z <= 36;
return (left || crown || topStep || right || heel || bottom || lowerNeck) && !opening;
}
for (let x = 34; x <= 44; x++) {
for (let z = 25; z <= 41; z++) {
if (!handleShape(x, z)) continue;
for (let y = 17; y <= 27; y++) {
let c;
if (y === 17) c = "#a55c25";
else if (y <= 19) c = "#aa6129";
else if (y >= 26) c = "#713b1e";
else c = "#8b491f";
if (z >= 38) c = y <= 20 ? "#bd762f" : "#945022";
if (z <= 28) c = y <= 20 ? "#8e4b20" : "#693719";
if (x >= 43) c = y <= 19 ? "#985021" : "#71391b";
if (rand() < 0.075) c = y <= 20 ? "#cf8738" : "#6d351b";
set(x, y, z, c);
}
}
}
// Faceted golden edge highlights and dark recess around the finger opening.
for (let x = 36; x <= 41; x++) {
set(x, 16, 40, x % 3 ? "#d59643" : "#e6ab56");
if (x <= 40) set(x, 17, 41, "#a9652c");
}
for (let z = 34; z <= 37; z++) {
set(43, 16, z, z % 2 ? "#b46b2a" : "#cf8637");
}
for (let x = 38; x <= 41; x++) {
set(x, 16, 27, x % 2 ? "#b16b2c" : "#d28c3b");
}
for (let z = 31; z <= 36; z++) {
if (handleShape(38, z)) set(38, 17, z, "#70401e");
if (handleShape(42, z)) set(42, 17, z, "#75401d");
}
for (let x = 39; x <= 41; x++) {
set(x, 17, 37, "#75421e");
set(x, 17, 30, "#63381d");
}
// Gold-toned joints and square rivets securing blade to handle.
box(34, 16, 33, 37, 16, 34, "#75401d");
box(35, 15, 33, 36, 15, 34, "#e6ae55");
set(35, 14, 34, "#f1c477");
set(36, 14, 33, "#bd792c");
box(35, 16, 27, 38, 16, 28, "#75401d");
box(36, 15, 27, 37, 15, 28, "#d49642");
set(36, 14, 28, "#f0ba61");
set(37, 14, 27, "#b97129");
// Broad wooden facets make the grip readable at small sizes.
box(35, 16, 36, 36, 16, 39, "#d08c3b");
set(37, 16, 39, "#f1b861");
box(42, 16, 32, 42, 16, 34, "#c27a30");
set(40, 16, 26, "#dc9946");
// Move the finished saw down so its lowest block rests on the floor at z = 0.
const blocks = [];
forEach((x, y, z, color) => blocks.push([x, y, z, color]));
for (const [x, y, z] of blocks) set(x, y, z, null);
for (const [x, y, z, color] of blocks) set(x, y, z - 6, color);import { draw } from "./assets/voxel";
import { serrucho } from "./assets/serrucho";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, serrucho, x, y, { size: 64, angle: 0, t: performance.now() / 1000 });
// size: its longest side, in px
// angle: turn on the floor, in radians
// t: seconds; if it moves, that animates it# In a terminal, in the game's folder
fogon assets add serrucho
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["serrucho"] })
# It lands in client/assets/serrucho.ts
# https://fogon.page/object/serrucho