← Basics3D assetfogon/pera
Pera
Drag to turn it// «Pera» · gpt-6-sol (medium)
// Pear («Pera»).
// A golden voxel pear with a bent stem and one green leaf.
const profile = [
[0, 7.5], [2, 10.5], [5, 13.3], [9, 15.4],
[13, 16], [16, 15.4], [19, 13.5], [22, 11],
[25, 8.5], [28, 6.5], [31, 4.8], [32, 3.6]
];
function radiusAt(z) {
for (let i = 1; i < profile.length; i++) {
if (z <= profile[i][0]) {
const [za, ra] = profile[i - 1];
const [zb, rb] = profile[i];
return ra + (rb - ra) * (z - za) / (zb - za);
}
}
return 0;
}
// Solid, gently ribbed body.
for (let z = 0; z <= 32; z++) {
const r = radiusAt(z);
for (let x = 7; x <= 41; x++) {
for (let y = 8; y <= 40; y++) {
const dx = x - 24, dy = y - 24;
const angle = Math.atan2(dy, dx);
const rib = 0.32 * Math.cos(12 * angle + z * 0.18);
const d = Math.sqrt(dx * dx + (dy / 0.96) ** 2);
if (d > r + rib) continue;
let color = "#cbb548";
if (z < 7) color = "#bca13b";
else if (z > 24) color = "#d5c252";
if (dy > 4) color = "#bca63c";
if (rand() < 0.075) color = "#bba23c";
set(x, y, z, color);
}
}
}
// Bright, blocky ledges and small variations across the exposed skin.
forEach((x, y, z, color) => {
if (z > 32 || !color) return;
const top = !get(x, y, z + 1);
const front = !get(x, y - 1, z);
const side = !get(x + 1, y, z);
if (top) {
set(x, y, z, rand() < 0.22 ? "#f0df75" : "#e6d164");
} else if (front) {
set(x, y, z, rand() < 0.16 ? "#e7d160" :
rand() < 0.12 ? "#b69b38" : "#d6bd4c");
} else if (side && rand() < 0.34) {
set(x, y, z, "#ddc65a");
}
});
// Short, crooked woody stem.
box(23, 23, 31, 25, 25, 33, "#68502a");
box(23, 23, 33, 24, 24, 36, "#79592d");
box(24, 23, 36, 25, 24, 39, "#624721");
box(25, 24, 39, 26, 25, 41, "#715329");
set(23, 22, 34, "#9b7138");
set(24, 22, 36, "#a27b40");
set(25, 23, 39, "#a17a3c");
// A single leaf stretches upward and to the right from the stem.
line(26, 25, 39, 38, 29, 43, 0, "#405c26");
for (let x = 26; x <= 39; x++) {
const t = (x - 26) / 13;
const cy = 25 + 4 * t;
const cz = 39 + 4 * t;
const width = 0.3 + 2.65 * Math.pow(Math.sin(Math.PI * t), 0.8);
const thick = 0.4 + 1.5 * Math.sin(Math.PI * t);
for (let y = Math.floor(cy - width); y <= Math.ceil(cy + width); y++) {
for (let z = Math.floor(cz - thick); z <= Math.ceil(cz + thick); z++) {
const shape = ((y - cy) / width) ** 2 +
((z - cz) / thick) ** 2;
if (shape > 1) continue;
const upper = z >= cz;
let green = upper ? "#71983d" : "#496b2d";
if (upper && rand() < 0.35) green = "#8aab4d";
if (!upper && rand() < 0.25) green = "#385823";
set(x, y, z, green);
}
}
}
line(28, 25, 39, 37, 28, 42, 0, "#597c30");import { draw } from "./assets/voxel";
import { pera } from "./assets/pera";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, pera, 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 pera
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["pera"] })
# It lands in client/assets/pera.ts
# https://fogon.page/object/pera