← Nature3D assetfogon/tocon
Tocón
Drag to turn it// «Tocón» · gpt-6-sol (medium)
// A tree stump: a short wide cylinder of bark with roots spreading out on the ground and a flat top showing light tan growth rings.
const cx = 24, cy = 24;
const bark = ["#a65d30", "#b96d37", "#cb7b3e", "#d78a48"];
const darkBark = "#844627";
// Chunky roots radiate across the ground.
const angles = [-1.57, -0.82, -0.12, 0.59, 1.36, 2.16, 2.87, 3.61];
for (let i = 0; i < angles.length; i++) {
const a = angles[i];
const dx = Math.cos(a), dy = Math.sin(a);
const bend = i % 2 ? 1.1 : -0.8;
const px = -dy * bend, py = dx * bend;
line(cx + dx * 8, cy + dy * 8, 5,
cx + dx * 15 + px, cy + dy * 15 + py, 2, 3, "#a96032");
line(cx + dx * 15 + px, cy + dy * 15 + py, 2,
cx + dx * 20 + px, cy + dy * 20 + py, 1, 2, "#b66a37");
line(cx + dx * 12 + px * 0.5, cy + dy * 12 + py * 0.5, 5,
cx + dx * 18 + px, cy + dy * 18 + py, 3, 0, "#dc9552");
line(cx + dx * 17 + px, cy + dy * 17 + py, 1,
cx + dx * 20 + px, cy + dy * 20 + py, 1, 0, "#854928");
}
// Solid, gently irregular trunk with a flared foot.
for (let z = 0; z <= 16; z++) {
const radius = 11.7 + (z < 5 ? (5 - z) * 0.43 : 0);
for (let x = 9; x <= 39; x++) for (let y = 9; y <= 39; y++) {
const dx = x - cx, dy = y - cy;
const a = Math.atan2(dy, dx);
const edge = radius + 0.37 * Math.sin(a * 9 + z * 0.17)
+ 0.22 * Math.sin(a * 17 - z * 0.12);
const d = Math.hypot(dx, dy);
if (d > edge) continue;
let shade = 1;
if (z >= 11) shade++;
if (x < 22 && z >= 5) shade++;
if (z <= 3) shade--;
if (rand() < 0.12) shade += rand() < 0.5 ? -1 : 1;
// Narrow, broken vertical furrows in the outer bark.
const furrow = Math.abs(Math.sin(a * 16 + 0.26 * Math.sin(z * 0.38)));
const groove = d > edge - 1.6 && furrow < 0.16 &&
(z + Math.floor(a * 19)) % 9 !== 0;
set(x, y, z, groove ? darkBark : bark[Math.max(0, Math.min(3, shade))]);
}
}
// Exposed cut surface: light wood with wobbly concentric growth rings.
for (let x = 12; x <= 36; x++) for (let y = 12; y <= 36; y++) {
const dx = x - 24.2, dy = y - 23.7;
const a = Math.atan2(dy, dx);
const r = Math.hypot(dx, dy);
const warped = r + 0.34 * Math.sin(a * 5 + r * 0.3)
+ 0.18 * Math.sin(a * 11);
if (warped > 10.8) continue;
let color = "#f4c77e";
if (warped < 2.3) color = "#ffe0a0";
if (rand() < 0.12) color = "#f9d28d";
for (const ring of [3.2, 5.7, 8.1, 10.0]) {
if (Math.abs(warped - ring) < 0.42) color = "#d99e5c";
}
set(x, y, 17, color);
}
// A small heartwood curl makes the rings legible from above.
set(24, 24, 17, "#e6ad68");
set(25, 24, 17, "#e6ad68");
set(24, 23, 17, "#ffe0a0");
// A few mossy flecks tucked into the shaded bark and roots.
for (let i = 0; i < 85; i++) {
const a = rand() * Math.PI * 2;
const z = Math.floor(rand() * 7);
const r = 11.7 + (z < 5 ? (5 - z) * 0.43 : 0);
const x = Math.round(cx + Math.cos(a) * r);
const y = Math.round(cy + Math.sin(a) * r);
if (get(x, y, z) && rand() < 0.55)
set(x, y, z, rand() < 0.45 ? "#71a646" : "#8dbb52");
}
// One rounded knot on the front face.
set(28, 13, 8, "#774327");
set(28, 13, 9, "#8e4b29");
set(29, 13, 8, "#e09a55");import { draw } from "./assets/voxel";
import { tocon } from "./assets/tocon";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, tocon, 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 tocon
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["tocon"] })
# It lands in client/assets/tocon.ts
# https://fogon.page/object/tocon