← Whole house3D assetfogon/ducha
Ducha
Drag to turn it// «Ducha» · gpt-6-sol (medium)
// A shower cabin: a square tray on the floor, two glass panels (light cyan, slightly transparent-looking with lighter edges) on the sides, a tall chrome pipe at the back with a big round rain shower head on top and two knobs, and white tiles on the back wall.
// Square shower tray, with a low raised rim.
box(7, 7, 0, 40, 40, 2, "#e6e3dc");
box(8, 8, 3, 39, 39, 3, "#f8f8f3");
box(11, 11, 3, 36, 36, 3, "#dce6e5");
box(12, 12, 3, 35, 35, 3, "#eaf1ef");
box(7, 7, 3, 40, 9, 4, "#ffffff");
box(7, 38, 3, 40, 40, 4, "#ffffff");
box(7, 10, 3, 9, 37, 4, "#ffffff");
box(38, 10, 3, 40, 37, 4, "#ffffff");
box(8, 8, 5, 39, 8, 5, "#cbd4d5");
// Little square drain in the tray.
box(22, 25, 3, 26, 29, 3, "#aebfc2");
box(23, 26, 4, 25, 28, 4, "#82999d");
set(24, 27, 4, "#536e75");
// Cream-white tiled back wall. The pale grey backing forms grout lines.
box(8, 39, 4, 40, 41, 42, "#eeeae2");
box(8, 38, 5, 40, 38, 40, "#cbd2d0");
for (let x = 9; x <= 38; x += 5) {
for (let z = 6; z <= 36; z += 5) {
const tile = rand() < 0.23 ? "#f4f3ec" : "#fffdf6";
box(x, 37, z, x + 3, 38, z + 3, tile);
box(x, 37, z + 3, x + 3, 37, z + 3, "#ebeae3");
}
}
box(7, 38, 41, 41, 41, 43, "#fffdfa");
box(7, 37, 42, 41, 37, 43, "#dce3e1");
box(7, 37, 4, 41, 38, 5, "#c6d1d0");
// Two pale cyan side panes. Fine gaps and highlights suggest clear glass.
for (const x of [9, 38]) {
for (let y = 10; y <= 36; y++) {
for (let z = 6; z <= 34; z++) {
if ((y + 2 * z) % 11 !== 0) {
set(x, y, z, (y + z) % 8 === 0 ? "#d8f8f8" : "#bce9ec");
}
}
}
box(x, 9, 5, x, 9, 36, "#a5b9bd");
box(x, 37, 5, x, 37, 36, "#a5b9bd");
box(x, 9, 35, x, 37, 36, "#e5f7f6");
line(x, 11, 7, x, 11, 33, 0, "#f1ffff");
line(x, 13, 27, x, 30, 27, 0, "#e9ffff");
}
box(8, 9, 36, 10, 37, 36, "#d4e1e2");
box(37, 9, 36, 39, 37, 36, "#d4e1e2");
// Chrome control plate, with two big, easy-to-read knobs.
box(16, 35, 14, 32, 37, 22, "#aababe");
box(17, 34, 15, 31, 34, 21, "#e7eff0");
box(17, 34, 21, 31, 34, 21, "#ffffff");
for (const x of [20, 28]) {
ellipsoid(x, 32, 18, 3, 2, 3, "#97a9ad");
ellipsoid(x, 31, 18, 2, 2, 2, "#ecf5f4");
set(x - 1, 29, 19, "#ffffff");
set(x, 29, 17, x === 20 ? "#77bfcf" : "#e8ac85");
}
// Tall exposed pipe, curving forward to the rain head.
cylinder(24, 35, 22, 2, 17, "#9aadb1");
cylinder(24, 34, 23, 1, 16, "#e5f0ef");
line(24, 35, 39, 24, 24, 39, 2, "#9aadb1");
line(24, 34, 40, 24, 24, 40, 1, "#f5fbf8");
box(22, 36, 25, 26, 37, 27, "#cbd8d9");
box(22, 36, 33, 26, 37, 35, "#cbd8d9");
// Broad, round rain-shower head and its dark underside nozzles.
cylinder(24, 24, 37, 7, 2, "#8ea3a8");
cylinder(24, 24, 39, 6, 1, "#e9f2f0");
cylinder(24, 24, 36, 5, 1, "#b8c9cb");
for (let dx = -4; dx <= 4; dx += 2) {
for (let dy = -4; dy <= 4; dy += 2) {
if (dx * dx + dy * dy <= 18) set(24 + dx, 24 + dy, 35, "#708d94");
}
}
// Separate animated water: scattered droplets leave the cabin open and readable.
part("water", [24, 24, 36]);
for (let i = 0; i < 54; i++) {
const x = 20 + Math.floor(rand() * 9);
const y = 20 + Math.floor(rand() * 9);
if ((x - 24) ** 2 + (y - 24) ** 2 > 19) continue;
const z = 10 + Math.floor(rand() * 25);
set(x, y, z, "#a9e6f4");
if (rand() < 0.32 && z > 12) set(x, y, z - 1, "#e6fbff");
}
animate("water", {
type: "colors",
palette: ["#82cfe9", "#a9e6f4", "#e6fbff", "#ffffff"],
pattern: "wave",
glow: 0.3
});
part("body", [24, 24, 0]);import { draw } from "./assets/voxel";
import { ducha } from "./assets/ducha";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, ducha, 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 ducha
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["ducha"] })
# It lands in client/assets/ducha.ts
# https://fogon.page/object/ducha