← City3D assetfogon/wooden-crate
Cajón de madera
Drag to turn it// «Cajón de madera» · propio
// A big wooden shipping crate: plank faces, a frame around every face and a diagonal brace, dark nails at the corners.
// A big wooden shipping crate on three skids: boards set back behind a frame, a brace across every face, nails.
const WOOD = {
plank: ["#b9803f", "#c68d49", "#d29a55"], groove: "#8a5a28", frame: "#9c6730", frameLight: "#b98040", frameDark: "#744a20",
brace: "#a87035", nail: "#2e2a26", inner: "#6b4520",
};
// What is at a point of a crate S × D × H (null: nothing). F: how wide the frame is. P: how wide a board is.
function crateAt(lx, ly, lz, S, D, H, F, P, T) {
if (lx < 0 || ly < 0 || lz < 0 || lx >= S || ly >= D || lz >= H) return null;
const d = [lx, S - 1 - lx, ly, D - 1 - ly, lz, H - 1 - lz];
let face = 0;
for (let i = 1; i < 6; i++) if (d[i] < d[face]) face = i;
const depth = d[face];
if (depth > 2) return null; // hollow
const [a, b, A, B] = face < 2 ? [ly, lz, D, H] : face < 4 ? [lx, lz, S, H] : [lx, ly, S, D];
const top = face === 5;
if (a < F || a >= A - F || b < F || b >= B - F) {
if (depth > 0) return T.frameDark;
if ((a === 1 || a === A - 2) && (b === 1 || b === B - 2)) return T.nail;
return top ? T.frameLight : a === 0 || a === A - 1 || b === 0 ? T.frameDark : T.frame;
}
if (depth === 0) {
// The brace, corner to corner.
const across = Math.abs(((a - F) * (B - 2 * F - 1)) / (A - 2 * F - 1) - (b - F));
return face !== 4 && across <= 1.3 ? (top ? T.frameLight : T.brace) : null;
}
if (depth === 1) return a % P === 0 ? T.groove : T.plank[(Math.floor(a / P) * 7 + face * 3) % 3];
return T.inner;
}
const S = 36, H = 32, X0 = 6, Y0 = 6, Z0 = 3;
for (let x = X0; x < X0 + S; x++)
for (let y = Y0; y < Y0 + S; y++)
for (let z = Z0; z < Z0 + H; z++) {
const c = crateAt(x - X0, y - Y0, z - Z0, S, S, H, 4, 5, WOOD);
if (c) set(x, y, z, c);
}
// The skids a forklift slides its forks between.
for (const [x0, x1] of [[8, 13], [21, 26], [34, 39]])
for (let x = x0; x <= x1; x++)
for (let y = Y0; y < Y0 + S; y++)
for (let z = 0; z < Z0; z++) set(x, y, z, z === 0 || y === Y0 ? WOOD.frameDark : rand() < 0.2 ? WOOD.groove : WOOD.inner);
// Two steel bands around it.
for (const y of [Y0 + 10, Y0 + 25])
for (let k = 0; k < S; k++) {
set(X0 + k, y, Z0 + H - 1, "#6f7379");
for (const x of [X0, X0 + S - 1]) set(x, y, Z0 + k < Z0 + H ? Z0 + k : Z0, "#5d6166");
}import { draw } from "./assets/voxel";
import { woodenCrate } from "./assets/wooden-crate";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, woodenCrate, 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 wooden-crate
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["wooden-crate"] })
# It lands in client/assets/wooden-crate.ts
# https://fogon.gg/object/wooden-crate