← Whole house3D assetfogon/consola-con-joystick
Consola con joystick
Drag to turn it// «Consola con joystick» · gpt-6-sol (medium)
// A home video game console: a sleek black and white box lying flat with a glowing blue light strip, and two chunky game controllers (one red, one blue) in front of it connected with curly cables.
// Low feet and the softly rounded white console body.
box(9, 25, 0, 15, 35, 1, "#454a50");
box(33, 25, 0, 39, 35, 1, "#454a50");
function roundedLayer(x0, x1, y0, y1, z, corner, color) {
for (let x = x0; x <= x1; x++) {
for (let y = y0; y <= y1; y++) {
const dx = Math.min(x - x0, x1 - x);
const dy = Math.min(y - y0, y1 - y);
if (dx < corner && dy < corner &&
(dx - corner) ** 2 + (dy - corner) ** 2 > corner ** 2) continue;
set(x, y, z, color);
}
}
}
for (let z = 1; z <= 7; z++) {
const c = z <= 2 ? "#b8c1c6" : z <= 5 ? "#e5eaeb" : "#faf9f5";
roundedLayer(5, 42, 22, 40, z, 3, c);
}
roundedLayer(6, 41, 23, 39, 8, 2, "#ffffff");
// Subtle variation on the broad, warm-white lid.
for (let x = 7; x <= 40; x++)
for (let y = 24; y <= 38; y++)
if (get(x, y, 8) === "#ffffff" && rand() < 0.10)
set(x, y, 8, "#f0f2ef");
// A contrasting, slightly raised black panel with a diagonal leading edge.
for (let y = 25; y <= 38; y++) {
const start = 18 + Math.floor((y - 25) * 0.38);
for (let x = start; x <= 40; x++) {
set(x, y, 8, y < 28 ? "#30363c" : "#252a30");
if (x >= start + 2 && x <= 39 && y >= 27 && y <= 37)
set(x, y, 9, rand() < 0.08 ? "#343a40" : "#191e24");
}
set(start, y, 8, "#747d82");
}
box(24, 32, 29, 9, 29, 9, "#41484d"); // tiny lid badge
box(26, 32, 29, 9, 28, 9, "#dce0df");
// Dark front fascia, a disc slot, and chunky little ports.
box(7, 21, 3, 40, 21, 5, "#292e34");
box(8, 21, 2, 39, 21, 2, "#626a70");
box(8, 20, 3, 40, 20, 5, "#22282e");
box(22, 20, 3, 36, 20, 3, "#0c1015");
box(23, 20, 4, 35, 20, 4, "#555f66");
for (const x of [11, 17]) {
box(x, 20, 3, x + 3, 20, 4, "#090d12");
box(x + 1, 20, 4, x + 2, 20, 4, "#69767d");
}
set(39, 20, 4, "#aebdc4");
set(39, 20, 3, "#49535a");
function controller(cx, shades) {
const cy = 10;
// Three overlapping rounded masses make the two broad handgrips.
for (let x = cx - 8; x <= cx + 8; x++)
for (let y = 4; y <= 16; y++)
for (let z = 0; z <= 7; z++) {
const oval = ((x - cx) / 7.0) ** 2 +
((y - 10.5) / 5.0) ** 2 +
((z - 3.1) / 3.25) ** 2 <= 1;
const grips = [-5, 5].some(d =>
((x - cx - d) / 3.2) ** 2 +
((y - 7.7) / 4.2) ** 2 +
((z - 2.7) / 2.9) ** 2 <= 1);
if (!oval && !grips) continue;
let c = z <= 1 ? shades[0] : z <= 3 ? shades[1] : shades[2];
if (z >= 5 && rand() < 0.13) c = shades[3];
set(x, y, z, c);
}
// Pale inset around the controls and a curved shoulder seam.
ellipsoid(cx, 10.5, 5.6, 4.7, 3.0, 1.0, shades[3]);
line(cx - 6, 13, 5, cx - 3, 15, 5, 0, shades[0]);
line(cx + 3, 15, 5, cx + 6, 13, 5, 0, shades[0]);
// Raised cross-shaped D-pad.
box(cx - 4, 10, 7, cx - 2, 10, 7, "#30353b");
box(cx - 3, 9, 7, cx - 3, 11, 7, "#30353b");
set(cx - 3, 10, 8, "#687279");
// Four big, glossy face buttons.
for (const [dx, dy, color] of [
[3, 9, "#f5d36d"], [2, 10, "#89d5af"],
[4, 10, "#f6a7ac"], [3, 11, "#bba9ec"]
]) {
set(cx + dx, dy, 7, "#353941");
set(cx + dx, dy, 8, color);
}
set(cx, 10, 7, "#464e53");
set(cx, 10, 8, "#f8f5e9");
set(cx - 1, 12, 7, "#697177");
set(cx + 1, 12, 7, "#697177");
// Dark triggers at the back edge.
box(cx - 6, 15, 3, cx - 4, 16, 4, "#30353a");
box(cx + 4, 15, 3, cx + 6, 16, 4, "#30353a");
}
controller(13, ["#813d45", "#ba5860", "#e57878", "#f6a49b"]);
controller(34, ["#315575", "#457faf", "#67a9d8", "#a2d4ed"]);
// Coiled cords sit in the gap between the controllers and console.
function cord(cx) {
line(cx, 15, 4, cx, 17, 3, 0, "#293139");
let previous = [cx, 17, 3];
for (let i = 1; i <= 60; i++) {
const t = i / 60;
const angle = t * Math.PI * 6;
const next = [
cx + Math.round(2.0 * Math.sin(angle)),
17 + 4.5 * t,
2 + Math.round(Math.cos(angle))
];
line(...previous, ...next, 0, "#293139");
previous = next;
}
line(...previous, cx, 22, 3, 0, "#293139");
set(cx, 18, 3, "#66747c");
set(cx + 2, 20, 2, "#66747c");
}
cord(13);
cord(34);
// The only moving part: a luminous strip across the front lip.
part("light strip", [24, 20, 5]);
box(8, 20, 5, 39, 20, 5, "#197ec2");
box(10, 20, 6, 37, 20, 6, "#74e5f5");
set(8, 20, 6, "#319fd5");
set(39, 20, 6, "#319fd5");
animate("light strip", {
type: "colors",
palette: ["#1879bc", "#2baee0", "#78e9fa", "#b3f7ff"],
pattern: "pulse",
glow: 0.8
});import { draw } from "./assets/voxel";
import { consolaConJoystick } from "./assets/consola-con-joystick";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, consolaConJoystick, 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 consola-con-joystick
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["consola-con-joystick"] })
# It lands in client/assets/consola-con-joystick.ts
# https://fogon.page/object/consola-con-joystick