← Basics3D assetfogon/carambola
Carambola
Drag to turn it// «Carambola» · gpt-6-sol (medium)
// Starfruit («Carambola»). Be faithful to the reference: keep thin parts thin (1–2 blocks: strings, necks, handles, legs, rods), keep its exact proportions and silhouette, and every visible detail (books on shelves, sound holes, tuning pegs, valves). Don't make it chunkier than the reference.
// Golden starfruit with five long, raised ribs and a squared-off lower end.
const pale = "#f7e66a";
const yellow = "#eed13f";
const gold = "#d6aa27";
const shadow = "#aa8120";
const olive = "#777a20";
// Lower body, with a narrow foot and uneven golden skin.
box(16, 18, 3, 33, 32, 20, yellow);
box(16, 18, 3, 16, 32, 20, gold);
box(17, 18, 3, 33, 18, 20, "#f1d651");
box(17, 19, 2, 32, 31, 3, gold);
box(15, 17, 1, 34, 32, 2, "#b99727");
box(16, 17, 2, 33, 17, 3, pale);
box(16, 18, 0, 19, 30, 1, olive);
box(30, 18, 0, 33, 30, 1, olive);
// Broad shoulders beneath the ribbed upper half.
box(14, 16, 20, 35, 33, 24, gold);
box(12, 14, 23, 37, 34, 25, yellow);
box(12, 14, 25, 36, 32, 26, pale);
box(14, 13, 24, 35, 14, 25, "#ffec77");
box(14, 16, 21, 16, 31, 23, "#b99322");
box(35, 17, 22, 36, 31, 24, "#c39420");
// Subtle irregular marks in the skin, kept flat against its faces.
for (let i = 0; i < 95; i++) {
const x = 18 + Math.floor(rand() * 15);
const z = 5 + Math.floor(rand() * 15);
const c = rand() < 0.54 ? "#e4bc38" : "#f8df66";
set(x, 17, z, c);
if (rand() < 0.23) set(x, 17, z + 1, c);
}
for (let i = 0; i < 35; i++) {
const y = 19 + Math.floor(rand() * 12);
const z = 5 + Math.floor(rand() * 14);
set(16, y, z, rand() < 0.5 ? "#b68c22" : "#dfb83c");
}
// Short, broken vertical streaks on the near end.
for (const [x, z, h] of [
[19, 7, 5], [22, 12, 4], [26, 6, 6],
[30, 10, 5], [32, 15, 3]
]) {
box(x, 16, z, x, 16, z + h, "#dfb538");
set(x, 16, z + h, pale);
}
// The upper fruit is solid, but its five lengthwise ribs rise into
// thin, slightly olive-tipped crests.
const profile = [
27, 29, 32, 34, 31, 29,
32, 36, 33, 30, 32, 38,
34, 30, 33, 36, 32, 29,
31, 34, 30, 28, 27
];
for (let x = 14; x <= 36; x++) {
for (let y = 13; y <= 34; y++) {
const endInset = Math.max(0, 4 - Math.min(y - 13, 34 - y));
const top = profile[x - 14] - endInset;
for (let z = 25; z <= top; z++) {
let c = z < 29 ? yellow : "#e6c934";
if (z >= top - 2) c = "#ead348";
if (z === top) c = (x % 4 === 1) ? olive : "#9a922a";
if (y < 16 && z >= top - 2) c = "#f1d95a";
set(x, y, z, c);
}
}
}
// Crisp continuous edges emphasize the slender raised ridges.
for (const [x, peak] of [[17, 34], [21, 36], [25, 38], [29, 36], [33, 34]]) {
for (let y = 17; y <= 31; y++) {
const tip = peak - (y > 28 ? Math.floor((y - 28) / 2) : 0);
set(x, y, tip, "#858320");
if (y % 5 !== 0) set(x, y, tip - 1, "#b7a52c");
}
}
// Little angular, pale star points at the near cut end.
for (const x of [16, 21, 25, 29, 34]) {
box(x, 12, 26, x + 1, 14, 27, pale);
set(x, 13, 28, "#fff080");
}
box(19, 12, 24, 31, 13, 25, "#f4dd5a");
// Fine amber seams where the upper and lower sections meet.
box(15, 16, 21, 33, 16, 21, "#b98f23");
box(17, 16, 22, 32, 16, 22, "#fff07b");
box(15, 17, 4, 34, 17, 4, "#f8e369");import { draw } from "./assets/voxel";
import { carambola } from "./assets/carambola";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, carambola, 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 carambola
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["carambola"] })
# It lands in client/assets/carambola.ts
# https://fogon.page/object/carambola