← FantasíaObjeto 3Dfogon/calavera
Calavera
Arrastrá para girarlo// «Calavera» · gpt-6-sol (medium)
// A big cartoon human skull sitting on a small stack of two old books: rounded bone-white cranium, large deep dark eye sockets, a triangular nose hole, cheekbones, and a jaw with a clear row of square teeth. Slight cracks and yellow-beige aging on top, a half-melted white candle with a small flame on top of the skull.
// Two old books, with their worn page edges facing forward.
box(5, 12, 0, 42, 39, 0, "#493447");
box(5, 12, 3, 42, 39, 3, "#604255");
box(7, 11, 1, 40, 37, 2, "#cbb992");
box(5, 11, 0, 7, 39, 3, "#51394d");
for (let x = 9; x <= 39; x++) {
if (x % 3 !== 0) set(x, 10, 1, "#9f8c70");
if (x % 4 !== 0) set(x, 10, 2, "#e0cda5");
}
for (let y of [15, 22, 30, 36]) box(5, y, 0, 7, y, 3, "#a88153");
box(5, 12, 3, 42, 12, 3, "#9c765b");
box(8, 10, 4, 40, 37, 4, "#325d61");
box(8, 10, 7, 40, 37, 7, "#467678");
box(10, 9, 5, 39, 35, 6, "#d5c39d");
box(7, 10, 4, 9, 37, 7, "#315358");
for (let x = 11; x <= 38; x++) {
if (x % 4 !== 0) set(x, 8, 5, "#ad9977");
if (x % 5 !== 0) set(x, 8, 6, "#e5d4ac");
}
for (let y of [13, 19, 28, 34]) box(7, y, 4, 9, y, 7, "#b99761");
box(8, 10, 7, 40, 10, 7, "#a3855b");
for (let i = 0; i < 90; i++) {
const x = 9 + Math.floor(rand() * 32);
const y = 11 + Math.floor(rand() * 26);
if (get(x, y, 7) === "#467678")
set(x, y, 7, rand() < 0.5 ? "#527d72" : "#385f62");
}
// Solid skull, with broad temples and an oversized rounded cranium.
ellipsoid(24, 24, 25, 16, 14, 14, "#d4c6a7");
ellipsoid(24, 23, 15, 11, 10, 7, "#cbbd9e");
ellipsoid(24, 18, 11, 10, 6, 3, "#d7c7a5");
ellipsoid(13, 17, 19, 5, 6, 4, "#d8c9a9");
ellipsoid(35, 17, 19, 5, 6, 4, "#d8c9a9");
line(10, 17, 18, 16, 12, 17, 2, "#e4d7b8");
line(38, 17, 18, 32, 12, 17, 2, "#e4d7b8");
// Warm aging, with lighter bone on the upper and forward-facing surfaces.
const bone = new Set(["#d4c6a7", "#cbbd9e", "#d7c7a5", "#d8c9a9", "#e4d7b8"]);
forEach((x, y, z, color) => {
if (!bone.has(color)) return;
const n = rand();
if (z > 29 && n < 0.14) set(x, y, z, "#eee2c5");
else if (z < 17 && n < 0.19) set(x, y, z, "#bba98a");
else if (n < 0.075) set(x, y, z, "#e8d9b9");
else if (n < 0.12) set(x, y, z, "#c1ae8e");
});
// Deep-set sockets: remove the forward bone, then color the recessed backs.
for (const eyeX of [17, 31]) {
for (let x = eyeX - 6; x <= eyeX + 6; x++)
for (let z = 18; z <= 31; z++) {
const d = ((x - eyeX) / 5.5) ** 2 + ((z - 24.5) / 6.3) ** 2;
if (d > 1) continue;
for (let y = 7; y <= 16; y++) {
if (get(x, y, z) !== undefined) set(x, y, z, null);
}
const back = d < 0.68 ? "#211e29" : "#493d3c";
set(x, 16, z, back);
if (d < 0.76) set(x, 15, z, d < 0.52 ? "#25212a" : "#645149");
}
// Heavy, friendly brow ridges and projecting cheekbones.
line(eyeX - 5, 15, 30, eyeX + 5, 14, 30, 1, "#e7dabb");
line(eyeX - 5, 14, 18, eyeX + 4, 13, 18, 1, "#e0d0ae");
}
ellipsoid(24, 13, 28, 2, 2, 6, "#e2d2b1");
// Inverted triangular nasal opening.
for (let z = 18; z <= 23; z++) {
const half = Math.floor((23 - z) * 0.68);
for (let x = 24 - half; x <= 24 + half; x++)
for (let y = 10; y <= 13; y++)
set(x, y, z, z < 20 ? "#514039" : "#29242a");
}
set(24, 10, 23, "#29242a");
// The mouth is a dark gap behind two unmistakable rows of square teeth.
box(16, 10, 12, 32, 12, 15, "#3a3030");
box(16, 9, 15, 32, 10, 16, "#b9a985");
for (let x = 17; x <= 31; x += 2) {
box(x, 8, 14, x + 1, 9, 16, "#f0e5cc");
box(x, 9, 11, x + 1, 10, 12, "#e6d8bc");
set(x + 1, 8, 14, "#cabb9f");
set(x + 1, 9, 11, "#c7b796");
}
line(15, 13, 11, 16, 10, 16, 2, "#c8b797");
line(33, 13, 11, 32, 10, 16, 2, "#c8b797");
box(18, 10, 9, 30, 13, 10, "#d9c8a5");
// Fine irregular cracks that follow the visible forehead.
function crack(x, z, color = "#937f67") {
const q = 1 - ((x - 24) / 16) ** 2 - ((z - 25) / 14) ** 2;
if (q <= 0) return;
const y = Math.ceil(24 - 14 * Math.sqrt(q)) - 1;
set(x, y, z, color);
}
for (const [x, z] of [
[13, 32], [14, 32], [15, 33], [16, 33], [17, 34],
[16, 31], [17, 30], [18, 29],
[27, 35], [28, 34], [29, 34], [30, 33], [31, 33],
[30, 32], [31, 31]
]) crack(x, z);
crack(18, 29, "#b09a7b");
// A little puddle of wax supports the half-melted candle.
ellipsoid(29, 24, 38, 5, 4, 1, "#e6dac4");
cylinder(29, 24, 38, 3, 5, "#f1e7d4");
cylinder(29, 24, 42, 3, 1, "#fff1dc");
line(26, 23, 40, 26, 23, 37, 1, "#e9deca");
line(32, 25, 41, 32, 25, 39, 1, "#e9deca");
line(29, 21, 40, 29, 21, 38, 1, "#fff0da");
set(29, 21, 37, "#e8dac1");
box(29, 23, 43, 29, 24, 43, "#514036");
// A tiny still flame with a saturated amber core.
ellipsoid(29, 23, 44, 2, 1, 1, "#e98332");
set(29, 23, 44, "#fff1a3");
set(29, 23, 45, "#ffca55");
set(29, 24, 44, "#ffc262");import { draw } from "./assets/voxel";
import { calavera } from "./assets/calavera";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, calavera, x, y, { size: 64, angle: 0, t: performance.now() / 1000 });
// size: lo que mide en px su lado más largo
// angle: giro sobre el piso, en radianes
// t: segundos; si se mueve, se anima solo con eso# En una terminal, en la carpeta del juego
fogon assets add calavera
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["calavera"] })
# Queda en client/assets/calavera.ts
# https://fogon.page/object/calavera