← Whole house3D assetfogon/ventilador-de-techo
Ventilador de techo
Drag to turn it// «Ventilador de techo» · gpt-6-sol (medium)
// A ceiling fan seen as an object on its own: a short brass rod at the top, a round white motor housing with a frosted glass light bowl underneath, and four long wooden blades sticking out horizontally. Shown standing on a small round base plate so it sits on the floor.
const brass = "#c99743";
const brassLight = "#efd080";
const brassDark = "#956a30";
const white = "#f6f4ed";
const whiteShade = "#dddcd5";
const walnut = "#89542f";
const honey = "#c98a48";
function disk(cx, cy, z, r, color) {
for (let x = -r; x <= r; x++)
for (let y = -r; y <= r; y++)
if (x*x + y*y <= r*r) set(cx+x, cy+y, z, color);
}
// A little weighted display base keeps the fan standing on the floor.
disk(24, 24, 0, 6, brassDark);
disk(24, 24, 1, 6, brass);
disk(24, 24, 2, 5, brassLight);
disk(24, 24, 3, 3, brass);
cylinder(24, 24, 4, 1, 35, brass, "z");
for (let z = 6; z <= 17; z++) set(23, 23, z, brassLight);
// The short exposed downrod above the motor.
cylinder(24, 24, 39, 1, 5, brass, "z");
disk(24, 24, 43, 2, brassLight);
// Motor, light, and all four blades turn together.
part("fan", [24, 24, 38]);
// Frosted glass bowl: a softly shaded, solid toy-like shape.
for (let x = 18; x <= 30; x++)
for (let y = 18; y <= 30; y++)
for (let z = 18; z <= 27; z++) {
const d = ((x-24)/5.7)**2 + ((y-24)/5.7)**2 + ((z-23)/5.5)**2;
if (d <= 1) {
let c = z < 21 ? "#dfd7be" : "#fff4d9";
if (y > 26) c = "#e8e4d9";
if (rand() < 0.11) c = "#fff9e9";
set(x, y, z, c);
}
}
for (let z = 21; z <= 24; z++)
for (let x = 22; x <= 24; x++)
set(x, 19, z, "#fffdf0");
// Metal lip securing the glass.
disk(24, 24, 27, 5, "#b6b8b5");
disk(24, 24, 28, 5, "#e5e5df");
// Rounded white motor housing, with grey lower and upper seams.
for (let z = 29; z <= 36; z++) {
const r = z === 36 ? 4 : z === 35 ? 5 : 6;
for (let x = -r; x <= r; x++)
for (let y = -r; y <= r; y++)
if (x*x + y*y <= r*r) {
let c = z === 29 || z === 35 ? whiteShade : white;
if (y > 2) c = z === 29 || z === 35 ? "#c7c8c3" : "#e7e6e0";
if (rand() < 0.045) c = "#ffffff";
set(24+x, 24+y, z, c);
}
}
disk(24, 24, 37, 3, brass);
disk(24, 24, 38, 2, brassLight);
// Four broad wooden blades. Their tapered roots and rounded ends
// leave a clear four-point silhouette even when viewed small.
for (let direction = 0; direction < 4; direction++) {
for (let t = 4; t <= 20; t++) {
const halfWidth = t < 7 ? 2 : t < 10 ? 3 : t < 17 ? 4 : t < 19 ? 3 : 2;
for (let w = -halfWidth; w <= halfWidth; w++) {
for (let z = 31; z <= 33; z++) {
const a = t * (direction === 0 ? 1 : direction === 2 ? -1 : 0)
+ w * (direction === 1 ? 1 : direction === 3 ? -1 : 0);
const b = t * (direction === 1 ? 1 : direction === 3 ? -1 : 0)
+ w * (direction === 0 ? -1 : direction === 2 ? 1 : 0);
let c = z === 31 ? walnut : honey;
if (Math.abs(w) === halfWidth) c = z === 33 ? "#aa6d39" : walnut;
else if (z === 33 && (w === -1 || rand() < 0.09)) c = "#dda35b";
else if (z === 33 && rand() < 0.07) c = "#b5793d";
set(24+a, 24+b, z, c);
}
}
}
}
// Brass blade brackets and a tidy central hub.
for (let d = 0; d < 4; d++) {
for (let t = 5; t <= 8; t++) {
const x = 24 + (d === 0 ? t : d === 2 ? -t : 0);
const y = 24 + (d === 1 ? t : d === 3 ? -t : 0);
set(x, y, 34, t === 8 ? brassDark : brassLight);
}
}
disk(24, 24, 37, 2, brassLight);
animate("fan", { type: "spin", axis: "z", speed: 4 });import { draw } from "./assets/voxel";
import { ventiladorDeTecho } from "./assets/ventilador-de-techo";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, ventiladorDeTecho, 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 ventilador-de-techo
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["ventilador-de-techo"] })
# It lands in client/assets/ventilador-de-techo.ts
# https://fogon.page/object/ventilador-de-techo