← Basics3D assetfogon/monopatin
Monopatín
Drag to turn it// «Monopatín» · gpt-6-sol (medium)
// Scooter («Monopatín»). Be faithful to the reference: keep thin parts thin (1–2 blocks: strings, necks, handles, legs, rods), keep its exact proportions and silhouette, and every visible detail (books on shelves, sound holes, tuning pegs, valves). Don't make it chunkier than the reference.
const teal = "#4f9f93";
const mint = "#72c4ad";
const light = "#9bd9c2";
const dark = "#326d68";
const shadow = "#285750";
const cream = "#d9d0b3";
const creamLight = "#eee2c4";
const creamShade = "#ada991";
const metal = "#aab5b0";
const metalLight = "#d9dfd5";
const tire = "#333638";
function discX(x0, x1, cy, cz, r, color) {
for (let x = x0; x <= x1; x++)
for (let y = cy - r; y <= cy + r; y++)
for (let z = cz - r; z <= cz + r; z++)
if ((y - cy) ** 2 + (z - cz) ** 2 <= r * r)
set(x, y, z, color);
}
// Two narrow wheels, with pale cast-metal rims and open-looking spokes.
for (const wy of [10, 37]) {
discX(19, 29, wy, 5, 5, tire);
for (const x of [18, 30]) {
for (let y = wy - 5; y <= wy + 5; y++)
for (let z = 0; z <= 10; z++) {
const d = Math.hypot(y - wy, z - 5);
if (d >= 3.35 && d <= 4.6)
set(x, y, z, d > 4.1 ? metal : metalLight);
}
for (let a = 0; a < 8; a++) {
const t = a * Math.PI / 4;
line(x, wy, 5, x, wy + Math.round(3.6 * Math.cos(t)),
5 + Math.round(3.6 * Math.sin(t)), 0, metalLight);
}
discX(x, x, wy, 5, 1, "#727d78");
set(x, wy, 5, metalLight);
}
box(17, wy, 5, 31, wy, 5, "#737f79");
}
// Low, thin running board.
box(18, 14, 11, 30, 38, 12, dark);
box(17, 15, 13, 31, 37, 13, light);
box(19, 16, 14, 29, 34, 14, "#bad9bb");
for (const x of [18, 30]) {
box(x, 18, 14, x, 34, 14, creamLight);
box(x, 20, 15, x, 32, 15, dark);
}
for (let y = 19; y <= 32; y += 3)
box(20, y, 15, 28, y, 15, "#8dbba5");
// Rounded, stepped front mudguard, closely following the wheel.
for (let y = 4; y <= 17; y++) {
const dz = Math.abs(y - 10);
const top = dz < 3 ? 13 : dz < 5 ? 12 : 10;
if (top > 10) {
box(18, y, top - 1, 30, y, top - 1, teal);
box(19, y, top, 29, y, top, y < 10 ? light : mint);
}
}
for (const x of [17, 31]) {
for (let y = 6; y <= 15; y++) {
const dz = Math.abs(y - 10);
const z = dz < 3 ? 11 : dz < 5 ? 10 : 8;
box(x, y, z - 2, x, y, z, dz < 4 ? mint : teal);
}
}
for (let y = 5; y <= 13; y += 2)
box(19, y, 13, 29, y, 13, "#a1dbc3");
// Front fork and its slim dark struts.
for (const x of [19, 29]) {
line(x, 10, 6, x, 13, 21, 1, dark);
line(x, 11, 8, x, 14, 20, 0, metal);
}
box(18, 10, 6, 30, 10, 6, "#78847e");
// Leg shield: tall, tapered, with a light inset and turquoise edges.
for (let z = 15; z <= 29; z++) {
const lo = z < 19 ? 19 : z > 26 ? 20 : 18;
const hi = z < 19 ? 29 : z > 26 ? 28 : 30;
box(lo, 16, z, hi, 19, z, teal);
box(lo, 16, z, lo, 19, z, z % 4 === 0 ? light : mint);
box(hi, 16, z, hi, 19, z, dark);
if (z >= 18 && z <= 28)
box(21, 15, z, 28, 15, z, z > 24 ? creamLight : cream);
}
box(21, 15, 16, 28, 15, 17, creamShade);
box(22, 14, 19, 27, 14, 27, cream);
box(22, 14, 27, 27, 14, 28, creamLight);
for (const x of [20, 29])
box(x, 17, 19, x, 18, 26, x === 20 ? light : dark);
box(19, 15, 29, 29, 18, 30, mint);
box(21, 14, 30, 27, 17, 30, light);
// Rear engine casing, kept narrow and ribbed rather than a solid box.
box(18, 27, 16, 30, 40, 23, teal);
box(19, 28, 23, 29, 39, 25, mint);
box(20, 29, 25, 28, 38, 25, light);
for (const x of [17, 31]) {
box(x, 29, 17, x, 40, 22, dark);
box(x, 29, 22, x, 40, 23, mint);
for (let y = 30; y <= 39; y += 3) {
box(x, y, 18, x, y, 22, light);
set(x, y + 1, 21, "#b1dfc9");
}
}
box(16, 32, 18, 16, 39, 20, mint);
box(32, 32, 18, 32, 39, 20, mint);
for (const x of [16, 32]) {
box(x, 34, 19, x, 38, 19, dark);
box(x, 34, 21, x, 39, 21, light);
set(x, 36, 20, metalLight);
}
box(19, 40, 17, 29, 41, 21, teal);
box(20, 41, 19, 28, 41, 20, dark);
// Rear mudguard and the slim rack/trim above the side casing.
for (let y = 34; y <= 44; y++) {
const dz = Math.abs(y - 37);
const top = dz < 3 ? 13 : dz < 5 ? 12 : 10;
box(18, y, top, 30, y, top, dz < 3 ? mint : teal);
}
box(16, 26, 24, 32, 41, 24, dark);
box(17, 27, 25, 31, 40, 25, light);
for (const x of [16, 32]) {
box(x, 28, 25, x, 40, 25, metalLight);
box(x, 30, 23, x, 30, 25, metal);
box(x, 39, 22, x, 39, 25, metal);
}
// Brown, gently rounded saddle with a dark stitched edge.
box(18, 29, 27, 30, 39, 28, "#503a30");
box(19, 28, 28, 29, 40, 29, "#75513b");
box(20, 29, 29, 28, 39, 30, "#886047");
box(21, 30, 30, 27, 38, 30, "#93694d");
for (let y = 30; y <= 38; y += 3) {
box(19, y, 29, 20, y, 29, "#a77a57");
box(28, y, 29, 29, y, 29, "#674535");
}
box(20, 40, 27, 28, 40, 28, "#49362e");
// Steering neck, horizontal bars and narrow black rubber grips.
line(24, 14, 29, 24, 12, 37, 1, dark);
box(22, 11, 35, 26, 14, 37, mint);
box(23, 11, 37, 25, 13, 38, light);
box(16, 12, 36, 32, 12, 37, metal);
box(13, 11, 36, 18, 13, 37, "#252e2e");
box(30, 11, 36, 36, 13, 37, "#252e2e");
box(14, 11, 37, 18, 11, 37, "#414a47");
box(31, 11, 37, 35, 11, 37, "#414a47");
set(22, 10, 36, metalLight);
set(26, 10, 36, metalLight);
// Cream headlight facing forward, with a silver bezel.
discX(20, 28, 10, 31, 2, creamShade);
for (let x = 21; x <= 27; x++)
for (let z = 28; z <= 34; z++)
if ((x - 24) ** 2 + (z - 31) ** 2 <= 7)
set(x, 8, z, creamLight);
box(22, 7, 30, 26, 7, 32, "#f3e9cb");
set(23, 7, 33, metalLight);
// One high round mirror and a smaller opposite mirror.
line(18, 12, 37, 16, 10, 43, 0, metal);
for (let x = 13; x <= 19; x++)
for (let z = 40; z <= 45; z++)
if ((x - 16) ** 2 + (z - 42.5) ** 2 <= 9)
set(x, 9, z, metal);
box(14, 8, 42, 18, 8, 44, "#cbd7d2");
set(15, 8, 44, metalLight);
line(31, 12, 37, 33, 13, 39, 0, metal);
box(31, 13, 39, 35, 14, 41, metal);
box(32, 12, 40, 34, 12, 41, metalLight);
// Small rear lamp, exposed fittings and a discreet kickstand.
box(21, 42, 20, 27, 42, 22, "#456c65");
box(23, 43, 20, 25, 43, 21, "#a76e56");
for (const x of [17, 31]) {
set(x, 26, 17, metalLight);
set(x, 39, 17, metalLight);
}
line(20, 29, 12, 18, 32, 2, 0, "#596762");
line(18, 32, 2, 21, 33, 2, 0, "#596762");import { draw } from "./assets/voxel";
import { monopatin } from "./assets/monopatin";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, monopatin, 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 monopatin
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["monopatin"] })
# It lands in client/assets/monopatin.ts
# https://fogon.page/object/monopatin