← Basics3D assetfogon/medio-coco
Medio coco
Drag to turn it// «Medio coco» · gpt-6-sol (medium)
// Coconut half («Medio coco»).
// Half a coconut, cut side up.
const cx = 24, cy = 24;
const outerCenter = 20.7, outerRadius = 21.3;
const innerRadius = 17.1;
const TAU = Math.PI * 2;
function hash(a, b) {
const n = Math.sin(a * 127.1 + b * 311.7) * 43758.5453;
return n - Math.floor(n);
}
for (let z = 0; z <= 24; z++) {
const roundRadius = Math.sqrt(Math.max(0,
outerRadius * outerRadius - (z - outerCenter) ** 2));
for (let x = 2; x <= 46; x++) {
for (let y = 2; y <= 46; y++) {
const dx = x - cx, dy = y - cy;
const r = Math.hypot(dx, dy);
const a = Math.atan2(dy, dx);
const grain = hash(x, y);
const edge = roundRadius
+ 0.32 * Math.sin(19 * a + 0.3)
+ 0.23 * Math.sin(43 * a + z * 0.12)
+ (grain - 0.5) * (z < 21 ? 0.85 : 0.35);
if (r > edge) continue;
let cavityFloor = 23.2;
if (r < innerRadius) {
cavityFloor = 23.2 - 14.1 *
Math.sqrt(Math.max(0, 1 - (r / innerRadius) ** 2));
if (z > cavityFloor + 0.35) continue;
}
const meat = (r < innerRadius && z >= cavityFloor - 2.2) ||
(r >= 16.8 && r < 19.15 && z >= 22);
const lip = z >= 22 && r >= 19.15;
if (meat) {
const depth = 24 - z;
const light = hash(x + z * 7, y - z * 3);
let color;
if (depth < 2 || (r > 16.8 && z >= 23)) {
color = light < 0.20 ? "#dad9cf" :
light < 0.73 ? "#f0eee5" : "#faf8ee";
} else if (depth < 8) {
color = light < 0.22 ? "#bcbdb5" :
light < 0.73 ? "#d8d8d0" : "#e9e9e1";
} else {
color = light < 0.35 ? "#aaa9a2" :
light < 0.83 ? "#c4c4ba" : "#d9d9d0";
}
set(x, y, z, color);
} else {
const streak = Math.sin(a * 94 + 0.55 * Math.sin(z * 0.65 + a * 17));
const fleck = hash(x * 3 + z * 11, y * 5 - z * 7);
const underside = z < 9;
let color = streak < -0.52 ? "#62361e" :
streak > 0.65 ? "#a35c2d" : "#854821";
if (underside && streak < 0.45) color = "#70391d";
if (fleck < 0.10) color = "#61351d";
if (fleck > 0.87) color = underside ? "#8b4924" : "#b16b36";
if (lip) color = fleck < 0.27 ? "#70391e" :
fleck > 0.74 ? "#a55c2d" : "#874720";
set(x, y, z, color);
}
}
}
}
// Short, uneven fibers and raised grain on the outside of the husk.
for (let i = 0; i < 220; i++) {
const angle = rand() * TAU;
const start = 2 + Math.floor(rand() * 17);
const length = 2 + Math.floor(rand() * 7);
const shade = ["#62351c", "#774020", "#9b5328", "#ad6532"][Math.floor(rand() * 4)];
for (let z = start; z < Math.min(22, start + length); z++) {
const radius = Math.sqrt(Math.max(0,
outerRadius * outerRadius - (z - outerCenter) ** 2));
const twist = angle + 0.012 * Math.sin(z * 0.8 + i);
const x = Math.round(cx + (radius + 0.18) * Math.cos(twist));
const y = Math.round(cy + (radius + 0.18) * Math.sin(twist));
if (get(x, y, z) === undefined ||
!["#faf8ee", "#f0eee5", "#e9e9e1"].includes(get(x, y, z))) {
set(x, y, z, shade);
}
}
}import { draw } from "./assets/voxel";
import { medioCoco } from "./assets/medio-coco";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, medioCoco, 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 medio-coco
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["medio-coco"] })
# It lands in client/assets/medio-coco.ts
# https://fogon.page/object/medio-coco