← Nature3D assetfogon/ombu
Ombú
Drag to turn it// «Ombú» · gpt-6-sol (medium)
// A massive Argentine ombú tree: a very thick, wide, swollen trunk with huge bulging roots spread over the ground like a low wall, and a broad flat dark green crown much wider than it is tall. Very sturdy and grand.
const bark = ["#865331", "#9c6339", "#ad7242", "#bc8050", "#c58b56"];
const greens = ["#205c32", "#28723a", "#318643", "#3b9949", "#4dab51", "#65bb5b"];
// A swollen, gently irregular trunk.
for (let z = 0; z <= 30; z++) {
const profile =
z < 5 ? 9.9 - z * 0.25 :
z < 15 ? 8.9 - (z - 5) * 0.23 :
z < 23 ? 6.6 + (z - 15) * 0.06 :
7.1 + (z - 23) * 0.27;
for (let x = 11; x <= 37; x++) for (let y = 11; y <= 37; y++) {
const dx = x - 24, dy = y - 24;
const angle = Math.atan2(dy, dx);
const radius = profile
+ 0.55 * Math.sin(angle * 7 + z * 0.075)
+ 0.38 * Math.sin(angle * 11 - z * 0.045);
if (dx * dx + dy * dy <= radius * radius) {
set(x, y, z, bark[2]);
}
}
}
// Huge buttress roots, spreading low across the ground.
for (let i = 0; i < 11; i++) {
const a = i * Math.PI * 2 / 11 + 0.12;
const reach = 18.8 + (i % 3) * 0.8;
for (let j = 0; j <= 9; j++) {
const t = j / 9;
const d = 7.1 + (reach - 7.1) * t;
const bend = 0.65 * Math.sin(t * Math.PI * 1.5 + i * 2.1) * t;
const x = 24 + Math.cos(a) * d - Math.sin(a) * bend;
const y = 24 + Math.sin(a) * d + Math.cos(a) * bend;
const width = 4.5 * (1 - t) + 1.25;
ellipsoid(x, y, 2.15 - 0.7 * t,
width, width * 0.82, 3.35 - 1.7 * t, bark[2]);
}
// Narrow bark creases following the raised tops of the roots.
const p = t => {
const d = 7.1 + (reach - 7.1) * t;
const bend = 0.65 * Math.sin(t * Math.PI * 1.5 + i * 2.1) * t;
return [
24 + Math.cos(a) * d - Math.sin(a) * bend,
24 + Math.sin(a) * d + Math.cos(a) * bend,
5.35 - 2.35 * t
];
};
const u = p(0.35), v = p(0.83);
line(u[0], u[1], u[2], v[0], v[1], v[2], 0, "#75472d");
}
// Broad limbs disappear into the foliage.
for (let i = 0; i < 7; i++) {
const a = i * Math.PI * 2 / 7 + 0.35;
line(24, 24, 25,
24 + Math.cos(a) * 15, 24 + Math.sin(a) * 15, 32,
2.2, bark[2]);
}
// Warm, lightly mottled bark and winding vertical grooves.
forEach((x, y, z, color) => {
if (!bark.includes(color)) return;
const exposed =
!get(x + 1, y, z) || !get(x - 1, y, z) ||
!get(x, y + 1, z) || !get(x, y - 1, z) ||
!get(x, y, z + 1);
if (!exposed) return;
const dx = x - 24, dy = y - 24;
const angle = Math.atan2(dy, dx);
let shade = 2;
if (z > 6 && z < 29) {
const winding = angle * 9 + 0.19 * Math.sin(z * 0.28) + z * 0.025;
if (Math.cos(winding) > 0.94) shade = 0;
}
if (shade !== 0) {
shade = 2 + (z > 12 ? 1 : 0) + (rand() < 0.12 ? -1 : 0);
if (rand() < 0.07) shade = 4;
}
set(x, y, z, bark[Math.max(0, Math.min(4, shade))]);
});
function leaves(cx, cy, cz, rx, ry, rz) {
const x0 = Math.ceil(cx - rx), x1 = Math.floor(cx + rx);
const y0 = Math.ceil(cy - ry), y1 = Math.floor(cy + ry);
const z0 = Math.ceil(cz - rz), z1 = Math.floor(cz + rz);
for (let x = x0; x <= x1; x++)
for (let y = y0; y <= y1; y++)
for (let z = z0; z <= z1; z++) {
const d =
((x - cx) / rx) ** 2 +
((y - cy) / ry) ** 2 +
((z - cz) / rz) ** 2;
if (d > 1) continue;
const height = (z - cz) / rz;
let shade = height < -0.4 ? 0 :
height < 0.08 ? 1 :
height < 0.55 ? 2 : 3;
if (height > 0.34 && rand() < 0.24) shade++;
if (rand() < 0.09) shade += rand() < 0.5 ? -1 : 1;
set(x, y, z, greens[Math.max(0, Math.min(5, shade))]);
}
}
// A wide, comparatively shallow, almost umbrella-flat crown.
leaves(24, 24, 34, 19.2, 18.8, 5.5);
for (let i = 0; i < 12; i++) {
const a = i * Math.PI * 2 / 12;
const d = 13.7 + (i % 3) * 0.35;
leaves(
24 + Math.cos(a) * d,
24 + Math.sin(a) * d,
33.4 + (i % 4) * 0.28,
7.0 + (i % 3) * 0.28,
6.9 + ((i + 1) % 3) * 0.25,
4.0 + (i % 2) * 0.45
);
}
// Rounded sunlit mounds break up the broad top without making it tall.
leaves(24, 24, 38.0, 10.5, 10.2, 3.5);
for (let i = 0; i < 10; i++) {
const a = i * Math.PI * 2 / 10 + 0.27;
const d = 10.2 + (i % 3) * 0.7;
leaves(
24 + Math.cos(a) * d,
24 + Math.sin(a) * d,
37.1 + (i % 3) * 0.23,
5.1 + (i % 2) * 0.6,
5.0 + ((i + 1) % 2) * 0.6,
2.25
);
}
// Small scattered highlights on the visible upper leaves.
forEach((x, y, z, color) => {
if (!greens.includes(color) || z < 36 || get(x, y, z + 1)) return;
if (rand() < 0.13) set(x, y, z, rand() < 0.62 ? greens[4] : greens[5]);
});import { draw } from "./assets/voxel";
import { ombu } from "./assets/ombu";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, ombu, 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 ombu
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["ombu"] })
# It lands in client/assets/ombu.ts
# https://fogon.page/object/ombu