← Basics3D assetfogon/corno-frances
Corno francés
Drag to turn it// «Corno francés» · gpt-6-sol (medium)
// French horn («Corno francés»). 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.
const gold = "#bd8a32";
const light = "#e5b955";
const bright = "#f5d477";
const shadow = "#86602a";
const dark = "#604321";
function pipe(points, colors = [gold, light], double = false) {
for (let i = 1; i < points.length; i++) {
const a = points[i - 1], b = points[i];
const n = Math.ceil(Math.max(
Math.abs(b[0] - a[0]), Math.abs(b[1] - a[1]), Math.abs(b[2] - a[2])
) * 2);
for (let j = 0; j <= n; j++) {
const t = j / n;
const x = Math.round(a[0] + (b[0] - a[0]) * t);
const y = Math.round(a[1] + (b[1] - a[1]) * t);
const z = Math.round(a[2] + (b[2] - a[2]) * t);
set(x, y, z, colors[(i + Math.floor(j / 5)) % colors.length]);
if (double) {
set(x, y + 1, z, shadow);
if (j % 3 !== 0) set(x, y, z + 1, light);
}
}
}
}
// The long, low return bend of the horn touches the floor.
pipe([
[13, 19, 18], [11, 19, 15], [10, 19, 9], [11, 19, 5],
[14, 19, 2], [18, 19, 0], [22, 19, 0], [29, 19, 5],
[33, 19, 9], [35, 19, 14], [35, 19, 20]
], [gold, "#a8752b", light], true);
// Smaller, separate turns visible through the large bend.
pipe([
[17, 15, 18], [17, 15, 9], [19, 15, 6], [23, 15, 5],
[28, 15, 7], [31, 15, 11], [31, 15, 21]
], [light, gold, bright]);
pipe([
[22, 12, 18], [22, 12, 10], [24, 12, 8], [28, 12, 9],
[30, 12, 12], [30, 12, 22]
], [gold, light]);
pipe([
[26, 22, 17], [26, 22, 8], [28, 22, 6], [32, 22, 8],
[34, 22, 13]
], [shadow, gold, light]);
// Hollow, tilted bell: its near rim is lower than its far rim.
const bx = 17.5, by = 17;
for (let z = 14; z <= 36; z++) {
for (let y = 6; y <= 29; y++) {
for (let x = 4; x <= 31; x++) {
const h = z - 0.50 * (y - by);
if (h < 16.5 || h > 30.4) continue;
const rx = 3.1 + (h - 16.5) * 0.67;
const ry = 2.3 + (h - 16.5) * 0.52;
const r = Math.sqrt(
((x - bx) / rx) ** 2 + ((y - by) / ry) ** 2
);
const wall = h < 21 ? 0.30 : 0.145;
if (r <= 1.035 && r >= 1 - wall) {
const rim = h > 29.1;
const c = rim
? (rand() < 0.42 ? bright : light)
: y > by + 2 ? (rand() < 0.3 ? light : gold)
: (rand() < 0.23 ? shadow : "#a77730");
set(x, y, z, c);
}
}
}
}
// Concave inner surface, with fine radial folds in the metal.
for (let y = 7; y <= 27; y++) {
for (let x = 5; x <= 30; x++) {
const dx = (x - bx) / 12.2;
const dy = (y - by) / 9.4;
const r = Math.sqrt(dx * dx + dy * dy);
if (r > 0.91) continue;
const h = 18.2 + 11.0 * Math.pow(r, 1.55);
const z = Math.round(h + 0.50 * (y - by));
const angle = Math.atan2(dy, dx);
const rib = Math.cos(angle * 25) > 0.76;
let c;
if (r < 0.28) c = rand() < 0.3 ? "#9b6928" : "#b98230";
else if (y > 17) c = rib ? "#98702f" : (rand() < 0.35 ? shadow : "#765022");
else c = rib ? bright : (rand() < 0.38 ? light : "#c69036");
set(x, y, z, c);
if (r > 0.55 && y > 17) set(x, y, z - 1, dark);
}
}
// Crisp, irregular one-block rolled edge around the bell.
for (let i = 0; i < 112; i++) {
const a = i * Math.PI * 2 / 112;
const x = Math.round(bx + 12.2 * Math.cos(a));
const y = Math.round(by + 9.4 * Math.sin(a));
const z = Math.round(30 + 0.50 * (y - by));
set(x, y, z, i % 7 < 3 ? bright : light);
if (i % 4 !== 0) set(x, y, z - 1, gold);
}
// Bell throat flowing into the large lower tube.
pipe([[17, 17, 19], [16, 17, 16], [14, 18, 13],
[12, 19, 11], [11, 19, 8]], [shadow, gold, light], true);
// Three slim valve casings and their raised finger buttons.
for (let i = 0; i < 3; i++) {
const x = 28 + i * 3;
const y = 13 + (i === 2 ? 1 : 0);
box(x, y, 15, x, y, 26, i === 1 ? "#a97830" : gold);
line(x, y, 17, x, y + 4, 17, 0, light);
line(x, y, 23, x, y + 4, 23, 0, shadow);
box(x, y, 27, x, y, 29, "#d5ac54");
box(x - 1, y - 1, 30, x + 1, y, 30, "#e9cb79");
set(x, y - 1, 31, "#fff0b3");
}
// Narrow connecting slides, each retaining a visible open center.
pipe([[28, 14, 19], [26, 11, 19], [26, 11, 14],
[29, 11, 12], [32, 11, 14], [32, 14, 18]], [light, gold]);
pipe([[31, 14, 21], [33, 10, 21], [35, 10, 19],
[35, 10, 15], [33, 14, 13]], [gold, bright]);
pipe([[34, 15, 24], [37, 15, 24], [37, 18, 23],
[35, 19, 21]], [light, "#aa792e"]);
// Diagonal leadpipe rising behind the bell toward the mouthpiece.
pipe([
[24, 24, 26], [27, 26, 29], [31, 28, 32],
[34, 30, 35], [36, 31, 38], [37, 32, 41]
], [gold, light, bright]);
pipe([[26, 26, 28], [29, 27, 27], [32, 28, 27],
[34, 28, 29]], [shadow, light]);
// Small silver mouthpiece and its slender gold shank.
box(37, 32, 39, 37, 32, 42, "#be933d");
box(36, 31, 43, 38, 33, 43, "#d5d5c9");
box(36, 31, 44, 38, 33, 44, "#f3f1e7");
set(37, 32, 44, "#555d5d");
set(37, 32, 42, "#faf0cb");import { draw } from "./assets/voxel";
import { cornoFrances } from "./assets/corno-frances";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, cornoFrances, 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 corno-frances
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["corno-frances"] })
# It lands in client/assets/corno-frances.ts
# https://fogon.page/object/corno-frances