← Basics3D assetfogon/cerezas
Cerezas
Drag to turn it// «Cerezas» · gpt-6-sol (medium)
// Cherries («Cerezas»).
// Two cherries, one in front of the other.
function cherry(cx, cy, cz, rx, ry, rz, seed) {
for (let x = Math.floor(cx - rx); x <= Math.ceil(cx + rx); x++)
for (let y = Math.floor(cy - ry); y <= Math.ceil(cy + ry); y++)
for (let z = Math.max(0, Math.floor(cz - rz)); z <= Math.ceil(cz + rz); z++) {
const dx = (x - cx) / rx;
const dy = (y - cy) / ry;
const dz = (z - cz) / rz;
// Slightly flattened top and a subtly uneven, pixelated outline.
const ripple = 0.035 * Math.sin(x * 1.7 + seed) * Math.cos(y * 1.3);
if (dx * dx + dy * dy + dz * dz > 1 + ripple) continue;
const n = rand();
let color;
if (z < cz - 6) color = n < 0.18 ? "#8d1429" : n < 0.55 ? "#a51730" : "#b51b32";
else if (z < cz + 2) color = n < 0.15 ? "#aa172d" : n < 0.68 ? "#c51d36" : "#d82a40";
else color = n < 0.2 ? "#b91b31" : n < 0.75 ? "#d6263d" : "#e4384a";
// Narrow dark-red facets on the sides of the fruit.
if (Math.abs(dx) > 0.68 && z < cz + 3 && (x + 2 * y) % 5 === 0)
color = "#a8172e";
set(x, y, z, color);
}
// Small dimple beneath the stem.
for (let x = cx - 2; x <= cx + 2; x++)
for (let y = cy - 2; y <= cy + 2; y++)
if (Math.abs(x - cx) + Math.abs(y - cy) < 4)
set(x, y, Math.round(cz + rz - 1), "#a91b30");
}
// The rear cherry is higher and partly hidden by the front one.
cherry(31, 29, 18.5, 10.5, 9.7, 10.8, 2);
cherry(17, 17, 12, 11.5, 10.5, 12, 5);
// Little patches of reflected light on the forward-facing skins.
function glint(cx, cy, cz, rx, ry, rz, pixels) {
for (const [x, z, color] of pixels) {
const dx = (x - cx) / rx, dz = (z - cz) / rz;
const span = 1 - dx * dx - dz * dz;
if (span <= 0) continue;
const y = Math.ceil(cy - ry * Math.sqrt(span));
set(x, y, z, color);
}
}
glint(17, 17, 12, 11.5, 10.5, 12, [
[21, 20, "#ef7773"], [22, 21, "#ffd5bd"], [23, 21, "#fff0db"],
[24, 20, "#ffe0c8"], [22, 19, "#fff1d9"], [23, 19, "#f9c5b5"],
[24, 18, "#f5a099"], [21, 18, "#ee7778"], [25, 17, "#e77a79"]
]);
glint(31, 29, 18.5, 10.5, 9.7, 10.8, [
[34, 25, "#f28d89"], [35, 26, "#ffe4cc"], [36, 25, "#fff0da"],
[37, 24, "#f7ccb8"], [35, 24, "#ffe8cf"], [36, 23, "#f5aaa1"],
[34, 23, "#ed7777"]
]);
// Paired, angular olive stems meet above the cherries.
line(17, 17, 23, 17, 17, 29, 1, "#695e27");
line(17, 17, 29, 20, 19, 34, 1, "#75682b");
line(20, 19, 34, 23, 23, 38, 1, "#807631");
line(23, 23, 38, 26, 25, 39, 1, "#665b28");
line(31, 29, 28, 30, 29, 34, 1, "#635c2b");
line(30, 29, 34, 27, 27, 38, 1, "#70672a");
line(27, 27, 38, 25, 25, 39, 1, "#796d2c");
// Warm sunlit edges make the stems legible against the fruit.
line(16, 16, 25, 16, 16, 29, 0, "#a39943");
line(19, 18, 31, 21, 20, 35, 0, "#ad9d49");
line(29, 28, 32, 28, 27, 35, 0, "#a7973c");
// A single broad leaf grows to the right of their joined stems.
for (let x = 26; x <= 40; x++)
for (let y = 22; y <= 32; y++)
for (let z = 36; z <= 43; z++) {
const u = (x - 33) / 7.5;
const v = (y - (26 + (x - 26) * 0.18)) / 4.4;
const w = (z - (39.5 - (x - 33) * 0.12)) / 3.5;
if (u * u + v * v + w * w > 1) continue;
let color = z >= 41 ? "#79a743" : z <= 38 ? "#477a36" : "#5e973c";
if (rand() < 0.19) color = z >= 40 ? "#94b657" : "#3d7934";
set(x, y, z, color);
}
// Leaf midrib and a few chunky veins.
line(26, 25, 40, 38, 28, 39, 0, "#a6b95c");
line(31, 26, 40, 33, 23, 41, 0, "#92b558");
line(35, 27, 39, 37, 31, 40, 0, "#83aa49");
line(28, 25, 40, 31, 23, 41, 0, "#b2bd65");import { draw } from "./assets/voxel";
import { cerezas } from "./assets/cerezas";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, cerezas, 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 cerezas
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["cerezas"] })
# It lands in client/assets/cerezas.ts
# https://fogon.page/object/cerezas