← Asian3D assetfogon/puesto-de-ramen
Puesto de ramen
Drag to turn it// «Puesto de ramen» · gpt-6-sol (medium)
// A small Japanese street ramen stall (yatai) on wooden wheels: a wooden counter with three stools in front, a short slanted roof, red noren curtains hanging at the front with a white bowl symbol, a big steaming pot behind the counter, two red paper lanterns hanging from the corners.
const wood = "#743b2d", woodLight = "#a45a39", woodDark = "#482c28";
const red = "#ad3032", redLight = "#d7473e", redDark = "#79292c";
const gold = "#e7b856", jade = "#579888", cream = "#f8ebd4";
const tile = ["#294d48", "#35635a", "#417267", "#274940"];
function ring(cx, cy, z, outer, inner, color) {
for (let x = cx - outer; x <= cx + outer; x++)
for (let y = cy - outer; y <= cy + outer; y++) {
const d = Math.hypot(x - cx, y - cy);
if (d <= outer && d >= inner) set(x, y, z, color);
}
}
// Cart bed, lacquered frame, and inset wooden panels.
box(10, 17, 9, 38, 35, 11, woodDark);
box(11, 18, 12, 37, 34, 13, woodLight);
for (let x = 11; x <= 37; x += 5) box(x, 17, 10, x + 1, 35, 17, redDark);
box(10, 34, 11, 38, 35, 19, red);
for (let x = 12; x <= 36; x += 5) box(x, 33, 13, x, 35, 18, gold);
box(10, 17, 9, 38, 17, 10, gold);
box(10, 35, 9, 38, 35, 10, gold);
// Four stout wheels, with visible hubs and spokes.
for (const x of [6, 40]) for (const y of [23, 32]) {
cylinder(x, y, 5, 5, 3, woodDark, "x");
cylinder(x - 1, y, 5, 4, 1, woodLight, "x");
const face = x === 6 ? 5 : 43;
for (let a = 0; a < 8; a++) {
const t = a * Math.PI / 4;
line(face, y, 5, face, y + Math.round(3.6 * Math.cos(t)),
5 + Math.round(3.6 * Math.sin(t)), 0, gold);
}
cylinder(face, y, 5, 1, 1, gold, "x");
}
// Counter: broad pale worktop over a red front.
box(10, 16, 13, 38, 19, 17, red);
box(9, 15, 18, 39, 21, 19, woodLight);
box(9, 15, 17, 39, 15, 17, gold);
for (let x = 11; x <= 37; x += 5) box(x, 15, 14, x, 15, 16, gold);
box(11, 20, 19, 37, 31, 19, wood);
// Three round stools in front of the counter.
for (const x of [16, 24, 32]) {
for (const dx of [-2, 2]) for (const dy of [-2, 2])
box(x + dx, 7 + dy, 0, x + dx, 7 + dy, 8, woodDark);
box(x - 2, 5, 4, x + 2, 9, 4, woodLight);
cylinder(x, 7, 9, 3, 2, redDark);
cylinder(x, 7, 11, 3, 1, redLight);
ring(x, 7, 11, 3, 2.4, gold);
}
// Posts and decorated crossbeams.
for (const x of [10, 38]) for (const y of [16, 34]) {
box(x, y, 12, x + 1, y + 1, 30, redDark);
box(x, y, 19, x + 1, y, 27, red);
box(x, y, 18, x + 1, y + 1, 18, gold);
box(x, y, 28, x + 1, y + 1, 28, gold);
}
box(10, 15, 28, 39, 16, 29, redDark);
box(10, 15, 28, 39, 15, 28, gold);
box(10, 33, 29, 39, 35, 30, redDark);
// A shallow, sloping glazed-tile roof with lifted side eaves.
for (let y = 12; y <= 38; y++) {
for (let x = 5; x <= 43; x++) {
const lift = x <= 8 || x >= 40 ? 2 : x <= 10 || x >= 38 ? 1 : 0;
const z = 30 + Math.floor((y - 12) / 8) + lift;
set(x, y, z - 1, woodDark);
set(x, y, z, tile[(Math.floor(x / 3) + Math.floor(y / 3)) % tile.length]);
if (y % 3 === 0)
set(x, y, z, tile[(Math.floor(x / 3) + 2) % tile.length]);
}
}
for (let x = 5; x <= 43; x++) {
const lift = x <= 8 || x >= 40 ? 2 : x <= 10 || x >= 38 ? 1 : 0;
set(x, 11, 29 + lift, gold);
set(x, 12, 30 + lift, jade);
}
for (let y = 13; y <= 38; y++) {
const rise = Math.floor((y - 12) / 8);
set(5, y, 32 + rise, gold);
set(43, y, 32 + rise, gold);
}
// Hanging red noren: three separate fabric panels with uneven hems.
box(12, 14, 24, 19, 14, 28, red);
box(20, 14, 23, 29, 14, 28, redLight);
box(30, 14, 24, 37, 14, 28, red);
for (let x = 12; x <= 37; x++) {
if (x === 19 || x === 29) continue;
set(x, 14, x % 5 === 0 ? 23 : 24, redDark);
if (x % 7 === 0) set(x, 13, 27, "#e56455");
}
box(11, 13, 29, 38, 15, 29, woodDark);
box(11, 12, 29, 38, 12, 29, gold);
// Bold white ramen-bowl emblem on the middle curtain.
box(22, 13, 26, 27, 13, 26, cream);
box(23, 13, 25, 26, 13, 25, cream);
box(24, 13, 24, 25, 13, 24, cream);
set(23, 13, 27, cream);
set(26, 13, 27, cream);
set(24, 13, 28, cream);
// Big iron pot behind the counter, with broth, lid edge, and handles.
cylinder(33, 26, 20, 5, 5, "#454747");
cylinder(33, 26, 24, 4, 1, "#8eaca0");
ring(33, 26, 25, 5, 3.5, "#c2c9b5");
box(27, 25, 23, 28, 27, 24, "#363f40");
box(38, 25, 23, 39, 27, 24, "#363f40");
for (const [x, y] of [[31, 25], [34, 27], [35, 24]])
set(x, y, 25, "#e6ddad");
// Bowls and chopsticks on the counter.
for (const x of [17, 23]) {
cylinder(x, 19, 20, 2, 1, cream);
cylinder(x, 19, 21, 1, 1, "#cf9861");
line(x, 19, 21, x + 2, 21, 23, 0, gold);
}
// Wisps rising from the pot, curled toward the front opening.
for (const [x, y, z] of [
[32, 22, 25], [32, 22, 26], [31, 21, 27], [32, 20, 28],
[35, 23, 25], [35, 22, 26], [36, 21, 27], [35, 20, 28]
]) set(x, y, z, "#eee9d8");
// Lantern cords and fittings are fixed; only the paper bodies pulse.
for (const x of [7, 41]) {
line(x, 12, 32, x, 12, 28, 0, woodDark);
cylinder(x, 12, 27, 2, 1, gold);
cylinder(x, 12, 19, 2, 1, gold);
line(x, 12, 18, x, 12, 16, 0, redDark);
set(x, 12, 15, gold);
}
part("leftLantern", [7, 12, 23]);
ellipsoid(7, 12, 23, 3, 3, 4, "#cd3b32");
animate("leftLantern", {
type: "colors", palette: ["#ba302e", "#e34530", "#f07938"],
pattern: "pulse", glow: 0.6
});
part("rightLantern", [41, 12, 23]);
ellipsoid(41, 12, 23, 3, 3, 4, "#cd3b32");
animate("rightLantern", {
type: "colors", palette: ["#ba302e", "#e34530", "#f07938"],
pattern: "pulse", glow: 0.6
});
part("body", [24, 24, 0]);
// Gold ribs give the lanterns their familiar paper silhouette.
for (const x of [7, 41]) {
for (const z of [20, 26]) ring(x, 12, z, 2, 1.5, gold);
set(x, 9, 23, gold);
set(x, 15, 23, gold);
}import { draw } from "./assets/voxel";
import { puestoDeRamen } from "./assets/puesto-de-ramen";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, puestoDeRamen, 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-ramen
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["puesto-de-ramen"] })
# It lands in client/assets/puesto-de-ramen.ts
# https://fogon.page/object/puesto-de-ramen