fogón

← Ancient and prehistory3D assetfogon/fogata

Fogata

by fogonCC04992 blocks
FogataDrag to turn it
// «Fogata» · gpt-6-sol (medium)
// A campfire: a ring of round grey stones on the ground with crossed dark brown logs in the middle, and a tall cartoon flame rising from them in layers (deep red at the bottom, orange, then yellow at the tips). A few small embers around the logs.

// Campfire stones
const cx = 24, cy = 24;
const greys = ["#666963", "#777b72", "#898d83", "#9ca096"];

for (let i = 0; i < 14; i++) {
  const a = 2 * Math.PI * i / 14;
  const r = 17 + (rand() - 0.5) * 1.4;
  const x = cx + Math.cos(a) * r;
  const y = cy + Math.sin(a) * r;
  const size = 2.8 + rand() * 0.6;
  ellipsoid(x, y, 2, size, size * 0.9, 2.7, greys[i % 3]);
}

// Subtle mottling on the round stones
forEach((x, y, z, color) => {
  if (color && z >= 2 && rand() < 0.13) {
    set(x, y, z, greys[Math.floor(rand() * greys.length)]);
  }
});

// Ash and glowing coals inside the ring
for (let i = 0; i < 32; i++) {
  const a = rand() * Math.PI * 2;
  const r = 4 + rand() * 10;
  const x = Math.round(cx + Math.cos(a) * r);
  const y = Math.round(cy + Math.sin(a) * r);
  box(x, y, 0, x + (rand() < 0.25 ? 1 : 0), y, 0,
      rand() < 0.7 ? "#51443b" : "#70584a");
}
for (let i = 0; i < 16; i++) {
  const a = rand() * Math.PI * 2;
  const r = 5 + rand() * 8;
  const x = Math.round(cx + Math.cos(a) * r);
  const y = Math.round(cy + Math.sin(a) * r);
  set(x, y, 1 + Math.floor(rand() * 2),
      ["#a43520", "#dd5a1e", "#f59229", "#ffd063"][i % 4]);
}

// Two chunky crossed logs, with bark grooves and pale cut ends
function log(x0, y0, z0, x1, y1, z1) {
  line(x0, y0, z0, x1, y1, z1, 2.8, "#382720");
  line(x0, y0, z0 + 1, x1, y1, z1 + 1, 1.8, "#63402b");
  line(x0 + 2, y0, z0 + 2, x1 - 2, y1, z1 + 2, 0, "#91603a");
  line(x0 + 4, y0 - 1, z0 + 2, x1 - 3, y1 - 1, z1 + 2, 0, "#4b3024");
  sphere(x0, y0, z0, 2.1, "#b38553");
  sphere(x1, y1, z1, 2.1, "#a97648");
  set(x0, y0, z0, "#69472e");
  set(x1, y1, z1, "#69472e");
}
log(12, 15, 5, 36, 33, 5);
log(12, 33, 7, 36, 15, 7);

// All flame blocks belong to one animated part.
part("flame", [24, 24, 9]);

function flameShade(z, bottom, top, edge) {
  const t = (z - bottom) / (top - bottom);
  if (t < 0.23) return edge ? "#ad2e20" : "#c83b20";
  if (t < 0.62) return edge ? "#e45a20" : "#f48122";
  if (t < 0.88) return edge ? "#ffad30" : "#ffce43";
  return edge ? "#ffdb65" : "#fff0a0";
}

// A tapered, slightly bending tongue built from solid elliptical slices
function tongue(x0, y0, bottom, top, width, depth, bend) {
  for (let z = bottom; z <= top; z++) {
    const t = (z - bottom) / (top - bottom);
    const flare = t < 0.19 ? 0.48 + t * 2.7 : Math.pow(1 - t, 0.78);
    const rx = Math.max(0.65, width * flare);
    const ry = Math.max(0.65, depth * flare);
    const mx = x0 + bend * t * t + Math.sin(z * 0.38) * 0.55;
    const my = y0 + Math.sin(z * 0.23) * 0.35;
    for (let x = Math.floor(mx - rx); x <= Math.ceil(mx + rx); x++) {
      for (let y = Math.floor(my - ry); y <= Math.ceil(my + ry); y++) {
        const d = ((x - mx) / rx) ** 2 + ((y - my) / ry) ** 2;
        if (d <= 1) {
          set(x, y, z, flameShade(z, bottom, top, d > 0.72));
        }
      }
    }
  }
}

// Side licks frame a taller central flame.
tongue(18, 23, 10, 30, 4.6, 3.5, -3);
tongue(30, 24, 10, 34, 5.0, 3.8, 3);
tongue(24, 24, 9, 40, 7.2, 5.7, -1.2);

// Bright, readable heart on the front of the fire
for (let z = 14; z <= 32; z++) {
  const t = (z - 14) / 18;
  const radius = (1 - t) * 3.3 + 0.6;
  const mid = 24 + Math.sin(z * 0.32) * 0.7;
  for (let x = Math.ceil(mid - radius); x <= Math.floor(mid + radius); x++) {
    const y = z < 23 ? 18 : 20;
    set(x, y, z, z < 19 ? "#f88826" : z < 28 ? "#ffd044" : "#fff0a0");
  }
}

animate("flame", {
  type: "colors",
  palette: ["#b72f20", "#ef6c21", "#ffc038", "#fff0a0"],
  pattern: "flicker",
  glow: 0.8
});
animate("flame", { type: "bob", axis: "z", amplitude: 1, speed: 4 });
part("body");