← Nature3D assetfogon/arbol-seco
Árbol seco
Drag to turn it// «Árbol seco» · gpt-6-sol (medium)
// A dead leafless tree: a gnarled grey-brown trunk splitting into crooked bare branches that twist upward and outward, thin twigs at the tips, a hollow knot hole on the front, no leaves at all.
const bark = "#837568";
const light = "#a99883";
const sun = "#b9a88f";
const shade = "#665c55";
const deep = "#4d4945";
function limb(points) {
for (let i = 0; i < points.length - 1; i++) {
const a = points[i], b = points[i + 1];
const distance = Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
const steps = Math.ceil(distance * 2);
for (let j = 0; j <= steps; j++) {
const t = j / steps;
sphere(
a[0] + (b[0] - a[0]) * t,
a[1] + (b[1] - a[1]) * t,
a[2] + (b[2] - a[2]) * t,
a[3] + (b[3] - a[3]) * t,
bark
);
}
}
}
// Wide, crooked roots anchor the tree to the ground.
sphere(24, 24, 3, 5.6, bark);
[
[[24,24,4,3.5],[20,22,2,2.5],[15,19,0,1.4]],
[[25,24,4,3.5],[29,21,2,2.4],[35,18,0,1.2]],
[[24,25,4,3.3],[22,29,2,2.4],[19,35,0,1.2]],
[[25,25,4,3.2],[29,29,2,2.2],[34,33,0,1.1]],
[[23,23,3,2.8],[21,19,1,2],[19,16,0,1]]
].forEach(limb);
// The trunk leans one way, then twists back before dividing.
limb([[24,24,2,5.5],[23,24,9,5],[25,25,16,4.2],
[23,25,23,3.3],[24,24,29,2.5],[26,24,34,1.5]]);
// Large crooked branches, followed by increasingly fine bare twigs.
[
[[23,25,22,3],[18,25,26,2.8],[14,24,31,2.2],[10,23,34,1.7],[6,22,39,0.8]],
[[15,24,30,1.7],[12,19,33,1.2],[10,15,38,0.7]],
[[10,23,34,1.5],[8,27,38,0.9],[5,29,41,0.5]],
[[25,25,19,3.1],[30,25,24,2.7],[34,24,29,2.2],[39,22,33,1.6],[43,20,39,0.7]],
[[34,24,29,1.8],[36,28,35,1.2],[39,30,40,0.6]],
[[39,22,33,1.5],[40,17,37,0.9],[42,15,42,0.5]],
[[24,26,27,2.3],[22,30,32,2],[18,34,36,1.4],[14,39,41,0.6]],
[[18,34,36,1.3],[19,38,40,0.8],[20,41,43,0.5]],
[[23,30,32,1.6],[26,35,37,1.1],[27,39,42,0.5]],
[[23,23,26,2.2],[19,19,30,1.8],[15,15,34,1.3],[11,10,40,0.6]],
[[15,15,34,1.2],[17,11,39,0.7],[18,8,42,0.5]],
[[25,24,29,2.3],[29,22,34,1.7],[31,20,39,1],[32,18,44,0.5]],
[[29,22,34,1.5],[26,18,39,0.9],[25,15,43,0.5]],
[[26,24,33,1.5],[24,27,39,0.9],[23,28,44,0.5]]
].forEach(limb);
// Give exposed bark a warm upper edge and darker undersides.
forEach((x, y, z, color) => {
if (color !== bark) return;
const top = !get(x, y, z + 1);
const bottom = !get(x, y, z - 1);
const front = !get(x, y - 1, z);
const r = rand();
if (top) set(x, y, z, r < 0.65 ? sun : light);
else if (bottom) set(x, y, z, shade);
else if (front) set(x, y, z, r < 0.18 ? light : r < 0.25 ? shade : bark);
else if (r < 0.055) set(x, y, z, light);
else if (r < 0.09) set(x, y, z, shade);
});
// Short, broken bark grooves on the front of the trunk and roots.
line(20, 21, 5, 21, 20, 9, 0, shade);
line(21, 20, 10, 22, 20, 12, 0, deep);
line(28, 22, 7, 29, 23, 11, 0, shade);
line(27, 21, 19, 27, 21, 22, 0, shade);
line(21, 23, 21, 21, 23, 24, 0, shade);
line(18, 21, 2, 15, 19, 0, 0, shade);
line(29, 22, 2, 33, 19, 0, 0, shade);
// Raised oval rim and a deep, unmistakable hollow knot on the front.
for (let x = 20; x <= 28; x++) {
for (let z = 11; z <= 19; z++) {
const d = ((x - 24) / 3.5) ** 2 + ((z - 15) / 4) ** 2;
if (d <= 1 && d > 0.38) {
set(x, 19, z, z >= 16 ? light : shade);
if (d > 0.73) set(x, 18, z, z >= 16 ? "#ab9780" : "#62564d");
}
if (d <= 0.38) {
set(x, 19, z, deep);
set(x, 20, z, "#30302e");
if (d < 0.24) set(x, 18, z, "#292b2a");
}
}
}
set(23, 19, 16, "#514a42");
set(25, 19, 13, "#554d43");import { draw } from "./assets/voxel";
import { arbolSeco } from "./assets/arbol-seco";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, arbolSeco, 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 arbol-seco
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["arbol-seco"] })
# It lands in client/assets/arbol-seco.ts
# https://fogon.page/object/arbol-seco