fogón

← Fantasy3D assetfogon/escoba-voladora

Escoba voladora

by fogonCC02843 blocks
Escoba voladoraDrag to turn it
// «Escoba voladora» · gpt-6-sol (medium)
// A big chunky witch's flying broom floating horizontally in the air, long along x and spanning about 44 blocks from end to end. The handle is THICK: a 2-block radius round dark brown wooden pole, slightly crooked, with a bigger round knob at the front end and a red cloth band near the middle. The back third is a HUGE, bushy, fan-shaped bundle of golden-yellow straw: it flares from 6 blocks wide at the tie to about 18 blocks wide and 16 blocks tall at its back end (like a cone lying on its side), made of many straw strands in 3 shades of yellow and ochre, tied with a dark twine band where it meets the handle. A trail of a few glowing violet star sparkles behind the bristles. The broom floats about 6 blocks above the floor with a small grey shadow ellipse on the floor below it. The broom should look heavy and chunky, not thin.

// A soft shadow stays on the floor while the broom floats above it.
for (let x = 5; x <= 43; x++) {
  for (let y = 17; y <= 31; y++) {
    const d = ((x - 24) / 19) ** 2 + ((y - 24) / 7) ** 2;
    if (d < 1 && rand() > (d > 0.82 ? 0.32 : 0.06)) {
      set(x, y, 0, d > 0.7 ? "#77727b" : "#55515d");
    }
  }
}

part("broom", [24, 24, 16]);

// Thick, gently crooked wooden handle.
const center = x => {
  if (x < 14) return [24, 16];
  if (x < 22) return [24 + (x - 14) / 8, 16 + (x - 14) / 8];
  return [25 - (x - 22) / 10, 17 - (x - 22) / 10];
};

for (let x = 5; x <= 32; x++) {
  const [cy, cz] = center(x);
  for (let y = 20; y <= 28; y++) {
    for (let z = 12; z <= 21; z++) {
      const d = ((y - cy) / 2.35) ** 2 + ((z - cz) / 2.35) ** 2;
      if (d <= 1) {
        let color = z > cz + 0.5 ? "#765032" : z < cz - 1 ? "#39251f" : "#563722";
        if (rand() < 0.09) color = "#835536";
        set(x, y, z, color);
      }
    }
  }
}
// Long, visible wood-grain strokes on the front of the pole.
for (let x = 8; x < 29; x++) {
  const [cy, cz] = center(x);
  if (x % 7 !== 0) {
    set(x, Math.round(cy - 2), Math.round(cz), x % 5 < 3 ? "#95633b" : "#33221c");
    if (x % 4 < 2) set(x, Math.round(cy - 1), Math.round(cz + 2), "#a07146");
  }
}

// Oversized rounded front knob.
sphere(5, 24, 16, 3.4, "#432a22");
sphere(5, 23, 17, 2.5, "#71482e");
for (let y = 22; y <= 26; y++)
  for (let z = 14; z <= 18; z++)
    if ((y - 24) ** 2 + (z - 16) ** 2 < 5 && get(2, y, z))
      set(2, y, z, "#34211e");
set(4, 21, 18, "#b17a4c");
set(5, 21, 19, "#a36c41");

// A bright red cloth grip, with warm brass edging.
for (let x = 18; x <= 21; x++) {
  const [cy, cz] = center(x);
  for (let y = 20; y <= 28; y++)
    for (let z = 12; z <= 21; z++) {
      const d = ((y - cy) / 2.65) ** 2 + ((z - cz) / 2.65) ** 2;
      if (d <= 1) {
        set(x, y, z, x === 18 || x === 21 ? "#b88341" :
          z > cz ? "#d44b50" : "#8e2938");
      }
    }
}
line(19, 22, 17, 20, 22, 18, 0, "#f18b72");

// Solid, dramatically flared straw bundle.
for (let x = 29; x <= 44; x++) {
  const t = Math.max(0, (x - 30) / 14);
  const ry = 2.8 + 6.3 * t;
  const rz = 2.7 + 5.3 * t;
  for (let y = 14; y <= 34; y++) {
    for (let z = 7; z <= 25; z++) {
      const d = ((y - 24) / ry) ** 2 + ((z - 16) / rz) ** 2;
      if (d <= 1 && (d < 0.89 || rand() > 0.15)) {
        let color = z > 17 ? "#e7ae3e" : z < 13 ? "#93631f" : "#c78e2b";
        if (rand() < 0.18) color = z > 16 ? "#f5cb65" : "#ad7624";
        set(x, y, z, color);
      }
    }
  }
}

// Individual long straw ridges follow the front and upper surface.
for (let strand = 0; strand < 48; strand++) {
  const angle = -1.35 + strand * 2.8 / 47;
  const bright = ["#f5cf69", "#e9b647", "#bd8228", "#ffe08a"][strand % 4];
  const end = 42 + Math.floor(rand() * 4);
  for (let x = 33; x <= end; x++) {
    const t = (x - 30) / 14;
    const ry = 2.8 + 6.3 * t;
    const rz = 2.7 + 5.3 * t;
    const y = Math.round(24 - ry * Math.cos(angle));
    const z = Math.round(16 + rz * Math.sin(angle));
    if (x <= 44 || rand() > 0.35) set(x, y, z, bright);
    if (x > 38 && strand % 5 === 0 && rand() > 0.35)
      set(x, y, z + 1, "#a97122");
  }
}
// Uneven pale ends make the back read as a bundle of separate stalks.
for (let i = 0; i < 34; i++) {
  const a = rand() * Math.PI * 2;
  const r = Math.sqrt(rand());
  const y = Math.round(24 + 8.5 * r * Math.cos(a));
  const z = Math.round(16 + 7.5 * r * Math.sin(a));
  set(44 + (rand() > 0.57 ? 1 : 0), y, z,
      i % 3 === 0 ? "#fff0a4" : i % 3 === 1 ? "#e8ae38" : "#a87324");
}

// Heavy dark twine binding at the narrow end.
for (let x = 30; x <= 32; x++) {
  for (let y = 20; y <= 28; y++)
    for (let z = 12; z <= 20; z++)
      if (((y - 24) / 3.35) ** 2 + ((z - 16) / 3.35) ** 2 <= 1)
        set(x, y, z, x === 31 ? "#382922" : "#59402a");
}
for (let x = 30; x <= 32; x++) {
  set(x, 21, 17 + (x % 2), "#a2783e");
  set(x, 24, 19, "#98723c");
}
box(31, 20, 15, 32, 20, 17, "#39271f");
set(31, 19, 16, "#c39749");

animate("broom", { type: "bob", axis: "z", speed: 2, amplitude: 2 });

// The sparkles bob in lockstep, but have their own flickering colors.
part("sparkles", [24, 24, 16]);
const stars = [[46, 11, 24], [46, 37, 22], [47, 13, 12], [46, 35, 10]];
for (const [x, y, z] of stars) {
  set(x, y, z, "#ffffff");
  set(x, y - 1, z, "#dc6cff");
  set(x, y + 1, z, "#b344f1");
  set(x, y, z - 1, "#9c3bd9");
  set(x, y, z + 1, "#f4a1ff");
  if (x < 47) set(x + 1, y, z, "#cd63ff");
}
set(45, 9, 19, "#d870ff");
set(47, 32, 27, "#f8adff");
animate("sparkles", { type: "bob", axis: "z", speed: 2, amplitude: 2 });
animate("sparkles", {
  type: "colors",
  palette: ["#9631e8", "#d441ef", "#ffffff", "#f29aff"],
  pattern: "flicker",
  glow: 0.85
});