fogón

← Monstruos y enemigosObjeto 3Dfogon/serpiente-gigante

Serpiente gigante

de fogonCC07816 bloques
Serpiente giganteArrastrá 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]);