← Gear3D assetfogon/brujula
Brújula
Drag to turn it// «Brújula» · gpt-6-sol (medium)
// A big chunky brass compass lying on the floor: a round brass case with a hinged lid opened upright at the back (+y), a cream dial with N E S W marks and a red and white needle.
const brass = "#a56b25";
const brassDark = "#754618";
const brassLight = "#d9a84c";
const gold = "#f2c966";
const ink = "#55432d";
const cx = 24, cy = 23;
function disk(radius, z, color) {
for (let x = cx - radius; x <= cx + radius; x++)
for (let y = cy - radius; y <= cy + radius; y++)
if ((x - cx) ** 2 + (y - cy) ** 2 <= radius ** 2)
set(x, y, z, color);
}
// Heavy, stepped brass case.
for (let z = 0; z <= 9; z++) {
const radius = z === 0 ? 17 : z === 1 || z === 9 ? 18 : 19;
for (let x = cx - radius; x <= cx + radius; x++)
for (let y = cy - radius; y <= cy + radius; y++) {
const d = Math.hypot(x - cx, y - cy);
if (d > radius) continue;
const edge = d > radius - 2;
let color = z < 3 ? brassDark : z > 7 ? brassLight : brass;
if (edge && z >= 3 && z <= 7) color = rand() < 0.16 ? brassLight : brass;
set(x, y, z, color);
}
}
// Raised bezel and recessed cream dial.
disk(17, 10, brassLight);
disk(15, 10, "#ede0b9");
disk(14, 11, "#f4e8ca");
for (let x = 5; x <= 43; x++)
for (let y = 4; y <= 42; y++) {
const d = Math.hypot(x - cx, y - cy);
if (d >= 15 && d <= 18) {
set(x, y, 10, d > 17 ? brassDark : brassLight);
if (d >= 16 && d <= 17.5) set(x, y, 11, gold);
} else if (d < 14 && rand() < 0.045) {
set(x, y, 11, "#e9dab5");
}
}
// Minute ticks around the dial.
for (let i = 0; i < 32; i++) {
const a = i * Math.PI / 16;
const r = i % 4 === 0 ? 12.8 : 13.5;
set(Math.round(cx + Math.sin(a) * r),
Math.round(cy + Math.cos(a) * r), 12,
i % 4 === 0 ? brass : "#8b7958");
}
// Big, legible cardinal letters, viewed from above.
function letter(x, y, rows) {
rows.forEach((row, j) => {
for (let i = 0; i < row.length; i++)
if (row[i] === "#") set(x + i, y + j, 12, ink);
});
}
letter(22, 32, ["#...#", "##..#", "#.#.#", "#..##", "#...#"]); // N
letter(32, 21, ["#####", "#....", "####.", "#....", "#####"]); // E
letter(22, 10, [".####", "#....", ".###.", "....#", "####."]); // S
letter(11, 21, ["#...#", "#...#", "#.#.#", "##.##", "#...#"]); // W
// Dark needle outline, white south half and ruby-red north arrow.
box(22, 17, 12, 26, 30, 12, ink);
for (let y = 16; y <= 23; y++) {
const halfWidth = y < 19 ? 0 : y < 22 ? 1 : 2;
box(cx - halfWidth, y, 13, cx + halfWidth, y, 13,
y < 20 ? "#ffffff" : "#e7e8dc");
}
for (let y = 24; y <= 31; y++) {
const halfWidth = y >= 30 ? 0 : y >= 28 ? 1 : 2;
box(cx - halfWidth, y, 13, cx + halfWidth, y, 13,
y >= 29 ? "#fa5747" : "#c8292c");
}
cylinder(cx, cy, 13, 2, 2, brassDark);
set(cx, cy, 15, gold);
// Substantial hinge across the back of the case.
box(15, 39, 6, 33, 43, 10, brassDark);
box(17, 38, 8, 31, 42, 11, brassLight);
for (const x of [17, 24, 31]) {
box(x - 2, 38, 8, x + 2, 43, 11, brass);
set(x, 38, 10, gold);
}
// Upright circular lid: thick brass back, dark inset, bright raised rim.
const lidZ = 26;
for (let x = 7; x <= 41; x++)
for (let z = 9; z <= 43; z++) {
const d = Math.hypot(x - cx, z - lidZ);
if (d > 17) continue;
for (let y = 40; y <= 42; y++)
set(x, y, z, y === 42 ? brassDark : brass);
if (d <= 15) {
set(x, 39, z, brassLight);
set(x, 38, z, d <= 13 ? "#264448" : brassLight);
if (d <= 13) set(x, 37, z, rand() < 0.06 ? "#305257" : "#29494d");
}
if (d >= 13 && d <= 17) {
for (let y = 37; y <= 39; y++)
set(x, y, z, d > 15.5 ? brass : gold);
if (d >= 15 && d <= 16) set(x, 36, z, brassLight);
}
}
// Engraved gold compass rose on the inside of the lid.
line(24, 36, 16, 24, 36, 36, 1, brassLight);
line(14, 36, 26, 34, 36, 26, 1, brassLight);
line(18, 36, 20, 30, 36, 32, 0, gold);
line(18, 36, 32, 30, 36, 20, 0, gold);
for (let d = 0; d <= 9; d++) {
const w = d < 3 ? 2 : d < 6 ? 1 : 0;
for (let dx = -w; dx <= w; dx++) {
set(cx + dx, 35, lidZ + d, d > 5 ? gold : brassLight);
set(cx + dx, 35, lidZ - d, d > 5 ? gold : brassLight);
set(cx + d, 35, lidZ + dx, d > 5 ? gold : brassLight);
set(cx - d, 35, lidZ + dx, d > 5 ? gold : brassLight);
}
}
// Sapphire-colored center boss and four lid rivets.
box(22, 34, 24, 26, 36, 28, brassDark);
box(23, 33, 25, 25, 34, 27, "#246ca0");
set(24, 32, 27, "#79bde0");
for (const [x, z] of [[24, 39], [24, 13], [11, 26], [37, 26]]) {
box(x - 1, 35, z - 1, x + 1, 36, z + 1, brassDark);
set(x, 34, z, gold);
}import { draw } from "./assets/voxel";
import { brujula } from "./assets/brujula";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, brujula, 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 brujula
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["brujula"] })
# It lands in client/assets/brujula.ts
# https://fogon.page/object/brujula