fogón

← City3D assetfogon/colectivo-urbano

Colectivo

by fogonCC020805 blocks
ColectivoDrag to turn it
// «Colectivo» · gpt-6-sol (medium)
// A Buenos Aires city bus (colectivo): a long boxy bus along y painted in bright fileteado-inspired colors (red and cream with a blue stripe), a big front windshield at -y with a route number sign on top, a row of side windows, a front door and a rear door, and six black wheels.

const C = {
  red: "#d73539", redLight: "#ed4945", redDark: "#a92430",
  cream: "#f6e7bd", creamLight: "#fff2d1", creamShade: "#dfcca1",
  blue: "#2179b8", blueLight: "#50a7d2", blueDark: "#155586",
  gold: "#f5bb48", glass: "#86cadd", glassDark: "#397b9c",
  frame: "#253b49", tire: "#20242a", tread: "#30343a",
  hub: "#bec7c6", metal: "#889599"
};

// Long, solid coach body. The front faces -y.
box(14, 4, 5, 34, 44, 20, C.cream);
box(14, 4, 5, 34, 44, 10, C.red);
box(14, 4, 19, 34, 44, 21, C.red);
box(13, 4, 6, 13, 44, 21, C.cream);
box(35, 4, 6, 35, 44, 21, C.cream);
for (const x of [13, 35]) {
  box(x, 4, 6, x, 44, 10, C.red);
  box(x, 4, 19, x, 44, 21, C.red);
  box(x, 4, 10, x, 44, 11, C.blue);
  box(x, 4, 12, x, 44, 12, C.gold);
  box(x, 4, 18, x, 44, 18, C.creamShade);
  box(x, 4, 21, x, 44, 21, C.redLight);
}
// Flecks in the broad painted panels.
for (let i = 0; i < 165; i++) {
  const y = 5 + Math.floor(rand() * 39);
  const z = 6 + Math.floor(rand() * 4);
  const x = rand() < 0.5 ? 13 : 35;
  if (rand() < 0.28) set(x, y, z, C.redLight);
}

box(14, 4, 22, 34, 44, 22, C.creamLight);
box(15, 5, 23, 33, 43, 23, C.creamShade);
box(17, 12, 24, 31, 17, 24, C.creamLight);
box(18, 13, 25, 30, 16, 25, C.metal);
box(18, 34, 24, 30, 38, 24, C.creamLight);
box(20, 35, 25, 28, 37, 25, C.metal);

// Side windows, with chunky posts and a light-reflecting upper edge.
function sideWindow(x, y0, y1) {
  box(x, y0, 13, x, y1, 17, C.frame);
  box(x + (x < 24 ? -1 : 1), y0 + 1, 14,
      x + (x < 24 ? -1 : 1), y1 - 1, 17, C.glassDark);
  const outer = x < 24 ? x - 1 : x + 1;
  box(outer, y0 + 1, 17, outer, y1 - 1, 17, C.glass);
  set(outer, y0 + 1, 16, C.blueLight);
  box(outer, y0, 13, outer, y1, 13, C.creamLight);
}
for (const [a, b] of [[7, 11], [17, 21], [23, 27], [29, 33], [36, 39], [41, 43]])
  sideWindow(13, a, b);
for (const [a, b] of [[16, 20], [21, 25], [31, 34], [36, 39], [41, 43]])
  sideWindow(35, a, b);

// Two glazed passenger doors on the right side.
function door(y0, y1) {
  box(35, y0, 6, 36, y1, 18, C.frame);
  box(37, y0 + 1, 8, 37, y1 - 1, 17, C.glassDark);
  const mid = Math.floor((y0 + y1) / 2);
  box(38, y0 + 1, 10, 38, mid - 1, 16, C.glass);
  box(38, mid + 1, 10, 38, y1 - 1, 16, C.glass);
  box(38, mid, 7, 38, mid, 18, C.creamLight);
  box(38, y0, 7, 38, y0, 18, C.creamLight);
  box(38, y1, 7, 38, y1, 18, C.creamLight);
  box(38, y0 + 1, 7, 38, y1 - 1, 7, C.gold);
  set(39, mid - 1, 11, C.gold);
  set(39, mid + 1, 11, C.gold);
}
door(6, 12);
door(26, 30);

// Gold, curling fileteado accents on the cream side panels.
for (const x of [12, 36]) {
  for (const y of [13, 28]) {
    set(x, y, 15, C.gold);
    set(x, y + 1, 15, C.gold);
    set(x, y + 1, 16, C.gold);
    set(x, y, 17, C.blue);
    set(x, y - 1, 16, C.redLight);
  }
}

// Front fascia, windshield, and prominent route-number box.
box(15, 3, 6, 33, 3, 21, C.red);
box(16, 2, 12, 32, 2, 19, C.frame);
box(17, 1, 13, 23, 1, 18, C.glassDark);
box(25, 1, 13, 31, 1, 18, C.glassDark);
box(18, 1, 16, 22, 1, 18, C.glass);
box(26, 1, 16, 30, 1, 18, C.glass);
box(24, 1, 12, 24, 1, 19, C.creamLight);
box(17, 1, 12, 31, 1, 12, C.creamLight);
box(18, 0, 20, 30, 1, 24, C.frame);
box(18, 0, 24, 30, 0, 24, C.gold);

// Pixel numerals "152", five blocks tall.
const numerals = [
  ["010", "110", "010", "010", "111"],
  ["111", "100", "111", "001", "111"],
  ["111", "001", "111", "100", "111"]
];
for (let d = 0; d < 3; d++)
  for (let row = 0; row < 5; row++)
    for (let col = 0; col < 3; col++)
      if (numerals[d][row][col] === "1")
        set(20 + d * 4 + col, -0 + 0, 23 - row, C.creamLight);
// Recessed sign face is at y=0; lower windshield remains behind it.
box(17, 1, 10, 31, 1, 10, C.blue);
box(20, 1, 8, 28, 1, 9, C.redDark);
for (const x of [17, 29]) {
  box(x, 0, 7, x + 2, 0, 8, C.creamLight);
  set(x + 1, 0, 7, C.gold);
}
box(15, 0, 5, 33, 1, 5, C.metal);
box(16, 0, 6, 32, 0, 6, C.redDark);
set(15, 1, 17, C.frame);
set(33, 1, 17, C.frame);
box(14, 0, 16, 15, 2, 17, C.frame);
box(33, 0, 16, 34, 2, 17, C.frame);

// Rear window, lights, and bumper.
box(17, 45, 13, 31, 45, 18, C.frame);
box(18, 46, 14, 30, 46, 17, C.glassDark);
box(19, 46, 17, 29, 46, 17, C.glass);
box(15, 45, 6, 33, 45, 11, C.redDark);
for (const x of [16, 31]) {
  box(x, 46, 7, x + 1, 46, 10, C.redLight);
  box(x, 46, 8, x + 1, 46, 8, C.gold);
}
box(15, 46, 5, 33, 46, 5, C.metal);

// Open dark wheel wells, cut into both lower sides.
for (const cy of [14, 34, 41])
  for (const x of [13, 14, 34, 35])
    for (let y = cy - 4; y <= cy + 4; y++)
      for (let z = 5; z <= 8; z++)
        if ((y - cy) ** 2 + (z - 4) ** 2 <= 20)
          set(x, y, z, C.frame);

// Each of the six tires is an independent spinning part.
for (const cy of [14, 34, 41]) {
  for (const side of ["left", "right"]) {
    const left = side === "left";
    const axle = left ? 12 : 36;
    const name = `wheel_${side}_${cy}`;
    part(name, [axle, cy, 4]);
    for (let x = axle - 2; x <= axle + 2; x++)
      for (let y = cy - 4; y <= cy + 4; y++)
        for (let z = 0; z <= 8; z++) {
          const r2 = (y - cy) ** 2 + (z - 4) ** 2;
          if (r2 <= 16)
            set(x, y, z, r2 >= 11 ? C.tread : C.tire);
        }
    const face = left ? axle - 2 : axle + 2;
    for (let y = cy - 2; y <= cy + 2; y++)
      for (let z = 2; z <= 6; z++)
        if ((y - cy) ** 2 + (z - 4) ** 2 <= 5)
          set(face + (left ? -1 : 1), y, z, C.hub);
    set(face + (left ? -2 : 2), cy, 4, C.blueDark);
    for (const [dy, dz] of [[0, 2], [2, 0], [0, -2], [-2, 0]])
      set(face + (left ? -1 : 1), cy + dy, 4 + dz, C.metal);
    animate(name, { type: "spin", axis: "x", speed: 6 });
  }
}
part("body", [24, 24, 0]);