fogón

← Pirates and sea3D assetfogon/coral

Coral

by fogonCC010508 blocks
CoralDrag to turn it
// «Coral» · gpt-6-sol (medium)
// A colorful coral cluster: pink branching coral, an orange brain coral dome, purple fan coral and a few yellow tube corals on a sandy base.

// Sunlit sand, broad enough to anchor the whole reef.
for (let z = 0; z <= 3; z++) {
  const rx = 21 - z * 0.9, ry = 19 - z * 0.9;
  for (let x = 2; x <= 46; x++) for (let y = 3; y <= 45; y++) {
    if (((x - 24) / rx) ** 2 + ((y - 24) / ry) ** 2 <= 1) {
      const n = rand();
      set(x, y, z, z === 3
        ? (n < 0.15 ? "#f8dfa0" : n < 0.29 ? "#d9ae70" : "#edca89")
        : (n < 0.12 ? "#c99d65" : "#dfb77b"));
    }
  }
}

// The sea fan is its own gently swaying piece, rooted behind the corals.
part("fan", [25, 34, 5]);
line(25, 34, 4, 25, 34, 14, 2, "#7540a4");
line(25, 33, 9, 25, 33, 17, 1, "#b871dd");

const fanTips = [
  [12, 28], [15, 33], [19, 36], [25, 37],
  [31, 36], [36, 33], [39, 27]
];
for (const [x, z] of fanTips) {
  line(25, 34, 12, x, 34, z, 1, "#8e4ab9");
  line(25, 33, 13, x, 33, z, 0, "#cf84e9");
}
for (let z = 17; z <= 34; z += 3) {
  const w = Math.min(13, Math.floor((z - 10) * 0.68));
  for (let x = 25 - w; x <= 25 + w; x++) {
    if (z <= 37 - 0.052 * (x - 25) ** 2) {
      set(x, 34, z, "#a557ca");
      if (x % 4 === 0) set(x, 33, z, "#d17bea");
    }
  }
}
for (let z = 19; z <= 31; z += 3) {
  for (let x = 16; x <= 34; x += 4) {
    if (Math.abs(x - 25) < (z - 10) * 0.68 &&
        z + 3 <= 37 - 0.052 * (x - 25) ** 2) {
      line(x, 34, z, x + (x < 25 ? -2 : 2), 34, z + 3, 0, "#b76bd9");
    }
  }
}
for (let x = 12; x <= 39; x++) {
  const z = Math.round(37 - 0.052 * (x - 25) ** 2);
  if (z >= 27) set(x, 34, z, "#d083ea");
}
animate("fan", { type: "swing", axis: "y", speed: 1.5, amplitude: 0.15 });
part("body");

// Chunky pink branching coral on the left.
const branches = [
  [[14, 21, 4], [15, 21, 14], 3],
  [[15, 21, 13], [13, 21, 23], 2],
  [[13, 21, 22], [11, 20, 32], 2],
  [[13, 21, 22], [17, 20, 30], 2],
  [[15, 21, 15], [20, 19, 21], 2],
  [[20, 19, 21], [21, 18, 30], 2],
  [[20, 19, 21], [24, 20, 27], 1],
  [[15, 21, 12], [9, 19, 19], 2],
  [[9, 19, 19], [7, 18, 27], 2],
  [[9, 19, 19], [11, 17, 25], 1],
  [[13, 21, 23], [9, 23, 29], 1],
  [[17, 20, 30], [17, 19, 35], 1],
  [[17, 20, 30], [20, 21, 34], 1],
  [[21, 18, 30], [24, 17, 34], 1]
];
for (const [a, b, r] of branches) {
  line(...a, ...b, r, "#e96b9f");
  sphere(...b, r + 0.45, "#f48ab3");
  if (r >= 2) {
    line(a[0], a[1] - 1, a[2] + 1,
         b[0], b[1] - 1, b[2], 0, "#ffadc8");
  }
}
for (const [x, y, z] of [[11,20,32],[17,19,35],[20,21,34],[24,17,34],
                            [7,18,27],[21,18,30]]) {
  sphere(x, y, z, 1.3, "#ffb0c8");
}

// Orange brain coral: a solid rounded dome with winding raised folds.
cylinder(33, 24, 4, 8, 5, "#c65a2c");
ellipsoid(33, 24, 9, 10, 8, 12, "#ed8237");
ellipsoid(33, 23, 10, 9, 7, 10, "#fa9c43");

for (let y = 17; y <= 29; y += 3) {
  for (let x = 25; x <= 41; x++) {
    const yy = y + Math.round(Math.sin(x * 0.85 + y) * 0.8);
    const q = ((x - 33) / 10) ** 2 + ((yy - 24) / 8) ** 2;
    if (q < 0.91) {
      const z = Math.round(9 + 12 * Math.sqrt(1 - q));
      set(x, yy, z + 1, "#c9652d");
      if (q < 0.83) set(x, yy + 1, z + 1, "#ffc066");
    }
  }
}
// Furrows curl down its viewer-facing side.
for (let x0 = 27; x0 <= 39; x0 += 3) {
  for (let z = 9; z <= 17; z++) {
    const x = x0 + Math.round(Math.sin(z * 0.68 + x0) * 0.7);
    const q = ((x - 33) / 10) ** 2 + ((z - 9) / 12) ** 2;
    if (q < 0.92) {
      const y = Math.round(24 - 8 * Math.sqrt(1 - q));
      set(x, y - 1, z, "#bd5c2b");
      set(x + 1, y - 1, z, "#ffb552");
    }
  }
}

// Yellow trumpet-shaped tube corals, their dark openings visible from above.
function tube(x, y, height, radius) {
  for (let z = 4; z < height - 2; z++) {
    const bendX = Math.round(Math.sin(z * 0.32 + x) * 0.7);
    cylinder(x + bendX, y, z, radius - 1, 1,
      z % 4 === 0 ? "#d69224" : "#f2b832");
    set(x + bendX, y - radius + 1, z, "#ffdb59");
  }
  const bx = x + Math.round(Math.sin((height - 3) * 0.32 + x) * 0.7);
  cylinder(bx, y, height - 3, radius + 0.3, 2, "#f3b52a");
  for (let dx = -radius - 1; dx <= radius + 1; dx++)
    for (let dy = -radius - 1; dy <= radius + 1; dy++) {
      const d = Math.hypot(dx, dy);
      if (d <= radius + 0.6) {
        set(bx + dx, y + dy, height - 1,
            d < radius - 0.25 ? "#9a5926" : "#ffdc51");
        if (d >= radius - 0.55 && d <= radius + 0.6)
          set(bx + dx, y + dy, height, "#ffe36c");
      }
    }
}
tube(25, 12, 17, 3);
tube(30, 10, 13, 2);
tube(40, 17, 13, 2);
tube(8, 29, 12, 2);

// Shells, golden sand flecks and a few turquoise bits of sea glass.
for (const [x, y, z, c] of [
  [18, 11, 4, "#fff1c2"], [19, 11, 4, "#fff1c2"],
  [36, 12, 4, "#74d6cb"], [37, 12, 4, "#a0e6d5"],
  [5, 24, 2, "#ffdf84"], [6, 25, 3, "#fff0ae"],
  [30, 39, 2, "#82d9ce"], [31, 39, 2, "#a3e8d8"],
  [42, 29, 2, "#fff0bd"], [41, 30, 3, "#ffdc84"]
]) set(x, y, z, c);