← Level kit3D assetfogon/nivel-caja-rompible
Caja rompible
Drag to turn it// «Caja rompible» · gpt-6-sol (medium)
// A classic breakable wooden crate, a cube 32x32x32 centered (x 8..39, y 8..39, z 0..31). Each face has a 3-block thick darker wooden frame along all edges and a diagonal brace from corner to corner, with lighter horizontal planks in between, visible plank lines, and small dark metal corner caps. Warm orange-brown wood. On the front face, a few small cracks to show it can be broken.
// Solid 32×32×32 crate, with every detail kept inside its exact footprint.
box(8, 8, 0, 39, 39, 31, "#bf7831");
const wood = {
plank: "#d99142",
light: "#e8a554",
shade: "#bd7130",
groove: "#985321",
frame: "#99501f",
frameLight: "#b9692b",
frameDark: "#773c1b",
brace: "#ab5b24",
braceLight: "#cc7b32"
};
function side(face, u, z, depth, color) {
if (face === 0) set(u, 8 + depth, z, color); // front
if (face === 1) set(u, 39 - depth, z, color); // back
if (face === 2) set(8 + depth, u, z, color); // left
if (face === 3) set(39 - depth, u, z, color); // right
}
// Recessed horizontal boards, raised edge frames, and diagonal braces.
for (let face = 0; face < 4; face++) {
for (let z = 0; z < 32; z++) {
for (let u = 8; u <= 39; u++) {
const edge = u < 11 || u > 36 || z < 3 || z > 28;
const diagonal = Math.abs(u - (8 + z));
if (edge) {
let color = wood.frame;
if (u === 8 || u === 39 || z === 0) color = wood.frameDark;
else if (u === 10 || z === 29) color = wood.frameLight;
if (rand() < 0.025) color = wood.frameLight;
side(face, u, z, 0, color);
} else {
// The exposed board lies one block behind the frame.
side(face, u, z, 0, null);
let color = wood.plank;
if ([7, 13, 19, 25].includes(z)) color = wood.groove;
else if ([8, 14, 20, 26].includes(z)) color = wood.light;
else if (rand() < 0.035) color = wood.shade;
side(face, u, z, 1, color);
// A crisp, chunky raised brace with a dark lower edge.
if (diagonal <= 1) {
side(face, u, z, 0,
diagonal === 0 ? wood.braceLight : wood.brace);
} else if (diagonal === 2 && u > 8 + z) {
side(face, u, z, 1, wood.frameDark);
}
}
}
}
}
// Top and underside receive the same framed, diagonal-board construction.
for (const top of [false, true]) {
const outerZ = top ? 31 : 0;
const innerZ = top ? 30 : 1;
for (let y = 8; y <= 39; y++) {
for (let x = 8; x <= 39; x++) {
const edge = x < 11 || x > 36 || y < 11 || y > 36;
const diagonal = Math.abs(x - y);
if (edge) {
let color = top ? wood.frameLight : wood.frameDark;
if (x === 8 || y === 8) color = wood.frameDark;
set(x, y, outerZ, color);
} else {
set(x, y, outerZ, null);
let color = top ? "#e6a04e" : wood.shade;
if ([14, 20, 26, 32].includes(y)) color = wood.groove;
else if ([15, 21, 27, 33].includes(y) && top) color = "#f1b362";
else if (rand() < 0.025) color = wood.shade;
set(x, y, innerZ, color);
if (diagonal <= 1) {
set(x, y, outerZ, diagonal === 0 ? wood.braceLight : wood.brace);
}
}
}
}
}
// Small iron plates wrap all eight corners. Tiny bright rivets keep them legible.
const iron = "#465059";
const ironLight = "#748087";
const rivet = "#ccd2c6";
for (const face of [0, 1, 2, 3]) {
for (const u0 of [8, 36]) {
for (const z0 of [0, 28]) {
for (let du = 0; du < 4; du++) {
for (let dz = 0; dz < 4; dz++) {
const clipped = (du === 3 && dz === 3);
if (!clipped) side(face, u0 + du, z0 + dz, 0,
du === 0 || dz === 0 ? ironLight : iron);
}
}
side(face, u0 + 2, z0 + 2, 0, rivet);
}
}
}
for (const x0 of [8, 36]) {
for (const y0 of [8, 36]) {
for (let dx = 0; dx < 4; dx++) {
for (let dy = 0; dy < 4; dy++) {
if (dx === 3 && dy === 3) continue;
set(x0 + dx, y0 + dy, 31,
dx === 0 || dy === 0 ? ironLight : iron);
}
}
set(x0 + 2, y0 + 2, 31, rivet);
}
}
// Two short, jagged splits in the front boards, clear of the main brace.
const cracks = [
[[33, 23], [33, 22], [32, 21], [33, 20], [34, 19],
[33, 18], [33, 17], [32, 16], [33, 15]],
[[16, 20], [17, 19], [17, 18], [18, 17], [17, 16],
[18, 15], [19, 14]]
];
for (const path of cracks) {
for (const [x, z] of path) {
set(x, 9, z, "#683716");
if (get(x + 1, 9, z) && rand() < 0.65)
set(x + 1, 9, z, "#efad5b");
}
}
set(34, 9, 19, "#683716");
set(35, 9, 18, "#683716");
set(18, 9, 17, "#683716");
set(19, 9, 17, "#683716");import { draw } from "./assets/voxel";
import { nivelCajaRompible } from "./assets/nivel-caja-rompible";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, nivelCajaRompible, 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 nivel-caja-rompible
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["nivel-caja-rompible"] })
# It lands in client/assets/nivel-caja-rompible.ts
# https://fogon.page/object/nivel-caja-rompible