← Basics3D assetfogon/banqueta-de-tres-patas
Banqueta de tres patas
Drag to turn it// «Banqueta de tres patas» · gpt-6-sol (medium)
// Three legged stool («Banqueta de tres patas»).
// Three-legged wooden stool
const woodDark = "#805027";
const woodShadow = "#94602d";
const woodMid = "#ae7337";
const woodLight = "#c58b45";
const woodHighlight = "#d89e53";
const legs = [
{ top: [19, 16], foot: [18, 10] }, // front
{ top: [13, 29], foot: [10, 33] }, // rear left
{ top: [34, 29], foot: [37, 33] } // rear right
];
function legCenter(leg, z) {
const t = Math.min(1, z / 34);
return [
Math.round(leg.foot[0] * (1 - t) + leg.top[0] * t),
Math.round(leg.foot[1] * (1 - t) + leg.top[1] * t)
];
}
// Low, chunky triangular footrest and its darker lower edges.
function beam(a, b, z) {
line(a[0], a[1], z, b[0], b[1], z, 1.25, woodShadow);
line(a[0], a[1] - 1, z + 1, b[0], b[1] - 1, z + 1, 0, woodLight);
line(a[0], a[1], z - 1, b[0], b[1], z - 1, 0, woodDark);
}
beam(legCenter(legs[0], 15), legCenter(legs[1], 15), 15);
beam(legCenter(legs[0], 15), legCenter(legs[2], 15), 15);
beam(legCenter(legs[1], 17), legCenter(legs[2], 17), 17);
// Short structural rails immediately beneath the seat.
beam(legCenter(legs[0], 31), legCenter(legs[1], 31), 31);
beam(legCenter(legs[0], 31), legCenter(legs[2], 31), 31);
beam(legCenter(legs[1], 31), legCenter(legs[2], 31), 31);
// Four-sided legs, subtly splayed outward at their feet.
for (let i = 0; i < legs.length; i++) {
for (let z = 0; z <= 35; z++) {
const [cx, cy] = legCenter(legs[i], z);
const width = z < 5 ? 4 : (z > 27 ? 5 : 4);
const lo = -Math.floor(width / 2);
const hi = lo + width - 1;
for (let dx = lo; dx <= hi; dx++) {
for (let dy = lo; dy <= hi; dy++) {
let color = woodMid;
if (dy === lo) color = woodLight;
if (dx === hi) color = woodShadow;
if (dy === hi) color = woodDark;
if (dx === lo && dy === lo) color = woodHighlight;
if (z % 8 === 2 && dx === lo && dy === lo) color = woodMid;
if (rand() < 0.045) color = dy === lo ? woodHighlight : woodShadow;
set(cx + dx, cy + dy, z, color);
}
}
}
// Squared-off joinery collars at the footrest and seat.
for (const z of [14, 15, 29, 30]) {
const [cx, cy] = legCenter(legs[i], z);
box(cx - 2, cy - 2, z, cx + 2, cy + 2, z, z === 14 || z === 29 ? woodDark : woodLight);
box(cx - 2, cy - 2, z, cx + 1, cy - 2, z, woodHighlight);
}
}
// Thick round seat: dark underside, warm carved rim, pale planked top.
const sx = 24, sy = 24;
const layers = [
{ z: 33, r: 17.2, base: "#865326" },
{ z: 34, r: 18.2, base: "#a66a31" },
{ z: 35, r: 19.0, base: "#9d642e" },
{ z: 36, r: 19.3, base: "#bb7b37" },
{ z: 37, r: 19.0, base: "#d99648" },
{ z: 38, r: 18.3, base: "#f5b761" }
];
for (const layer of layers) {
for (let x = 4; x <= 44; x++) {
for (let y = 4; y <= 44; y++) {
const d = Math.hypot(x - sx, y - sy);
if (d > layer.r) continue;
let color = layer.base;
if (layer.z === 38) {
// Long, slightly diagonal boards, with narrow seams and fine grain.
const plank = x + 0.32 * (y - sy);
const band = Math.floor(plank / 5);
const shades = ["#f9be6b", "#efab56", "#f6b965", "#f2b15b", "#ffca76"];
color = shades[((band % shades.length) + shades.length) % shades.length];
const seam = ((plank % 5) + 5) % 5;
if (seam < 0.48) color = "#d79548";
else if (seam < 1.05) color = "#ffca78";
if (rand() < 0.11) color = rand() < 0.58 ? "#ffd082" : "#e9a454";
if (d > 17.1) color = y < 24 ? "#d89445" : "#e4a451";
} else if (d > layer.r - 1.5) {
color = y < 23 ? "#98602d" : "#b67636";
if (layer.z >= 36) color = y < 23 ? "#bb7c39" : "#ce8a43";
if (rand() < 0.22) color = "#db9850";
} else if (rand() < 0.075) {
color = layer.z < 36 ? "#b77b39" : "#e7a650";
}
set(x, y, layer.z, color);
}
}
}
// Individually visible, blocky end-grain marks around the seat's front lip.
for (let a = 0; a < Math.PI * 2; a += 0.115) {
const x = Math.round(sx + 18.7 * Math.cos(a));
const y = Math.round(sy + 18.7 * Math.sin(a));
set(x, y, 36, rand() < 0.35 ? "#a56830" : "#bb7938");
if (rand() < 0.72) set(x, y, 37, "#d39247");
}import { draw } from "./assets/voxel";
import { banquetaDeTresPatas } from "./assets/banqueta-de-tres-patas";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, banquetaDeTresPatas, 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 banqueta-de-tres-patas
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["banqueta-de-tres-patas"] })
# It lands in client/assets/banqueta-de-tres-patas.ts
# https://fogon.page/object/banqueta-de-tres-patas