← Basics3D assetfogon/balde
Balde
Drag to turn it// «Balde» · gpt-6-sol (medium)
// Bucket («Balde»).
const cx = 24, cy = 24;
const TAU = Math.PI * 2;
const staves = 28;
function sector(x, y) {
const angle = Math.atan2(y - cy, x - cx);
const position = ((angle + Math.PI) / TAU) * staves;
return { index: Math.floor(position), seam: position % 1 };
}
function radiusAt(z) {
return 11.7 + 2.7 * Math.min(z, 25) / 25;
}
function woodShade(index, seam, z, inside, x, y) {
const grain = (index * 17 + 7) % 7;
if (seam < 0.09 || seam > 0.95) return inside ? "#70411f" : "#71401e";
if (inside) {
if (grain < 2) return "#885026";
if (grain > 5) return "#a46530";
return "#965a29";
}
if (z < 3) return grain < 3 ? "#945522" : "#a8642b";
if (grain === 0) return "#a96730";
if (grain === 1) return "#b97637";
if (grain === 5) return "#c3823d";
if (grain === 6) return "#a76229";
return y < cy ? "#b77434" : "#ae692f";
}
// Solid tapered base and individual-looking wooden staves.
for (let z = 0; z <= 26; z++) {
const outer = radiusAt(z);
const inner = outer - 2.65;
for (let x = 8; x <= 40; x++) {
for (let y = 8; y <= 40; y++) {
const dx = x - cx, dy = y - cy;
const r = Math.sqrt(dx * dx + dy * dy);
if (r > outer) continue;
if (z >= 12 && r < inner) continue;
const s = sector(x, y);
const inside = z >= 12 && r < outer - 1.25;
let color = woodShade(s.index, s.seam, z, inside, x, y);
if (z === 26) {
color = s.seam < 0.09 ? "#a9692c" :
r > outer - 1.3 ? "#e3a44d" : "#cf8c3e";
} else if (z === 25 && r > outer - 1.5) {
color = "#d99a46";
} else if (inside && rand() < 0.045) {
color = "#ad7035";
} else if (!inside && r > outer - 1.35 && z > 5 && z < 20) {
if (rand() < 0.075) color = "#d08c42";
else if (rand() < 0.045) color = "#88501f";
}
set(x, y, z, color);
}
}
}
// Recessed, shadowed wooden floor inside the bucket.
for (let x = 12; x <= 36; x++) {
for (let y = 12; y <= 36; y++) {
if (Math.hypot(x - cx, y - cy) < radiusAt(12) - 2.7) {
let color = ((Math.floor((x + 1) / 3) + 2) % 4 === 0)
? "#79451f" : "#895025";
if (rand() < 0.12) color = "#9b5d2a";
set(x, y, 11, color);
}
}
}
// Fine raised grain on selected outer staves.
for (let z = 7; z <= 19; z++) {
for (let x = 9; x <= 39; x++) {
for (let y = 9; y <= 39; y++) {
const r = Math.hypot(x - cx, y - cy);
const outer = radiusAt(z);
if (r < outer - 0.85 || r > outer) continue;
const s = sector(x, y);
if (s.seam > 0.3 && s.seam < 0.47 &&
(s.index % 4 === 0 || s.index % 7 === 2) &&
(z % 9 !== 0)) {
set(x, y, z, z % 5 === 0 ? "#d18b40" : "#875020");
}
}
}
}
// Two continuous, dark blue-gray iron hoops.
function hoop(z0, z1) {
for (let z = z0; z <= z1; z++) {
const outer = radiusAt(z) + 0.8;
for (let x = 8; x <= 40; x++) {
for (let y = 8; y <= 40; y++) {
const r = Math.hypot(x - cx, y - cy);
if (r < outer - 1.65 || r > outer) continue;
let color;
if (z === z1) color = "#718087";
else if (z === z0) color = "#344953";
else color = y < cy ? "#4c6470" : "#465861";
if (rand() < 0.08) color = z === z1 ? "#87949a" : "#364b56";
set(x, y, z, color);
}
}
}
}
hoop(3, 5);
hoop(20, 22);
// Small iron mounting plates at the sides of the upper hoop.
box(9, 22, 20, 11, 26, 23, "#43545b");
box(37, 22, 20, 39, 26, 23, "#43545b");
box(9, 23, 22, 10, 25, 23, "#79868a");
box(38, 23, 22, 39, 25, 23, "#748188");
set(10, 23, 21, "#9ba4a1");
set(38, 23, 21, "#9ba4a1");
// Faceted iron bail: high arch with a wooden grip across its crown.
const left = [
[10, 24, 23], [10, 24, 28], [12, 25, 32],
[15, 26, 35], [19, 27, 38]
];
const right = [
[38, 24, 23], [38, 24, 28], [36, 25, 32],
[33, 26, 35], [29, 27, 38]
];
for (const side of [left, right]) {
for (let i = 0; i < side.length - 1; i++) {
const a = side[i], b = side[i + 1];
line(...a, ...b, 0, "#354750");
line(a[0], a[1] + 1, a[2], b[0], b[1] + 1, b[2],
0, "#64727a");
}
}
line(19, 27, 38, 29, 27, 38, 0, "#354750");
// Warm carved wooden handle, capped by darker end rings.
box(19, 26, 37, 29, 28, 39, "#b87535");
box(20, 26, 39, 28, 28, 40, "#e5a555");
box(20, 26, 37, 28, 26, 37, "#915321");
box(19, 25, 37, 20, 29, 39, "#805029");
box(28, 25, 37, 29, 29, 39, "#805029");
box(21, 25, 38, 27, 25, 38, "#d99343");import { draw } from "./assets/voxel";
import { balde } from "./assets/balde";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, balde, 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 balde
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["balde"] })
# It lands in client/assets/balde.ts
# https://fogon.page/object/balde