fogón

← Nature3D assetfogon/palmera

Palmera

by fogonCC02333 blocks
PalmeraDrag to turn it
// «Palmera» · gpt-6-sol (medium)
// A tropical palm tree: a tall gently curved trunk made of stacked ring segments in tan and light brown, topped by 6-7 long arching bright green fronds drooping outward in a star, with 3 brown coconuts clustered under the fronds.

const bark = ["#a96b39", "#bd8046", "#ce9253", "#dda365"];
const groove = "#88542f";
const leafDark = "#279640";
const leafMid = "#38b84b";
const leafBright = "#59d65a";
const leafSun = "#83e673";

// A gently bending trunk built from short, rounded bark rings.
function trunkCenter(z) {
  const t = z / 35;
  return [23 + 4 * t * t, 25 - 2 * t + 0.25 * Math.sin(t * 7)];
}

for (let z = 0; z <= 35; z++) {
  const [cx, cy] = trunkCenter(z);
  const radius = z < 4 ? 3.0 - z * 0.18 : 2.35;
  for (let x = Math.floor(cx - radius); x <= Math.ceil(cx + radius); x++) {
    for (let y = Math.floor(cy - radius); y <= Math.ceil(cy + radius); y++) {
      const d = Math.hypot(x - cx, y - cy);
      if (d > radius) continue;
      const ring = z % 4 === 0 && d > radius - 1.15;
      const shade = y < cy - 0.5 ? 2 : (x < cx ? 1 : 0);
      let color = ring ? groove : bark[Math.min(3, shade + (rand() < 0.12 ? 1 : 0))];
      if (z % 4 === 1 && d > radius - 0.7 && y < cy) color = bark[3];
      set(x, y, z, color);
    }
  }
}

// Short, splayed roots anchor the tree to the ground.
for (const a of [0.25, 2.25, 3.65, 5.15]) {
  const dx = Math.cos(a), dy = Math.sin(a);
  line(23, 25, 2, 23 + dx * 4, 25 + dy * 4, 0, 1, "#a96b39");
  set(23 + dx * 4, 25 + dy * 4, 0, "#ce9253");
}

part("crown", [27, 23, 35]);

// Seven broad, feather-edged fronds arc up, then droop at their tips.
const cx = 27, cy = 23;
function leafHeight(r) {
  return 35 + 0.76 * r - 0.061 * r * r;
}
for (let i = 0; i < 7; i++) {
  const a = i * Math.PI * 2 / 7;
  const dx = Math.cos(a), dy = Math.sin(a);
  const sx = -dy, sy = dx;

  for (let r = 1; r <= 19.5; r += 0.65) {
    const width = Math.max(0.45, 3.25 * Math.sin(Math.PI * r / 20));
    const z = Math.round(leafHeight(r));

    for (let side = -width; side <= width; side += 0.8) {
      const x = Math.round(cx + dx * r + sx * side);
      const y = Math.round(cy + dy * r + sy * side);
      const edge = Math.abs(side) / width;
      set(x, y, z - 1, leafDark);
      set(x, y, z,
        edge < 0.23 ? leafSun :
        edge < 0.72 ? (rand() < 0.22 ? leafSun : leafBright) :
        leafMid
      );
    }
  }

  // Alternating pointed leaflets give each frond its palm-leaf outline.
  for (let r = 5; r < 18; r += 2.2) {
    const width = 3.25 * Math.sin(Math.PI * r / 20);
    for (const side of [-1, 1]) {
      const startX = cx + dx * r + sx * side * (width - 0.4);
      const startY = cy + dy * r + sy * side * (width - 0.4);
      const endX = cx + dx * (r + 1.1) + sx * side * (width + 2.0);
      const endY = cy + dy * (r + 1.1) + sy * side * (width + 2.0);
      line(startX, startY, leafHeight(r),
           endX, endY, leafHeight(r + 1.1) - 0.7, 0, leafBright);
    }
  }
}

ellipsoid(27, 23, 35, 2.7, 2.7, 1.7, "#39ad45");
set(27, 23, 37, leafSun);

// Three coconuts hang visibly beneath the canopy.
for (const [x, y, z] of [[25, 21, 33], [29, 22, 33], [27, 25, 32]]) {
  ellipsoid(x, y, z, 1.65, 1.65, 1.55, "#754626");
  set(x, y - 1, z, "#a46a37");
  set(x - 1, y, z + 1, "#bd8046");
  set(x, y, z + 1, "#ca9050");
  set(x, y - 1, z - 1, "#593820");
}

animate("crown", { type: "swing", axis: "y", speed: 1.5, amplitude: 0.12 });