fogón

← FantasíaObjeto 3Dfogon/totem-runico

Tótem rúnico

de fogonCC013834 bloques
Tótem rúnicoArrastrá para girarlo
// «Tótem rúnico» · gpt-6-sol (medium)
// A tall carved stone totem: stacked blocks of grey stone with carved faces and glowing blue runes, moss at the base, and a small floating crystal hovering above the top.

const stone = ["#666e70", "#717a7b", "#7c8585", "#899291"];
const dark = "#38474d";
const recess = "#30434c";
const cyan = "#43e8f2";
const bright = "#b5fbff";

function carvedBlock(x0, x1, y0, y1, z0, z1) {
  for (let z = z0; z <= z1; z++)
    for (let y = y0; y <= y1; y++)
      for (let x = x0; x <= x1; x++) {
        // Nipped corners make each massive block feel softly carved.
        const cornerX = Math.min(x - x0, x1 - x);
        const cornerY = Math.min(y - y0, y1 - y);
        const cornerZ = Math.min(z - z0, z1 - z);
        if (cornerX === 0 && cornerY === 0) continue;
        if (cornerX === 0 && cornerZ === 0 && (y === y0 || y === y1)) continue;
        let c = stone[z >= z1 - 2 ? 2 : z <= z0 + 1 ? 0 : 1];
        if (rand() < 0.12) c = stone[Math.floor(rand() * stone.length)];
        set(x, y, z, c);
      }
}

function rune(x, y, z) {
  const glow = "#168fa8";
  line(x, y, z, x, y, z + 4, 0, glow);
  set(x, y - 1, z + 1, cyan);
  set(x, y - 1, z + 2, bright);
  set(x, y - 1, z + 3, cyan);
  set(x - 1, y - 1, z + 3, cyan);
  set(x + 1, y - 1, z + 3, cyan);
  set(x - 1, y - 1, z + 4, "#72f5ff");
  set(x + 1, y - 1, z + 4, "#72f5ff");
}

function face(front, low, high) {
  const y = front - 1;
  const eyeZ = high - 5;

  // Deep-set, generously sized cartoon eyes.
  for (const x of [20, 28]) {
    box(x - 1, y, eyeZ - 1, x + 1, y, eyeZ + 1, recess);
    box(x - 1, y - 1, eyeZ, x + 1, y - 1, eyeZ + 1, cyan);
    set(x, y - 2, eyeZ + 1, bright);
    box(x - 2, y - 1, eyeZ + 2, x + 2, y, eyeZ + 2, "#596467");
    box(x - 1, y - 2, eyeZ + 3, x + 1, y - 2, eyeZ + 3, "#929b98");
  }

  box(23, y - 2, eyeZ - 2, 25, y - 1, eyeZ, "#929b98");
  box(23, y - 3, eyeZ - 2, 25, y - 3, eyeZ - 2, "#a7afaa");

  const mouthZ = low + 3;
  line(21, y - 1, mouthZ + 1, 23, y - 1, mouthZ, 0, dark);
  line(23, y - 1, mouthZ, 25, y - 1, mouthZ, 0, dark);
  line(25, y - 1, mouthZ, 27, y - 1, mouthZ + 1, 0, dark);
  set(20, y - 1, mouthZ + 2, "#a09198");
  set(28, y - 1, mouthZ + 2, "#a09198");

  rune(16, y, low + 3);
  rune(32, y, low + 3);
}

// Broad, weathered footing.
for (let z = 0; z <= 3; z++)
  for (let y = 10; y <= 38; y++)
    for (let x = 7; x <= 41; x++) {
      const dx = (x - 24) / (17 - z * 0.7);
      const dy = (y - 24) / (14 - z * 0.5);
      if (dx * dx + dy * dy > 1 + (rand() - 0.5) * 0.075) continue;
      set(x, y, z, rand() < 0.2 ? "#596663" : stone[z === 3 ? 2 : 0]);
    }

carvedBlock(15, 33, 18, 32, 4, 15);
carvedBlock(14, 34, 17, 33, 16, 26);
carvedBlock(15, 33, 18, 32, 27, 36);

// Heavy lips between the three carved heads.
for (const [x0, x1, y0, y1, z] of [
  [13, 35, 16, 34, 15],
  [13, 35, 16, 34, 26],
  [14, 34, 17, 33, 36]
]) {
  box(x0 + 1, y0 + 1, z, x1 - 1, y1 - 1, z, "#525e61");
  box(x0 + 2, y0, z, x1 - 2, y1, z, "#929b96");
  box(x0, y0 + 2, z, x1, y1 - 2, z, "#929b96");
  line(x0 + 2, y0 - 1, z, x1 - 2, y0 - 1, z, 0, "#a5ada5");
}
face(18, 4, 15);
face(17, 16, 26);
face(18, 27, 36);

// Tiny glowing marks in the gaps between heads.
for (const z of [15, 26, 36]) {
  for (const x of [18, 24, 30]) {
    set(x, 15, z, "#166a7c");
    set(x, 14, z, x === 24 ? bright : cyan);
  }
}

// Scattered moss on the footing and on lower stone ledges.
forEach((x, y, z, color) => {
  if (z > 9 || z < 2 || get(x, y, z + 1) !== undefined) return;
  const chance = z <= 3 ? 0.39 : 0.15;
  if (rand() < chance) {
    set(x, y, z + 1, rand() < 0.3 ? "#80a266" : "#537d62");
    if (rand() < 0.16) set(x, y, z + 2, "#91ae70");
  }
});

// Moss spills down the front corners.
for (const x of [16, 17, 31, 32]) {
  for (let z = 4; z <= 8; z++)
    if (rand() < 0.7) set(x, 17, z, rand() < 0.5 ? "#547b60" : "#789667");
}

// Two miniature storybook mushrooms.
for (const [x, y, cap] of [
  [12, 15, "#b97ac2"],
  [37, 18, "#db9eae"]
]) {
  box(x, y, 3, x, y, 5, "#e9dbb6");
  box(x - 2, y - 1, 6, x + 2, y + 1, 6, cap);
  box(x - 1, y - 1, 7, x + 1, y + 1, 7, cap);
  set(x - 1, y - 1, 7, "#f1c5de");
  set(x + 1, y, 7, "#f1c5de");
}

// A brass-rimmed socket below the hovering crystal.
box(21, 21, 37, 27, 27, 37, "#685e51");
box(22, 22, 38, 26, 26, 38, "#c1a574");
box(23, 23, 39, 25, 25, 39, "#4e9da4");

part("crystal", [24, 24, 42]);
for (let z = 39; z <= 45; z++) {
  const radius = [0, 2, 3, 3, 2, 1, 0][z - 39];
  for (let y = 24 - radius; y <= 24 + radius; y++)
    for (let x = 24 - radius; x <= 24 + radius; x++) {
      if (Math.abs(x - 24) + Math.abs(y - 24) > radius + 1) continue;
      set(x, y, z, x <= 24 && y <= 24 ? "#a8faff" : "#208dca");
    }
}
animate("crystal", { type: "bob", axis: "z", amplitude: 1, speed: 2 });
animate("crystal", {
  type: "colors",
  palette: ["#216ac7", "#36e9ff", "#f0ffff"],
  pattern: "pulse",
  glow: 0.9
});
part("body", [24, 24, 0]);