fogón

← Parties and Christmas3D assetfogon/pila-de-regalos

Pila de regalos

by fogonCC018843 blocks
Pila de regalosDrag to turn it
// «Pila de regalos» · gpt-6-sol (medium)
// A cheerful pile of five gift boxes of different sizes stacked and leaning: a big green box with a red ribbon at the bottom, a blue one with silver stripes, a tall purple one, a small yellow cube and a tiny pink box on top. Every box has a crossed ribbon and a little bow in a contrasting color.

// Five cheerful, slightly staggered presents.
function gift(x0, y0, z0, x1, y1, z1, paper, ribbon, spots, bowSize) {
  const cx = Math.floor((x0 + x1) / 2);
  const cy = Math.floor((y0 + y1) / 2);
  const midZ = z0 + Math.floor((z1 - z0) * 0.53);
  const band = (x1 - x0 > 20) ? 3 : (x1 - x0 > 8 ? 2 : 1);

  // Solid wrapping paper, with soft-looking corners and lighter upper faces.
  for (let x = x0; x <= x1; x++)
    for (let y = y0; y <= y1; y++)
      for (let z = z0; z <= z1; z++) {
        const corner = (x === x0 || x === x1) && (y === y0 || y === y1);
        if (corner && (z === z0 || z === z1)) continue;

        let color = paper[0];
        if (z === z1) color = paper[1];
        else if (x === x1 || y === y1) color = paper[2];
        else if (y === y0 || x === x0) color = paper[0];
        if (z !== z0 && z !== z1 && rand() < 0.035) color = paper[1];
        set(x, y, z, color);
      }

  // Sparse printed confetti, kept clear of the ribbon.
  for (let x = x0 + 2; x <= x1 - 2; x++)
    for (let z = z0 + 2; z <= z1 - 2; z++)
      if (Math.abs(x - cx) > band + 2 && Math.abs(z - midZ) > 2 &&
          rand() < 0.075) set(x, y0, z, spots);

  // Crossed ribbon: it runs down both visible sides and across the lid.
  for (let x = x0; x <= x1; x++)
    for (let y = y0; y <= y1; y++) {
      if (Math.abs(x - cx) < band || Math.abs(y - cy) < band)
        set(x, y, z1, ribbon[1]);
    }

  for (let z = z0; z <= z1; z++) {
    for (let x = x0; x <= x1; x++) {
      if (Math.abs(x - cx) < band || Math.abs(z - midZ) < band)
        set(x, y0, z, ribbon[z === z1 ? 1 : 0]);
    }
    for (let y = y0; y <= y1; y++) {
      if (Math.abs(y - cy) < band || Math.abs(z - midZ) < band)
        set(x1, y, z, ribbon[2]);
    }
  }

  // Bright narrow highlights make the ribbons look shiny.
  for (let z = z0 + 1; z < z1; z++) {
    if (Math.abs(z - midZ) >= band) set(cx - 1, y0 - 1, z, ribbon[1]);
  }
  for (let y = y0 + 1; y < y1; y++) set(cx - 1, y, z1 + 1, ribbon[1]);
  for (let x = x0 + 1; x < x1; x++) set(x, cy - 1, z1 + 1, ribbon[1]);

  // A bow sits just in front of the lid, where the next present cannot hide it.
  const by = y0 - 2;
  const bz = z1;
  const w = bowSize;
  const h = Math.min(bowSize, z1 >= 44 ? 1 : 3);
  for (const side of [-1, 1]) {
    line(cx, by, bz + 1, cx + side * w, by, bz + h, 0, ribbon[2]);
    line(cx + side * w, by, bz + h, cx + side * (w + 1), by, bz + 1, 0, ribbon[1]);
    line(cx + side * (w + 1), by, bz + 1, cx, by, bz, 0, ribbon[0]);
    if (w > 2) {
      line(cx + side, by - 1, bz + 1,
           cx + side * (w - 1), by - 1, bz + h, 0, ribbon[1]);
    }
    line(cx, by, bz, cx + side * Math.max(1, w - 1), by, bz - 2, 0, ribbon[0]);
  }
  box(cx - 1, by - 1, bz, cx + 1, by, bz + 1, ribbon[1]);
  set(cx, by - 2, bz + 1, spots);
}

gift(7, 9, 0, 39, 38, 10,
  ["#28b95a", "#65e984", "#188e49"],
  ["#d92739", "#ff6262", "#ab2037"], "#b9ffc5", 4);

gift(11, 11, 11, 34, 33, 20,
  ["#308cde", "#76c5ff", "#2464b4"],
  ["#bccbd8", "#ffffff", "#829eaf"], "#d7efff", 3);

gift(20, 14, 21, 30, 25, 32,
  ["#9254cb", "#c59aee", "#693ea4"],
  ["#e6a92f", "#ffe477", "#b97b22"], "#f4d9ff", 3);

gift(17, 13, 33, 24, 20, 39,
  ["#f6d54a", "#fff18d", "#d6a832"],
  ["#26bdbd", "#8cf5e2", "#168c99"], "#fff8cc", 2);

gift(21, 15, 40, 26, 20, 44,
  ["#f28fba", "#ffd0df", "#d56b9d"],
  ["#54cba1", "#b9ffce", "#309878"], "#ffffff", 2);