fogón

← Basics3D assetfogon/tetera

Tetera

by fogonCC010922 blocks
TeteraDrag to turn it
// «Tetera» · gpt-6-sol (medium)
// Teapot («Tetera»).

// Porcelain teapot with cobalt-blue trim.
const ivory = "#eee9dc";
const light = "#faf7ec";
const cream = "#d9d2c2";
const shadow = "#bdb6a8";
const blue = "#204d7e";
const brightBlue = "#35699b";
const darkBlue = "#17395f";

function disk(cx, cy, z, rx, ry, color) {
  for (let x = Math.ceil(cx - rx); x <= cx + rx; x++)
    for (let y = Math.ceil(cy - ry); y <= cy + ry; y++)
      if (((x - cx) / rx) ** 2 + ((y - cy) / ry) ** 2 <= 1)
        set(x, y, z, color);
}

// The handle sits behind the rounded body. Its open center is important
// to the teapot's silhouette.
const handle = [
  [12, 23, 25], [9, 23, 25], [6, 23, 23],
  [4, 23, 20], [3, 23, 16], [3, 23, 12],
  [5, 23, 8], [8, 23, 6], [12, 23, 6]
];
for (let i = 0; i < handle.length - 1; i++) {
  line(...handle[i], ...handle[i + 1], 2.1, darkBlue);
  line(handle[i][0], 21, handle[i][2],
       handle[i + 1][0], 21, handle[i + 1][2], 1.25, blue);
}
line(5, 20, 19, 5, 20, 13, 0, brightBlue);
line(7, 20, 22, 11, 20, 24, 0, brightBlue);
line(6, 20, 8, 11, 20, 6, 0, brightBlue);

// Small raised foot, with a dark-blue edge below the pot.
disk(23, 24, 0, 8.5, 6.5, darkBlue);
disk(23, 24, 1, 9.2, 7.0, blue);
disk(23, 24, 2, 9.4, 7.2, brightBlue);
disk(23, 24, 3, 9.1, 6.9, cream);
disk(23, 24, 4, 9.7, 7.3, ivory);

// Full, slightly flattened porcelain belly.
const cx = 23, cy = 24, cz = 15;
for (let z = 5; z <= 25; z++) {
  const taper = Math.sqrt(Math.max(0, 1 - ((z - cz) / 11.3) ** 2));
  const rx = 13.5 * taper + 0.8;
  const ry = 10.3 * taper + 0.5;
  for (let x = Math.ceil(cx - rx); x <= cx + rx; x++) {
    for (let y = Math.ceil(cy - ry); y <= cy + ry; y++) {
      const d = ((x - cx) / rx) ** 2 + ((y - cy) / ry) ** 2;
      if (d > 1) continue;
      const angle = Math.atan2((y - cy) / ry, (x - cx) / rx);
      const ribs = Math.cos(angle * 23);
      let color = z >= 19 ? light : ivory;
      if (y > cy + 3 || z < 9) color = cream;
      if (y < cy - 3 && ribs > 0.68 && z >= 9 && z <= 23)
        color = light;
      if (y < cy - 3 && ribs < -0.72 && d > 0.76 && z >= 9 && z <= 23)
        color = cream;
      if (d > 0.89 && y > cy && rand() < 0.16) color = shadow;
      set(x, y, z, color);
    }
  }
}

// Pronounced vertical flutes across the visible front of the porcelain.
for (let a = 3.35; a < 6.12; a += 0.235) {
  for (let z = 9; z <= 23; z++) {
    const taper = Math.sqrt(Math.max(0, 1 - ((z - cz) / 11.3) ** 2));
    const x = Math.round(cx + (13.5 * taper + 0.6) * Math.cos(a));
    const y = Math.round(cy + (10.3 * taper + 0.6) * Math.sin(a));
    set(x, y, z, z > 19 ? light : ivory);
    if (z > 10 && z < 22 && Math.cos(a * 23) < 0)
      set(x, y + 1, z, cream);
  }
}

// Layered lid: cobalt rim, broad pale top, and patterned inner ring.
disk(23, 24, 25, 12.5, 9.1, darkBlue);
disk(23, 24, 26, 12.8, 9.5, blue);
disk(23, 24, 27, 11.6, 8.4, brightBlue);
disk(23, 24, 28, 10.5, 7.4, ivory);
disk(23, 24, 29, 8.5, 5.9, light);
for (let a = 0; a < Math.PI * 2; a += 0.13) {
  const r = 7.1 + (Math.sin(a * 12) > 0 ? 0.8 : 0);
  set(23 + r * Math.cos(a), 24 + r * 0.7 * Math.sin(a), 30,
      Math.sin(a * 12) > 0 ? cream : blue);
}
disk(23, 24, 31, 4.2, 3.2, cream);
disk(23, 24, 32, 3.1, 2.5, blue);
disk(23, 24, 33, 2.6, 2.4, darkBlue);
disk(23, 24, 34, 2.4, 2.1, blue);
disk(23, 24, 35, 2.0, 1.8, brightBlue);
set(23, 22, 35, light);

// Narrow porcelain spout curves upward to a squared blue lip.
line(34, 24, 17, 37, 24, 19, 2.6, cream);
line(37, 24, 19, 39, 24, 24, 2.3, ivory);
line(39, 24, 24, 40, 24, 31, 1.8, ivory);
line(40, 24, 31, 41, 24, 34, 1.5, cream);
line(38, 21, 21, 40, 21, 29, 0, light);
box(40, 21, 33, 44, 27, 35, blue);
box(41, 22, 35, 45, 26, 36, brightBlue);
box(42, 22, 34, 44, 24, 35, darkBlue);
box(44, 23, 33, 45, 26, 34, darkBlue);

// A hand-painted cobalt scroll on the front-right of the belly.
function front(x, z) {
  const taper = Math.sqrt(Math.max(0, 1 - ((z - cz) / 11.3) ** 2));
  const rx = 13.5 * taper + 0.8;
  const ry = 10.3 * taper + 0.5;
  const f = 1 - ((x - cx) / rx) ** 2;
  return f > 0 ? Math.round(cy - ry * Math.sqrt(f)) - 1 : null;
}
function paint(x, z, color = blue) {
  const y = front(x, z);
  if (y !== null) {
    set(x, y, z, color);
    set(x, y + 1, z, color);
  }
}
for (let a = 0; a < Math.PI * 2; a += 0.16) {
  paint(Math.round(30 + 3.1 * Math.cos(a)),
        Math.round(14 + 4.7 * Math.sin(a)), blue);
}
for (let z = 12; z <= 16; z++) paint(30, z, darkBlue);
paint(29, 17, brightBlue);
paint(31, 11, brightBlue);
paint(33, 19, blue);
paint(34, 18, blue);
paint(27, 19, blue);
paint(28, 20, brightBlue);
paint(33, 9, darkBlue);
paint(32, 8, blue);