fogón

← Animals3D assetfogon/ballena

Ballena

by fogonCC013811 blocks
BallenaDrag to turn it
// «Ballena» · gpt-6-sol (medium)
// A huge chubby cartoon blue whale, horizontal along y, head at the front (-y): a big rounded dark blue body with a pale blue belly with grooves, small eyes near the mouth, a wide smiling mouth, two flippers, a tiny dorsal fin and a big horizontal tail fluke. A small white water spout on top of its head.

// Big rounded body and a low, pale belly.
ellipsoid(24, 20, 14, 15, 15, 13, "#2769ad");
ellipsoid(24, 20, 10, 12, 12, 10, "#2769ad");

// Narrow the body into the tail joint.
ellipsoid(24, 32, 14, 7, 8, 6, "#2769ad");
ellipsoid(24, 37, 14, 3, 5, 3, "#2769ad");

// Color the body in broad, readable bands.
forEach((x, y, z, color) => {
  if (color !== "#2769ad") return;
  if (z <= (y < 17 ? 12 : 10) && y < 32) {
    set(x, y, z, rand() < 0.07 ? "#91d3e9" : z < 5 ? "#77bedb" : "#a5ddef");
  } else if (z >= 20) {
    set(x, y, z, rand() < 0.09 ? "#3981c2" : "#3176b8");
  } else {
    set(x, y, z, rand() < 0.07 ? "#225d9f" : "#2769ad");
  }
});

// Find the front-facing block at a given point on the face.
function front(x, z) {
  for (let y = 3; y <= 32; y++) {
    if (get(x, y, z)) return y;
  }
  return null;
}

// Fine grooves radiating down the pale chin.
for (const x of [17, 21, 25, 29, 33]) {
  for (let z = 3; z <= 8; z++) {
    const y = front(x, z);
    if (y !== null && y < 23) set(x, y - 1, z, "#70b6d4");
  }
}

// An exaggerated, upturned smile across the front of the head.
for (let x = 12; x <= 36; x++) {
  const z = Math.round(9 + 0.035 * (x - 24) * (x - 24));
  const y = front(x, z);
  if (y !== null) {
    set(x, y - 1, z, "#173e68");
    if (x >= 19 && x <= 29) set(x, y - 1, z + 1, "#19446d");
  }
}

// Small black dot eyes, with one bright toy-like glint each.
for (const x of [15, 33]) {
  const z = 19;
  const y = front(x, z);
  ellipsoid(x, y - 1, z, 1.5, 1.3, 1.5, "#102541");
  set(x - 1, y - 2, z + 1, "#ffffff");
}

// Broad, swept-back flippers.
for (const side of [-1, 1]) {
  for (let i = 0; i <= 10; i++) {
    const x = 24 + side * (12 + i);
    const y = 20 + Math.round(i * 0.9);
    const r = i < 6 ? 3 : 2;
    ellipsoid(x, y, 10 - Math.round(i * 0.15), 2, r, 2,
      i > 7 ? "#3179b9" : "#2464a7");
  }
  ellipsoid(24 + side * 22, 30, 8, 2, 2, 1, "#4c94c9");
}

// Tiny dorsal fin, peeking over the back.
for (let z = 25; z <= 30; z++) {
  const width = Math.max(0, 3 - Math.floor((z - 25) / 2));
  box(24 - width, 31 + Math.floor((z - 25) / 3), z,
      24 + width, 34, z, z >= 28 ? "#347cbb" : "#245f9f");
}

// The fluke is one moving piece, hinged at the tail joint.
part("tail", [24, 37, 14]);
ellipsoid(24, 39, 14, 3, 4, 2, "#245f9f");
for (let dx = -14; dx <= 14; dx++) {
  const a = Math.abs(dx);
  const y0 = 38 + Math.floor(a * 0.36);
  const y1 = Math.min(46, 42 + Math.floor(a * 0.32));
  const halfThickness = a < 5 ? 2 : 1;
  for (let y = y0; y <= y1; y++) {
    for (let z = 14 - halfThickness; z <= 14 + halfThickness; z++) {
      set(24 + dx, y, z,
        z === 14 + halfThickness ? "#3984bd" : "#245f9f");
    }
  }
}
animate("tail", { type: "swing", axis: "x", speed: 2, amplitude: 0.3 });
part("body");

// A little fountain rising from the top of the head.
part("spout", [24, 12, 26]);
line(24, 12, 26, 24, 12, 32, 1, "#f4fcff");
line(24, 12, 32, 21, 11, 35, 0, "#f4fcff");
line(24, 12, 32, 27, 11, 35, 0, "#f4fcff");
line(24, 12, 32, 24, 15, 35, 0, "#f4fcff");
sphere(21, 11, 35, 1, "#f4fcff");
sphere(27, 11, 35, 1, "#f4fcff");
sphere(24, 15, 35, 1, "#f4fcff");
animate("spout", {
  type: "colors",
  palette: ["#ffffff", "#eafaff", "#bdeeff"],
  pattern: "flicker",
  glow: 0.25
});
part("body");