fogón

← Monsters and enemies3D assetfogon/gargola

Gárgola

by fogonCC015515 blocks
GárgolaDrag to turn it
// «Gárgola» · gpt-6-sol (medium)
// A crouching cartoon stone gargoyle on a small stone pedestal, facing -y: grey stone with darker cracks and moss spots, a grinning face with horns and glowing blue eyes, pointed ears, clawed hands on its knees, and two bat wings folded up behind its back.

const stone = ["#626c73", "#79848a", "#929da0"];
const dark = "#465158";
const light = "#adb8b8";
const moss = "#577d62";

function rocky(cx, cy, cz, rx, ry, rz) {
  for (let x = Math.floor(cx - rx); x <= Math.ceil(cx + rx); x++)
    for (let y = Math.floor(cy - ry); y <= Math.ceil(cy + ry); y++)
      for (let z = Math.floor(cz - rz); z <= Math.ceil(cz + rz); z++) {
        const d = ((x - cx) / rx) ** 2 + ((y - cy) / ry) ** 2 + ((z - cz) / rz) ** 2;
        if (d > 1) continue;
        let c = z < cz - rz * 0.35 ? stone[0] : z > cz + rz * 0.35 ? stone[2] : stone[1];
        if (rand() < 0.055) c = rand() < 0.5 ? stone[0] : stone[2];
        set(x, y, z, c);
      }
}

// Low, beveled display pedestal.
box(8, 10, 0, 40, 38, 1, "#48545b");
box(9, 11, 2, 39, 37, 3, "#68747a");
box(11, 13, 4, 37, 35, 5, "#929c9e");
box(11, 13, 4, 37, 13, 4, "#b2bbbb");
box(11, 35, 4, 37, 35, 4, "#58646b");
for (let i = 0; i < 45; i++) {
  const x = 11 + Math.floor(rand() * 27);
  const y = 13 + Math.floor(rand() * 23);
  set(x, y, 5, rand() < 0.28 ? moss : "#818e90");
}

// Each folded bat wing is a separate moving part.
function inside(poly, x, z) {
  let hit = false;
  for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
    const a = poly[i], b = poly[j];
    if ((a[1] > z) !== (b[1] > z) &&
        x < (b[0] - a[0]) * (z - a[1]) / (b[1] - a[1]) + a[0]) hit = !hit;
  }
  return hit;
}

function wing(side) {
  const mirror = x => side < 0 ? x : 48 - x;
  const poly = [
    [17, 27], [15, 34], [11, 43], [9, 39],
    [6, 41], [7, 34], [4, 32], [7, 28],
    [10, 29], [9, 24], [14, 27]
  ];
  part(side < 0 ? "leftWing" : "rightWing",
       [side < 0 ? 17 : 31, 31, 28]);
  for (let x = 4; x <= 17; x++)
    for (let z = 23; z <= 43; z++) {
      if (!inside(poly, x + 0.5, z + 0.5)) continue;
      const edge = !inside(poly, x - 0.5, z + 0.5) ||
                   !inside(poly, x + 1.5, z + 0.5) ||
                   !inside(poly, x + 0.5, z - 0.5) ||
                   !inside(poly, x + 0.5, z + 1.5);
      for (let y = 32; y <= 33; y++)
        set(mirror(x), y, z,
            edge ? dark : rand() < 0.17 ? "#75818b" : "#66727d");
    }
  // Raised ribs make the wing shape legible from the front.
  for (const [x, z] of [[11, 43], [6, 41], [4, 32], [9, 24]]) {
    line(mirror(17), 31, 28, mirror(x), 31, z, 0, "#9aa5a7");
  }
  line(mirror(11), 31, 43, mirror(6), 31, 41, 0, dark);
  line(mirror(6), 31, 41, mirror(4), 31, 32, 0, dark);
  animate(side < 0 ? "leftWing" : "rightWing",
          { type: "swing", axis: "y", speed: side < 0 ? 2 : -2, amplitude: 0.3 });
}
wing(-1);
wing(1);
part("body");

// Haunches and enormous planted feet.
rocky(17, 20, 14, 6, 7, 7);
rocky(31, 20, 14, 6, 7, 7);
rocky(16, 17, 8, 5, 7, 3);
rocky(32, 17, 8, 5, 7, 3);
for (const x of [13, 16, 19, 29, 32, 35]) {
  box(x, 10, 6, x + 1, 14, 8, stone[2]);
  set(x, 9, 6, light);
}
rocky(24, 25, 23, 9, 8, 10);
rocky(24, 18, 21, 7, 4, 7);
box(20, 14, 18, 28, 15, 18, "#687773");

// Shoulders, bent arms, and hands resting on the knees.
for (const side of [-1, 1]) {
  const shoulder = side < 0 ? 16 : 32;
  const elbow = side < 0 ? 12 : 36;
  const hand = side < 0 ? 17 : 31;
  rocky(shoulder, 22, 27, 4, 5, 5);
  line(shoulder, 19, 26, elbow, 17, 19, 3, stone[0]);
  line(elbow, 17, 19, hand, 13, 17, 2, stone[1]);
  rocky(hand, 13, 17, 3, 3, 2);
  for (let i = -2; i <= 2; i += 2) {
    const fx = hand + i;
    line(fx, 11, 17, fx, 9, 15, 1, stone[2]);
    set(fx, 9, 14, light);
  }
}

// Oversized head, pointed ears, and swept horns.
rocky(24, 19, 32, 10, 8, 8);
for (const side of [-1, 1]) {
  const ear = side < 0
    ? [[15, 34], [9, 40], [10, 33], [14, 30]]
    : [[33, 34], [39, 40], [38, 33], [34, 30]];
  for (let x = side < 0 ? 9 : 33; x <= (side < 0 ? 15 : 39); x++)
    for (let z = 30; z <= 40; z++)
      if (inside(ear, x + 0.5, z + 0.5))
        for (let y = 17; y <= 20; y++)
          set(x, y, z, y === 17 ? stone[2] : stone[0]);
  const hx = side < 0 ? 18 : 30;
  line(hx, 17, 38, hx + side * 2, 17, 42, 2, stone[0]);
  line(hx + side * 2, 17, 42, hx + side * 4, 17, 44, 1, light);
}

// Cheeks and a broad, friendly toothy grin.
rocky(19, 13, 29, 4, 3, 3);
rocky(29, 13, 29, 4, 3, 3);
box(20, 10, 27, 28, 12, 30, stone[1]);
box(22, 9, 30, 26, 10, 31, stone[2]);
box(20, 9, 27, 28, 9, 28, "#303c46");
set(19, 10, 28, dark);
set(29, 10, 28, dark);
for (const x of [21, 23, 25, 27]) set(x, 8, 28, "#d3d7cc");
set(24, 8, 27, "#819098");

// Heavy brows frame bright cyan eyes.
for (const x of [19, 29]) {
  box(x - 2, 11, 33, x + 2, 13, 35, "#35464f");
  box(x - 1, 10, 34, x + 1, 10, 35, "#36d9ef");
  set(x, 9, 35, "#d1ffff");
  line(x - 3, 12, 37, x + 2, 12, 37, 1, stone[0]);
}

// A few deliberately placed cracks and moss flecks.
line(15, 12, 33, 17, 11, 31, 0, "#3e4c53");
line(17, 11, 31, 16, 12, 29, 0, "#3e4c53");
line(31, 13, 38, 33, 14, 36, 0, "#49565c");
line(23, 15, 18, 25, 15, 16, 0, "#48565c");
for (const [x, y, z] of [
  [13, 17, 20], [14, 16, 21], [34, 17, 21],
  [35, 17, 20], [16, 12, 14], [32, 12, 13],
  [18, 13, 38], [30, 13, 39], [22, 15, 25]
]) set(x, y, z, moss);