← City3D assetfogon/puesto-de-choripan
Puesto de choripán
Drag to turn it// «Puesto de choripán» · gpt-6-sol (medium)
// A street choripán stand: a small cart with a big black iron grill on top full of sausages and bread rolls, a little smoke above, a red and white striped umbrella, jars of chimichurri on the side shelf and a hand-painted sign reading CHORI.
// Street choripán cart
const iron = "#20272a", ironLight = "#384044";
const teal = "#258a7c", tealLight = "#43a393", tealDark = "#17675f";
const red = "#cf4139", redDark = "#a72f2f";
const cream = "#fff0cb", gold = "#f5be50";
// Wheels, low enough to touch the street.
for (const x of [15, 34]) {
cylinder(x, 10, 5, 5, 3, iron, "y");
cylinder(x, 9, 5, 3, 1, ironLight, "y");
cylinder(x, 8, 5, 1, 1, gold, "y");
}
box(13, 30, 0, 17, 33, 8, iron);
box(32, 30, 0, 36, 33, 8, iron);
// Cart and its painted front.
box(11, 13, 9, 38, 35, 21, tealDark);
box(12, 13, 11, 37, 34, 21, teal);
box(12, 13, 20, 37, 34, 21, tealLight);
box(11, 12, 10, 38, 13, 21, redDark);
box(12, 11, 11, 37, 12, 21, red);
for (let i = 0; i < 115; i++) {
const x = 13 + Math.floor(rand() * 24);
const z = 12 + Math.floor(rand() * 8);
set(x, 11, z, rand() < 0.5 ? "#d94e42" : "#c63c35");
}
// Hand-painted CHORI sign, facing the viewer.
box(13, 10, 12, 36, 10, 20, gold);
box(14, 9, 13, 35, 9, 19, cream);
const glyphs = {
C: ["111", "100", "100", "100", "111"],
H: ["101", "101", "111", "101", "101"],
O: ["111", "101", "101", "101", "111"],
R: ["110", "101", "110", "101", "101"],
I: ["111", "010", "010", "010", "111"]
};
"CHORI".split("").forEach((letter, n) => {
const pixels = glyphs[letter];
for (let row = 0; row < 5; row++)
for (let col = 0; col < 3; col++)
if (pixels[row][col] === "1")
set(16 + n * 4 + col, 8, 18 - row, redDark);
});
for (const x of [15, 35]) {
set(x, 8, 18, tealDark);
set(x, 8, 14, tealDark);
}
// Iron grill: thick rim, hot grating, and little side handles.
box(10, 12, 22, 39, 35, 24, iron);
box(12, 14, 25, 37, 33, 25, "#101718");
for (let y = 15; y <= 32; y += 3)
box(13, y, 26, 36, y, 26, ironLight);
box(9, 20, 23, 10, 27, 24, ironLight);
box(39, 20, 23, 40, 27, 24, ironLight);
box(10, 12, 25, 39, 13, 25, ironLight);
box(10, 34, 25, 39, 35, 25, ironLight);
// Browned sausages, with dark grill marks.
function sausage(x, y, length) {
line(x, y, 28, x + length, y, 28, 1, "#ae5632");
line(x + 1, y, 29, x + length - 1, y, 29, "#da7843");
for (let dx = 2; dx < length; dx += 3)
set(x + dx, y - 1, 29, "#663527");
}
sausage(14, 15, 8);
sausage(26, 15, 8);
sausage(20, 20, 9);
sausage(13, 23, 6);
// Split golden bread rolls.
function roll(x, y) {
ellipsoid(x, y, 28, 4, 2, 2, "#c97d3c");
ellipsoid(x, y, 29, 3, 2, 1, "#eeb66d");
line(x - 2, y - 1, 30, x + 2, y - 1, 30, 0, cream);
}
roll(17, 19);
roll(32, 19);
roll(29, 25);
// Side shelf with jars of vivid green chimichurri.
box(39, 15, 19, 45, 32, 20, tealDark);
box(39, 15, 21, 45, 32, 21, tealLight);
for (const y of [18, 26]) {
cylinder(42, y, 22, 2, 5, "#a9ddd0");
cylinder(42, y, 23, 1, 3, "#4c9050");
cylinder(42, y, 27, 2, 1, "#e8d6a6");
set(41, y - 1, 24, cream);
}
box(44, 19, 22, 45, 21, 27, "#e6b647");
box(44, 19, 28, 45, 21, 28, "#f6dc89");
// Umbrella pole rises from the rear of the cart.
box(24, 32, 25, 25, 33, 39, "#e4d6b5");
box(24, 32, 30, 24, 32, 38, cream);
// A broad red-and-white striped canopy, set back so the food stays visible.
const ux = 24, uy = 32, rx = 19, ry = 12;
for (let x = ux - rx; x <= ux + rx; x++)
for (let y = uy - ry; y <= uy + ry; y++) {
const dx = (x - ux) / rx, dy = (y - uy) / ry;
const d = Math.sqrt(dx * dx + dy * dy);
if (d > 1) continue;
const angle = Math.atan2(dy, dx) + Math.PI;
const stripe = Math.floor(angle / (Math.PI / 6)) % 2;
const z = 37 + Math.floor(7 * (1 - Math.pow(d, 1.5)));
const color = stripe
? (d < 0.65 ? "#fff5df" : "#eee3d0")
: (d < 0.65 ? "#e94b42" : red);
set(x, y, z - 1, stripe ? "#d5cbbd" : redDark);
set(x, y, z, color);
if (d > 0.91) {
set(x, y, 36, stripe ? cream : red);
if ((x + y) % 5 < 3) set(x, y, 35, stripe ? cream : red);
}
}
set(ux, uy, 44, gold);
// Small wisps drifting up from the exposed front of the grill.
for (const [x, y, z] of [
[18, 16, 31], [19, 16, 32], [19, 15, 33],
[20, 15, 34], [28, 17, 31], [29, 17, 32],
[29, 16, 33], [30, 16, 34]
]) set(x, y, z, "#cbd2ce");import { draw } from "./assets/voxel";
import { puestoDeChoripan } from "./assets/puesto-de-choripan";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, puestoDeChoripan, x, y, { size: 64, angle: 0, t: performance.now() / 1000 });
// size: its longest side, in px
// angle: turn on the floor, in radians
// t: seconds; if it moves, that animates it# In a terminal, in the game's folder
fogon assets add puesto-de-choripan
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["puesto-de-choripan"] })
# It lands in client/assets/puesto-de-choripan.ts
# https://fogon.page/object/puesto-de-choripan