← Monstruos y enemigosObjeto 3Dfogon/serpiente-gigante
Serpiente gigante
Arrastrá para girarlo// «Serpiente gigante» · gpt-6-sol (medium)
// A big cartoon snake coiled on the ground in a spiral, with the front of its body rising up into an S-curve and the head facing -y: bright green scales with yellow diamond pattern and a pale belly, a wide flat head with glowing yellow slit eyes, two fangs and a forked red tongue.
// Coiled body: a broad spiral resting on the floor.
const greenDark = "#187b34";
const green = "#2fba43";
const greenLight = "#54d951";
const yellow = "#f5dc42";
const yellowLight = "#fff078";
const belly = "#e9e5a4";
const bellyShade = "#c8ca83";
const path = [];
const steps = 155;
for (let i = 0; i <= steps; i++) {
const t = i / steps;
const a = -Math.PI / 2 + t * Math.PI * 2.8;
const radius = 15 - t * 10;
path.push([
24 + Math.cos(a) * radius,
24 + Math.sin(a) * radius,
a
]);
}
for (const [x, y] of path) {
sphere(x, y, 3.8, 3.8, greenDark);
sphere(x, y, 4.4, 3.35, green);
sphere(x, y, 5.0, 2.65, greenLight);
}
// Subtle scale variation, before the bold markings are added.
forEach((x, y, z, color) => {
if (color === green && rand() < 0.045) set(x, y, z, greenLight);
if (color === greenLight && rand() < 0.035) set(x, y, z, green);
});
// Diamonds follow the center of the spiral, across the upper surface.
for (let i = 7; i < steps - 3; i += 7) {
const [cx, cy] = path[i];
const previous = path[i - 2], next = path[i + 2];
const dx = next[0] - previous[0], dy = next[1] - previous[1];
const length = Math.hypot(dx, dy);
const tx = dx / length, ty = dy / length;
const nx = -ty, ny = tx;
for (let along = -3; along <= 3; along++) {
for (let across = -2; across <= 2; across++) {
if (Math.abs(along) / 3 + Math.abs(across) / 2 > 1.05) continue;
const x = Math.round(cx + tx * along + nx * across);
const y = Math.round(cy + ty * along + ny * across);
const z = Math.round(4.3 + Math.sqrt(3.6 * 3.6 - across * across));
set(x, y, z, Math.abs(along) + Math.abs(across) < 2 ? yellowLight : yellow);
}
}
}
// The tapered tail curls upward inside the spiral.
const tail = [
[28, 27, 5, 3.0], [27, 27, 6, 2.6], [26, 26, 7, 2.1],
[25, 25, 8, 1.6], [24, 25, 9, 1.0]
];
for (const [x, y, z, r] of tail) {
sphere(x, y, z, r, greenDark);
sphere(x, y, z + 0.5, r * 0.85, greenLight);
}
// The entire raised section sways from its base.
part("raised head and neck", [24, 9, 6]);
animate("raised head and neck", {
type: "swing", axis: "y", speed: 2, amplitude: 0.3
});
const neck = [
[24, 9, 6], [23, 11, 10], [19, 16, 15],
[19, 17, 20], [26, 16, 25], [28, 13, 30],
[26, 11, 33]
];
for (let j = 0; j < neck.length - 1; j++) {
const a = neck[j], b = neck[j + 1];
const count = Math.ceil((b[2] - a[2]) * 2);
for (let k = 0; k <= count; k++) {
const t = k / count;
const x = a[0] + (b[0] - a[0]) * t;
const y = a[1] + (b[1] - a[1]) * t;
const z = a[2] + (b[2] - a[2]) * t;
const r = z < 11 ? 3.8 : 4.1;
sphere(x, y, z, r, greenDark);
sphere(x, y + 0.25, z + 0.35, r - 0.55, green);
ellipsoid(x, y - 2.8, z, 2.55, 1.65, 2.25, belly);
}
}
// Belly plates and a few yellow scales on the exposed sides of the neck.
for (let z = 11; z <= 29; z += 3) {
let a = neck[0], b = neck[1];
for (let j = 0; j < neck.length - 1; j++) {
if (z >= neck[j][2] && z <= neck[j + 1][2]) {
a = neck[j]; b = neck[j + 1]; break;
}
}
const t = (z - a[2]) / (b[2] - a[2]);
const x = a[0] + (b[0] - a[0]) * t;
const y = a[1] + (b[1] - a[1]) * t;
line(x - 2, y - 4.25, z, x + 2, y - 4.25, z, 0, bellyShade);
for (const side of [-1, 1]) {
sphere(x + side * 3.3, y + 0.7, z + 1, 1.05, yellow);
}
}
// Broad, flattened cartoon head and pale lower jaw.
ellipsoid(25, 10.5, 34, 9, 6, 4.8, greenDark);
ellipsoid(25, 10, 34.7, 8.5, 5.65, 4.15, green);
ellipsoid(25, 7, 30, 7.8, 4.7, 2.5, bellyShade);
ellipsoid(25, 6.6, 30.6, 7.4, 4.2, 2.2, belly);
ellipsoid(25, 5.2, 32.8, 8.1, 4.0, 2.9, green);
ellipsoid(25, 5.8, 34, 7.5, 3.5, 2.2, greenLight);
// Raised brows frame two bright, slit-pupil eyes.
for (const ex of [20, 30]) {
ellipsoid(ex, 4.8, 36, 2.65, 1.65, 2.15, greenDark);
ellipsoid(ex, 3.55, 36.1, 1.95, 0.85, 1.6, yellow);
ellipsoid(ex - 0.35, 3.0, 36.6, 0.8, 0.45, 0.55, yellowLight);
line(ex, 2.8, 35, ex, 2.8, 37, 0, "#24391c");
ellipsoid(ex, 5.3, 38, 3.2, 1.8, 0.9, greenLight);
}
// Nostrils, a curved smile, and two pointed ivory fangs.
set(22, 1, 33, "#176229");
set(28, 1, 33, "#176229");
line(20, 2, 30, 30, 2, 30, 0, "#31502a");
line(19, 3, 31, 20, 2, 30, 0, "#31502a");
line(30, 2, 30, 31, 3, 31, 0, "#31502a");
for (const fx of [21, 29]) {
box(fx - 1, 2, 28, fx + 1, 3, 30, "#fff7d3");
box(fx, 2, 26, fx, 3, 27, "#fff7d3");
set(fx - 1, 2, 28, "#d8d2a5");
}
// A little forked tongue pokes toward the viewer.
line(25, 2, 29, 25, 0, 27, 0, "#e83951");
line(25, 0, 27, 22, 0, 26, 0, "#fb4b63");
line(25, 0, 27, 28, 0, 26, 0, "#fb4b63");
part("body", [24, 24, 0]);import { draw } from "./assets/voxel";
import { serpienteGigante } from "./assets/serpiente-gigante";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, serpienteGigante, 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 serpiente-gigante
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["serpiente-gigante"] })
# Queda en client/assets/serpiente-gigante.ts
# https://fogon.page/object/serpiente-gigante