fogón

← MedievalObjeto 3Dfogon/balista

Balista

de fogonCC05555 bloques
BalistaArrastrá para girarlo
// «Balista» · gpt-6-sol (medium)
// A medieval ballista: a giant crossbow on a wooden base with four small wheels, a thick wooden bow arm with rope string drawn back, a huge bolt with an iron tip and red fletching loaded and pointing forward (-y), and a winch with a crank at the back.

// Medieval ballista, facing -y
const woodDark = "#4b3022";
const wood = "#70472b";
const woodLight = "#a47748";
const woodEdge = "#c09258";
const iron = "#303238";
const ironLight = "#777b7c";
const rope = "#d7bd87";
const red = "#a32d30";
const redLight = "#ce4a40";
const blue = "#263f77";
const gold = "#d6aa51";

// Four small, iron-bound wooden wheels. Their bottoms touch the floor.
for (const wx of [11, 37]) {
  for (const wy of [15, 36]) {
    const outerX = wx < 24 ? wx - 2 : wx + 2;
    for (let i = 0; i < 32; i++) {
      const a = i * Math.PI * 2 / 32;
      const b = (i + 1) * Math.PI * 2 / 32;
      for (const dx of [-1, 0, 1]) {
        line(wx + dx, wy + 4 * Math.cos(a), 4 + 4 * Math.sin(a),
             wx + dx, wy + 4 * Math.cos(b), 4 + 4 * Math.sin(b),
             0.65, dx === 0 ? woodLight : woodDark);
      }
      line(outerX, wy + 4 * Math.cos(a), 4 + 4 * Math.sin(a),
           outerX, wy + 4 * Math.cos(b), 4 + 4 * Math.sin(b),
           0.45, iron);
    }
    for (let i = 0; i < 8; i++) {
      const a = i * Math.PI / 4;
      line(wx, wy, 4,
           wx, wy + 3.7 * Math.cos(a), 4 + 3.7 * Math.sin(a),
           0.7, wood);
    }
    cylinder(wx - 2, wy, 4, 1.4, 5, iron, "x");
    set(outerX, wy, 4, ironLight);
  }
}

// Axles, heavy chassis and individually visible deck planks.
for (const y of [15, 36]) {
  line(10, y, 4, 38, y, 4, 1, iron);
  box(14, y - 1, 6, 34, y + 1, 8, woodDark);
}
for (const x of [15, 31]) {
  box(x, 12, 7, x + 2, 41, 10, woodDark);
  box(x, 12, 10, x + 2, 41, 10, woodLight);
}
for (let x = 18; x <= 30; x += 3) {
  box(x, 13, 8, x + 2, 40, 10, x % 2 ? wood : woodLight);
  line(x, 13, 11, x, 40, 11, 0, woodDark);
}
for (const y of [13, 39]) {
  box(14, y, 8, 34, y + 2, 11, woodDark);
  box(15, y, 11, 33, y + 1, 11, woodEdge);
  for (const x of [16, 22, 28, 33]) set(x, y, 11, ironLight);
}

// Diagonal braces and the elevated bolt trough.
for (const x of [17, 31]) {
  line(x, 14, 10, x, 22, 15, 1.2, wood);
  line(x, 37, 10, x, 25, 15, 1.2, woodDark);
  box(x - 1, 19, 12, x + 1, 22, 15, wood);
  box(x - 1, 19, 15, x + 1, 20, 15, iron);
}
box(21, 12, 12, 27, 38, 15, woodDark);
box(22, 13, 15, 26, 36, 16, woodLight);
for (const x of [21, 27]) {
  line(x, 12, 16, x, 37, 16, 0.6, iron);
}
box(19, 32, 13, 29, 34, 16, woodDark); // catch for the drawn string
for (const x of [19, 29]) box(x, 32, 15, x, 34, 17, iron);

// The broad, forward-swept wooden bow.
for (const side of [-1, 1]) {
  const X = d => 24 + side * d;
  line(X(0), 21, 17, X(10), 19, 17, 2.1, woodDark);
  line(X(10), 19, 17, X(18), 15, 17, 1.9, wood);
  line(X(18), 15, 17, X(20), 13, 17, 1.35, woodDark);
  line(X(2), 21, 19, X(10), 19, 19, 0.6, woodEdge);
  line(X(11), 18, 19, X(17), 15, 19, 0.5, woodLight);
  for (const d of [5, 11, 16]) {
    const y = d < 10 ? 20 : d < 15 ? 18 : 16;
    line(X(d), y - 1, 15, X(d), y + 1, 19, 0.55, iron);
    set(X(d), y, 19, ironLight);
  }
  box(X(20) - 1, 12, 16, X(20) + 1, 14, 18, iron);
  set(X(20), 13, 19, gold);
}

// Pale rope drawn taut to the rear catch, forming the crossbow's V.
line(4, 13, 18, 24, 34, 18, 0.55, rope);
line(44, 13, 18, 24, 34, 18, 0.55, rope);
sphere(24, 34, 18, 1, gold);

// Loaded siege bolt, above the trough, aimed straight at the viewer.
line(24, 10, 19, 24, 35, 19, 1.2, woodDark);
line(24, 11, 20, 24, 33, 20, 0.45, woodEdge);
for (const y of [15, 25, 32]) {
  box(23, y, 18, 25, y, 19, iron);
  set(24, y, 20, ironLight);
}
// Chunky tapered iron point.
box(22, 9, 18, 26, 11, 20, iron);
box(23, 7, 18, 25, 9, 20, ironLight);
box(24, 5, 19, 24, 7, 19, "#bdc0b9");

// Large red fletching, with two side vanes and an upright vane.
for (const side of [-1, 1]) {
  for (let y = 29; y <= 35; y++) {
    const width = y < 31 ? 2 : y < 34 ? 4 : 3;
    for (let d = 2; d <= width; d++) {
      set(24 + side * d, y, 19, d === width ? redLight : red);
      if (d < width) set(24 + side * d, y, 20, red);
    }
  }
}
for (let y = 30; y <= 35; y++) {
  const h = y < 32 ? 2 : 4;
  for (let z = 21; z <= 20 + h; z++)
    set(24, y, z, z === 20 + h ? redLight : red);
}

// Small royal-blue heraldic panels on either flank of the carriage.
for (const x of [14, 34]) {
  box(x, 24, 9, x, 30, 13, gold);
  box(x, 25, 10, x, 29, 12, blue);
  for (let y = 26; y <= 28; y++) set(x, y, 11, red);
  set(x, 27, 12, gold);
}
for (const y of [18, 27, 35]) {
  for (const x of [15, 33]) set(x, y, 10, ironLight);
}

// Fixed iron bearing for the winch at the rear right.
box(32, 36, 13, 38, 40, 18, woodDark);
box(35, 37, 14, 39, 39, 17, iron);
set(39, 38, 16, ironLight);

// Only the crank wheel moves; its pivot is exactly at the axle.
part("crank", [39, 38, 16]);
for (let i = 0; i < 32; i++) {
  const a = i * Math.PI * 2 / 32;
  const b = (i + 1) * Math.PI * 2 / 32;
  line(40, 38 + 4 * Math.cos(a), 16 + 4 * Math.sin(a),
       40, 38 + 4 * Math.cos(b), 16 + 4 * Math.sin(b),
       0.7, iron);
}
for (let i = 0; i < 6; i++) {
  const a = i * Math.PI / 3;
  line(40, 38, 16,
       40, 38 + 3.8 * Math.cos(a), 16 + 3.8 * Math.sin(a),
       0.6, woodLight);
}
cylinder(39, 38, 16, 1.2, 3, gold, "x");
line(41, 41, 18, 44, 41, 18, 0.8, iron);
box(43, 40, 17, 45, 42, 19, woodLight);
animate("crank", { type: "spin", axis: "x", speed: 2 });