fogón

← FantasíaObjeto 3Dfogon/ruinas-magicas

Ruinas mágicas

de fogonCC09962 bloques
Ruinas mágicasArrastrá para girarlo
// «Ruinas mágicas» · gpt-6-sol (medium)
// Ancient magic ruins: a broken circle of mossy grey stone pillars of different heights, one fallen pillar lying on the ground, a cracked stone floor with glowing violet runes in the center, and ivy climbing the columns.

const stone = ["#777f7b", "#858d88", "#969e97", "#6b746f"];
const darkStone = "#535d59";
const moss = ["#537852", "#668d59", "#83a66a"];
const glow = ["#a95cff", "#ed65df", "#58e9e3"];
const cx = 24, cy = 24;

function disk(x, y, z, r, color) {
  for (let dx = -Math.ceil(r); dx <= r; dx++)
    for (let dy = -Math.ceil(r); dy <= r; dy++)
      if (dx * dx + dy * dy <= r * r) set(x + dx, y + dy, z, color);
}

// An uneven, tiled foundation.
for (let x = 4; x <= 44; x++) {
  for (let y = 4; y <= 44; y++) {
    const d = Math.hypot(x - cx, y - cy);
    if (d > 19.5 || (d > 18.1 && rand() < 0.3)) continue;
    box(x, y, 0, x, y, 1, d > 17.5 ? darkStone : stone[0]);
    const seam = (x + Math.floor(y / 7) % 2) % 7 === 0 || y % 7 === 0;
    set(x, y, 2, seam ? "#555f5c" : stone[rand() < 0.16 ? 2 : rand() < 0.3 ? 0 : 1]);
    if (d > 9 && rand() < 0.075) set(x, y, 2, moss[Math.floor(rand() * moss.length)]);
  }
}

// Short surviving pieces of the circular outer wall.
for (let a = 0; a < Math.PI * 2; a += 0.065) {
  if ((a > 0.18 && a < 0.55) || (a > 2.5 && a < 3.1) ||
      (a > 4.1 && a < 5.5)) continue;
  const x = Math.round(cx + 16 * Math.cos(a));
  const y = Math.round(cy + 16 * Math.sin(a));
  set(x, y, 3, rand() < 0.2 ? moss[0] : stone[0]);
  if (rand() < 0.5) set(x, y, 4, stone[1]);
}

// Raised, dark altar beneath the luminous inscription.
disk(cx, cy, 3, 9, "#59615f");
disk(cx, cy, 4, 8, "#464c55");
for (let a = 0; a < Math.PI * 2; a += 0.045) {
  const x = Math.round(cx + 8.5 * Math.cos(a));
  const y = Math.round(cy + 8.5 * Math.sin(a));
  set(x, y, 4, a % 0.45 < 0.09 ? "#a6a49b" : "#77817e");
}

// Cracks radiating into the old flagstones.
const cracks = [
  [[16, 19], [13, 18], [11, 16]],
  [[30, 18], [33, 16], [36, 17]],
  [[17, 29], [14, 31], [12, 33]],
  [[29, 32], [32, 34], [34, 37]],
  [[23, 34], [22, 37], [20, 39]]
];
for (const chain of cracks) {
  for (let i = 1; i < chain.length; i++) {
    const [x0, y0] = chain[i - 1], [x1, y1] = chain[i];
    line(x0, y0, 2, x1, y1, 2, 0, "#424b4b");
  }
}

function mushroom(x, y, cap) {
  box(x, y, 3, x, y, 4, "#dfd2af");
  box(x - 1, y, 5, x + 1, y, 5, cap);
  box(x, y - 1, 5, x, y + 1, 5, cap);
  set(x, y, 6, "#f4adb8");
}

function pillar(x, y, top, seed) {
  // Broad foot, rounded-looking square shaft, and inset front face.
  box(x - 3, y - 3, 3, x + 3, y + 3, 5, darkStone);
  box(x - 3, y - 3, 5, x + 3, y + 3, 6, stone[2]);
  box(x - 2, y - 2, 7, x + 2, y + 2, top - 2, stone[0]);
  box(x - 2, y - 2, 7, x + 1, y - 2, top - 2, stone[1]);
  box(x - 2, y - 2, 7, x - 2, y + 2, top - 2, stone[2]);
  box(x + 2, y - 1, 7, x + 2, y + 2, top - 2, stone[3]);

  for (let z = 10; z < top - 2; z += 6) {
    box(x - 2, y - 2, z, x + 2, y - 2, z, "#65706b");
    set(x + (z % 2 ? 1 : -1), y - 2, z, "#a1a79d");
  }
  // Deliberately irregular broken ends.
  box(x - 2, y - 2, top - 1, x + 1, y + 2, top - 1, stone[1]);
  box(x - 2, y, top, x, y + 2, top, stone[2]);
  set(x + 1, y + 1, top, stone[0]);
  if (seed % 3 === 0) {
    box(x - 3, y - 3, top - 3, x + 3, y + 3, top - 2, stone[2]);
    box(x - 3, y + 2, top - 3, x + 3, y + 3, top - 3, stone[3]);
  }

  // Ivy follows one face in a winding, leafy strand.
  const ivyTop = Math.min(top - 3, 12 + seed * 2);
  for (let z = 6; z <= ivyTop; z++) {
    const ix = x - 1 + Math.round(Math.sin(z * 0.74 + seed) * 1.4);
    set(ix, y - 3, z, z % 4 === 0 ? "#756b48" : moss[0]);
    if (z % 3 === 0) {
      box(ix - 1, y - 3, z, ix, y - 3, z + 1, moss[1]);
      set(ix + 1, y - 3, z + 1, moss[2]);
    }
  }
  for (let i = 0; i < 10; i++) {
    const mx = x + Math.floor(rand() * 6) - 3;
    const my = y + Math.floor(rand() * 6) - 3;
    set(mx, my, rand() < 0.5 ? 6 : top, moss[Math.floor(rand() * 3)]);
  }
}

[
  [10, 13, 25], [8, 24, 30], [12, 35, 22],
  [24, 39, 36], [36, 35, 27], [40, 24, 32],
  [38, 13, 19]
].forEach(([x, y, h], i) => pillar(x, y, h, i + 1));

// A toppled column across the near side of the courtyard.
cylinder(15, 9, 5, 3, 16, "#78827c", "x");
cylinder(15, 9, 5, 2, 16, "#929a91", "x");
for (const x of [16, 21, 27]) {
  box(x, 6, 3, x + 1, 12, 7, "#646e69");
  box(x, 7, 8, x + 1, 11, 8, "#9da59a");
}
box(14, 7, 3, 14, 11, 7, "#555e5c");
box(30, 8, 3, 31, 10, 6, "#636d68");
for (let i = 0; i < 18; i++) {
  const x = 15 + Math.floor(rand() * 16);
  const y = 7 + Math.floor(rand() * 5);
  set(x, y, 8, moss[Math.floor(rand() * 3)]);
}

mushroom(7, 16, "#cd648c");
mushroom(35, 10, "#bd70d5");
mushroom(39, 30, "#d57893");
mushroom(13, 39, "#b967bb");

// Only the magic inscription changes color.
part("runes", [24, 24, 5]);
for (const radius of [7.1, 5.1]) {
  for (let a = 0; a < Math.PI * 2; a += 0.018) {
    if (radius < 6 && Math.floor(a * 8) % 17 === 0) continue;
    set(Math.round(cx + radius * Math.cos(a)),
        Math.round(cy + radius * Math.sin(a)), 5,
        glow[Math.floor(a * 3) % 3]);
  }
}
for (let i = 0; i < 8; i++) {
  const a = i * Math.PI / 4;
  const x0 = Math.round(cx + 5.6 * Math.cos(a));
  const y0 = Math.round(cy + 5.6 * Math.sin(a));
  const x1 = Math.round(cx + 6.7 * Math.cos(a));
  const y1 = Math.round(cy + 6.7 * Math.sin(a));
  line(x0, y0, 5, x1, y1, 5, 0, glow[i % 3]);
  const px = Math.round(cx + 6.2 * Math.cos(a + 0.17));
  const py = Math.round(cy + 6.2 * Math.sin(a + 0.17));
  set(px, py, 5, glow[(i + 1) % 3]);
}
// Large, legible four-pointed sigil.
for (let d = -3; d <= 3; d++) {
  set(cx + d, cy, 5, glow[1]);
  set(cx, cy + d, 5, glow[0]);
}
for (const [dx, dy] of [[-2,-2], [-2,2], [2,-2], [2,2]])
  set(cx + dx, cy + dy, 5, glow[2]);
set(cx, cy, 6, "#f6b8ff");

animate("runes", {
  type: "colors",
  palette: ["#994dff", "#f05adf", "#57e9ee"],
  pattern: "wave",
  glow: 0.8
});