← Casa completaObjeto 3Dfogon/cucha-de-perro
Cucha de perro
Arrastrá para girarlo// «Cucha de perro» · gpt-6-sol (medium)
// A dog house: a small wooden kennel with red painted plank walls, a dark green triangular roof, an arched door at the front, a name plate above the door, and a dog bowl with a bone next to it.
const red = ["#bf5550", "#c96259", "#d66d62", "#df796a"];
const honey = "#dba665";
const walnut = "#785039";
const roofGreen = ["#294e40", "#315b49", "#386751", "#42745b"];
function plankColor() {
return red[Math.floor(rand() * red.length)];
}
function roofColor() {
return roofGreen[Math.floor(rand() * roofGreen.length)];
}
function roofTop(x) {
return Math.round(36 - 0.8 * Math.abs(x - 24));
}
function doorTop(x) {
const dx = x - 24;
return 14 + Math.floor(Math.sqrt(Math.max(0, 6.5 * 6.5 - dx * dx)));
}
function inDoor(x, z) {
return Math.abs(x - 24) <= 6 && z <= doorTop(x);
}
// Honey-colored base and a dark, recessed interior.
box(10, 13, 0, 38, 38, 1, "#a9774a");
box(11, 14, 1, 37, 37, 2, honey);
box(13, 17, 3, 35, 35, 3, "#715039");
box(18, 17, 2, 30, 19, 2, "#9a683f");
// Red plank walls, with a real opening through the thick front wall.
for (let z = 2; z <= 23; z++) {
for (let y = 14; y <= 37; y++) {
for (let x = 11; x <= 37; x++) {
const front = y <= 16;
const back = y >= 35;
const side = x <= 13 || x >= 35;
if (!(front || back || side) || (front && inDoor(x, z))) continue;
const seam = z > 2 && (z - 2) % 5 === 0;
const joint = (x + (Math.floor(z / 5) % 2) * 7) % 12 === 0;
let c = seam ? "#98453f" : plankColor();
if (!seam && joint && front) c = "#ae4e49";
set(x, y, z, c);
}
}
}
// Front and rear triangular gables.
for (let x = 11; x <= 37; x++) {
for (let z = 24; z <= roofTop(x) - 3; z++) {
for (let y = 14; y <= 16; y++)
set(x, y, z, z % 5 === 0 ? "#a34a44" : plankColor());
for (let y = 35; y <= 37; y++)
set(x, y, z, z % 5 === 0 ? "#a34a44" : plankColor());
}
}
// Chunky corner posts and a bright sill.
for (const x of [11, 37]) {
for (const y of [14, 37]) {
box(x, y, 2, x, y, 23, "#a97449");
for (let z = 4; z <= 22; z += 5) set(x, y - (y === 37 ? 1 : 0), z, honey);
}
}
box(17, 12, 1, 31, 17, 2, "#bd8852");
box(19, 11, 2, 29, 12, 2, "#ebbd7b");
// Deep walnut arch, edged with golden wood.
for (let x = 16; x <= 32; x++) {
for (let z = 2; z <= 23; z++) {
const inside = inDoor(x, z);
const nearArch = !inside && (
inDoor(x - 1, z) || inDoor(x + 1, z) ||
inDoor(x, z - 1) || inDoor(x, z - 2)
);
if (nearArch) {
box(x, 12, z, x, 14, z, "#b8814e");
set(x, 11, z, "#e6b879");
} else if (inside) {
set(x, 18, z, "#392d2a");
}
}
}
// Little interior floorboards visible through the door.
for (let x = 19; x <= 29; x += 3)
line(x, 17, 3, x, 27, 3, 0, "#9b7048");
// A small sky-blue side window with substantial wooden muntins.
box(38, 22, 11, 38, 32, 20, "#9c693f");
box(39, 23, 12, 39, 31, 19, "#ebbd7b");
box(40, 24, 13, 40, 30, 18, "#90bfc4");
box(41, 24, 15, 41, 30, 15, "#edc68b");
box(41, 27, 13, 41, 27, 18, "#edc68b");
box(41, 24, 18, 41, 30, 18, "#fff0c9");
// Thick dark-green pitched roof, projecting beyond every wall.
for (let x = 8; x <= 40; x++) {
const top = roofTop(x);
for (let y = 11; y <= 40; y++) {
for (let z = top - 3; z <= top; z++) {
let c = roofColor();
if (z === top) c = (y % 7 === 0) ? "#254b3d" : "#46785c";
if (z === top - 3) c = "#213e34";
if (y === 11 || y === 40) c = z === top ? "#598568" : "#294b3c";
set(x, y, z, c);
}
if (x < 24 && x % 4 === 0 || x > 24 && x % 4 === 1) {
for (const y of [18, 25, 32])
set(x, y, top, "#638b6b");
}
}
}
// Ridge cap and tidy front fascia follow the two sloping edges.
box(23, 10, 36, 25, 41, 36, "#244b3b");
for (let x = 8; x <= 40; x++) {
const z = roofTop(x);
set(x, 10, z - 2, "#bd8b57");
set(x, 10, z - 1, "#d5a46a");
set(x, 41, z - 2, "#a7764b");
}
// Raised name plate, safely below the peak.
box(17, 9, 23, 31, 11, 30, "#835638");
box(18, 8, 24, 30, 8, 29, "#efc68a");
for (const x of [18, 30])
for (const z of [24, 29]) set(x, 7, z, "#f8e0ad");
const letters = [
["101", "111", "111", "101", "101"], // M
["010", "101", "111", "101", "101"], // A
["101", "101", "010", "101", "101"] // X
];
letters.forEach((rows, i) => {
for (let row = 0; row < 5; row++)
for (let col = 0; col < 3; col++)
if (rows[row][col] === "1")
set(19 + i * 4 + col, 7, 28 - row, walnut);
});
// Sky-blue dog bowl: thick lip, hollow center, and a little food.
for (let z = 0; z <= 4; z++) {
for (let x = 5; x <= 17; x++) {
for (let y = 0; y <= 11; y++) {
const d = Math.hypot(x - 11, y - 5.5);
if (z === 0 && d <= 4.5) set(x, y, z, "#6899a2");
else if (z === 1 && d <= 5) set(x, y, z, "#77b3bf");
else if (z === 2 && d >= 3.3 && d <= 5.2) set(x, y, z, "#89c4d0");
else if (z === 3 && d >= 3.8 && d <= 5.5) set(x, y, z, "#9cd3da");
else if (z === 4 && d >= 4.1 && d <= 5.6) set(x, y, z, "#c1e8e7");
if (z === 2 && d < 3.3) set(x, y, z, "#866040");
}
}
}
for (const [x, y] of [[9, 5], [12, 4], [13, 7], [10, 7]])
set(x, y, 3, "#bc8b56");
// Chunky toy bone beside the bowl, resting on the floor.
box(30, 4, 0, 40, 7, 0, "#f0dfb7");
box(32, 5, 1, 38, 6, 2, "#fff1cf");
for (const x of [31, 39])
for (const y of [4, 7])
sphere(x, y, 1.5, 1.6, "#fff1cf");
line(33, 5, 3, 37, 5, 3, 0, "#fff9df");import { draw } from "./assets/voxel";
import { cuchaDePerro } from "./assets/cucha-de-perro";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, cuchaDePerro, x, y, { size: 64, angle: 0, t: performance.now() / 1000 });
// size: lo que mide en px su lado más largo
// angle: giro sobre el piso, en radianes
// t: segundos; si se mueve, se anima solo con eso# En una terminal, en la carpeta del juego
fogon assets add cucha-de-perro
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["cucha-de-perro"] })
# Queda en client/assets/cucha-de-perro.ts
# https://fogon.page/object/cucha-de-perro