← FantasíaObjeto 3Dfogon/casa-en-el-arbol
Casa en el árbol
Arrastrá para girarlo// «Casa en el árbol» · gpt-6-sol (medium)
// A cozy treehouse: a thick brown tree trunk with a wooden plank platform halfway up and a small wooden cabin with a red pointed roof and a round window on it, a rope ladder hanging down to the ground at the front (-y), and a big round leafy green crown above the cabin.
// Cozy storybook treehouse
const bark = ["#654128", "#754c2e", "#875737", "#95623e"];
const leaves = ["#365d38", "#427447", "#4d8950", "#5d9a58"];
function woodPlank(x0, y0, z0, x1, y1, z1, i) {
box(x0, y0, z0, x1, y1, z1,
["#94613a", "#a66e42", "#b77b49", "#a36a3c"][i % 4]);
}
// Thick trunk, with roots reaching out from its base.
cylinder(24, 27, 0, 5.5, 28, bark[1]);
cylinder(24, 28, 24, 4, 17, bark[0]);
ellipsoid(24, 27, 7, 6, 5, 8, bark[1]);
const roots = [
[13, 21], [16, 35], [34, 19], [37, 32], [24, 39], [23, 15]
];
for (const [x, y] of roots) {
line(24, 27, 5, x, y, 0, 2.1, bark[0]);
ellipsoid(x, y, 0, 2.5, 2, 1.4, bark[1]);
}
// A few bark ridges, mostly on the visible front.
for (let i = 0; i < 58; i++) {
const x = 19 + Math.floor(rand() * 11);
const z = Math.floor(rand() * 18);
const y = 22 + Math.floor(rand() * 3);
if (get(x, y, z)) {
line(x, y - 1, z, x, y - 1, Math.min(z + 1 + Math.floor(rand() * 3), 18),
0, rand() < 0.65 ? bark[0] : bark[3]);
}
}
// Branches disappearing into the treetop.
line(24, 29, 32, 12, 32, 39, 2, bark[0]);
line(25, 29, 33, 37, 34, 39, 2, bark[0]);
line(24, 30, 36, 25, 39, 41, 2, bark[0]);
// Diagonal supports beneath the platform.
for (const [x, y] of [[12, 12], [36, 12], [12, 36], [36, 36]]) {
line(24, 27, 9, x, y, 17, 1.2, "#67442e");
line(24, 27, 9, x, y, 17, 0, "#a16e42");
}
// Solid plank platform, with individual broad boards.
box(11, 10, 17, 37, 37, 17, "#64432d");
for (let y = 10, i = 0; y <= 37; y += 3, i++) {
woodPlank(11, y, 18, 37, Math.min(y + 2, 37), 19, i);
box(11, y, 17, 37, y, 17, "#755034");
}
box(11, 10, 17, 37, 10, 18, "#69442e");
box(11, 37, 17, 37, 37, 18, "#69442e");
box(11, 10, 17, 11, 37, 18, "#69442e");
box(37, 10, 17, 37, 37, 18, "#69442e");
// Low balcony railings, leaving the front open for the ladder.
for (const x of [12, 36]) {
for (const y of [14, 23, 33]) box(x, y, 20, x + 1, y + 1, 23, "#755037");
box(x, 13, 23, x + 1, 36, 24, "#ad7849");
}
for (const x of [12, 35]) {
box(x, 35, 20, x + 2, 36, 23, "#755037");
}
box(13, 35, 23, 36, 36, 24, "#ad7849");
// Cabin: chunky wooden walls and visible horizontal timber courses.
box(15, 16, 20, 34, 34, 31, "#ae794d");
for (let z = 21; z <= 30; z += 3) {
box(15, 15, z, 34, 15, z, "#c18a55");
box(15, 16, z, 15, 34, z, "#c18a55");
box(34, 16, z, 34, 34, z, "#8b5c39");
}
for (const x of [15, 34]) {
box(x, 15, 20, x + 1, 16, 31, "#754e33");
box(x, 15, 26, x + 1, 16, 26, "#d29a5a");
}
box(15, 14, 30, 34, 16, 31, "#69462f");
// Arched front door.
box(18, 14, 20, 22, 15, 27, "#533a30");
box(19, 14, 28, 21, 15, 28, "#533a30");
box(18, 13, 20, 22, 13, 26, "#805337");
box(19, 13, 27, 21, 13, 28, "#805337");
for (let z = 21; z <= 26; z += 2) {
box(19, 12, z, 19, 12, z, "#a77347");
}
box(21, 12, 23, 21, 12, 24, "#f2c574");
box(18, 12, 20, 22, 12, 20, "#d2a364");
// Large round window with a warm brass rim and luminous teal glass.
for (let dx = -4; dx <= 4; dx++) {
for (let dz = -4; dz <= 4; dz++) {
const d = Math.sqrt(dx * dx + dz * dz);
const x = 29 + dx, z = 26 + dz;
if (d <= 3.65 && d >= 2.35) set(x, 13, z, "#dbad66");
else if (d < 2.35) set(x, 13, z, dz > 0 ? "#5de1ce" : "#219caa");
}
}
line(29, 12, 24, 29, 12, 28, 0, "#b78150");
line(27, 12, 26, 31, 12, 26, 0, "#b78150");
set(28, 12, 28, "#c5fff0");
// Pointed red roof: each side rises toward the central ridge.
for (let x = 12; x <= 37; x++) {
const height = 39 - Math.ceil(Math.abs(x - 24.5) * 0.63);
for (let y = 12; y <= 36; y++) {
const tile = (Math.floor(y / 4) + Math.floor(x / 3)) % 3;
box(x, y, 31, x, y, height - 1, "#793e3d");
set(x, y, height, ["#b9504a", "#c85e50", "#a84443"][tile]);
if (y % 5 === 0 && y > 12 && y < 36) {
set(x, y, height, "#d4715b");
}
}
set(x, 11, height - 1, "#713b39");
set(x, 12, height, "#df765c");
}
box(23, 11, 39, 26, 36, 39, "#8c3c3e");
box(24, 12, 40, 25, 35, 40, "#d47a5d");
// Warm lantern hanging beside the doorway.
line(13, 15, 29, 13, 15, 26, 0, "#b78b51");
box(12, 12, 24, 14, 14, 26, "#674735");
box(13, 11, 24, 13, 11, 25, "#ffcf70");
set(13, 10, 25, "#ffe69a");
box(12, 12, 27, 14, 14, 27, "#d0a567");
// Rope ladder, hanging past the front edge all the way to the ground.
for (const x of [19, 23]) {
line(x, 10, 19, x, 8, 16, 0, "#e0ba80");
line(x, 8, 16, x, 8, 0, 0, "#c49a68");
for (let z = 1; z <= 16; z += 4) set(x, 7, z, "#edd09b");
}
for (let z = 1; z <= 17; z += 3) {
box(19, 8, z, 23, 8, z, "#8b6040");
box(20, 7, z, 22, 7, z, "#c49761");
}
// Round leafy crown behind and above the cabin.
ellipsoid(24, 32, 39, 17, 11, 6, leaves[0]);
ellipsoid(12, 31, 38, 7, 8, 6, leaves[1]);
ellipsoid(37, 33, 39, 7, 8, 6, leaves[1]);
ellipsoid(24, 39, 39, 10, 5, 6, leaves[1]);
ellipsoid(22, 29, 42, 12, 7, 3, leaves[2]);
ellipsoid(11, 29, 40, 5, 5, 4, leaves[2]);
ellipsoid(37, 31, 41, 5, 5, 4, leaves[2]);
// Dappled leaves on exposed surfaces.
forEach((x, y, z, color) => {
if (!leaves.includes(color)) return;
if ((get(x, y - 1, z) === undefined || get(x, y, z + 1) === undefined)
&& rand() < 0.12) {
set(x, y, z, rand() < 0.7 ? "#75ae61" : "#a0bf70");
}
});
// Tiny magical glimmers nestled in the foliage.
for (const [x, y, z, c] of [
[13, 22, 40, "#d678de"], [18, 22, 43, "#78ecce"],
[31, 23, 43, "#d678de"], [38, 27, 42, "#86f1d4"],
[10, 27, 43, "#ed9bdc"], [27, 24, 44, "#a8f3df"]
]) {
set(x, y, z, c);
}
// Moss and cheerful little mushrooms around the roots.
for (const [x, y] of [[17, 21], [29, 20], [33, 31], [19, 35], [13, 27]]) {
ellipsoid(x, y, 0, 2, 1.5, 0.7, "#648450");
}
for (const [x, y, cap] of [
[14, 19, "#c86587"], [34, 20, "#e07970"],
[17, 35, "#bb70a5"], [32, 35, "#d77084"]
]) {
box(x, y, 0, x, y, 2, "#e9d9ad");
ellipsoid(x, y, 3, 2, 1.5, 1, cap);
set(x - 1, y - 1, 3, "#ffe6b4");
set(x + 1, y - 1, 3, "#ffe6b4");
}import { draw } from "./assets/voxel";
import { casaEnElArbol } from "./assets/casa-en-el-arbol";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, casaEnElArbol, 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 casa-en-el-arbol
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["casa-en-el-arbol"] })
# Queda en client/assets/casa-en-el-arbol.ts
# https://fogon.page/object/casa-en-el-arbol