← Pirates and sea3D assetfogon/faro
Faro
Drag to turn it// «Faro» · gpt-6-sol (medium)
// A tall round lighthouse on a small rocky base: white tower with thick red horizontal stripes, a small door at the bottom front, a black railing balcony near the top and a glass lantern room with a bright yellow light and a red cone roof.
const cx = 24, cy = 24;
function disc(z, radius, color, inner = -1) {
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 && d > inner) set(x, y, z, color);
}
}
// Low, uneven rocky island with a few sunny patches.
for (let z = 0; z <= 4; z++) {
for (let x = 5; x <= 43; x++) {
for (let y = 5; y <= 43; y++) {
const dx = x - cx, dy = y - cy;
const angle = Math.atan2(dy, dx);
const edge = 18 - z * 1.35
+ 1.1 * Math.sin(angle * 7)
+ 0.7 * Math.sin(angle * 13);
if (Math.hypot(dx, dy) > edge) continue;
const shades = ["#777a73", "#85877b", "#969789", "#a4a18d"];
let color = shades[Math.floor(rand() * shades.length)];
if (z >= 3 && rand() < 0.20) color = "#c5b38a";
set(x, y, z, color);
}
}
}
for (let i = 0; i < 55; i++) {
const a = rand() * Math.PI * 2, r = 13 + rand() * 5;
const x = Math.round(cx + Math.cos(a) * r);
const y = Math.round(cy + Math.sin(a) * r);
if (get(x, y, 3)) set(x, y, 4, rand() < 0.6 ? "#b0a997" : "#d0bc91");
}
// Solid, gently tapering striped tower.
for (let z = 4; z <= 33; z++) {
const radius = 10 - Math.floor((z - 4) / 10);
const red = (z >= 10 && z <= 14) ||
(z >= 20 && z <= 24) ||
(z >= 30 && z <= 33);
for (let x = cx - radius; x <= cx + radius; x++)
for (let y = cy - radius; y <= cy + radius; y++) {
if (Math.hypot(x - cx, y - cy) > radius) continue;
const front = y < cy;
let color;
if (red) {
color = front ? "#e9473e" : "#b92d31";
if (rand() < 0.10) color = "#d63834";
} else {
color = front ? "#fff4dd" : "#dfd8c5";
if (rand() < 0.10) color = "#eee5cf";
}
set(x, y, z, color);
}
}
// Heavy stone footing.
disc(4, 11, "#bbb6a4", 9);
disc(5, 10, "#e3d7bd", 9);
// Recessed plank door and its chunky dark arch.
box(21, 12, 5, 27, 14, 10, "#493b37");
box(22, 11, 5, 26, 12, 10, "#925932");
for (let x = 22; x <= 26; x++)
for (let z = 5; z <= 10; z++)
if (x === 22 || x === 25) set(x, 10, z, "#bb7940");
box(21, 12, 11, 27, 14, 11, "#493b37");
box(22, 12, 12, 26, 14, 12, "#493b37");
box(23, 11, 9, 25, 11, 10, "#342d2c");
set(25, 9, 7, "#ffd36a");
box(21, 9, 4, 27, 12, 4, "#c2b49a");
// Two small glowing tower windows, with bold frames.
function windowAt(y, z) {
box(22, y, z, 26, y, z + 5, "#434044");
box(23, y - 1, z + 1, 25, y - 1, z + 4, "#f6c967");
box(24, y - 2, z + 1, 24, y - 2, z + 4, "#ffe89a");
box(22, y - 2, z, 26, y - 2, z, "#4c4540");
box(22, y - 2, z + 5, 26, y - 2, z + 5, "#4c4540");
box(24, y - 3, z + 1, 24, y - 3, z + 4, "#544947");
}
windowAt(15, 17);
windowAt(16, 26);
// Projecting black balcony and gold-edged deck.
disc(33, 12, "#292c31");
disc(34, 12, "#424248");
disc(34, 10, "#c49a52", 9);
disc(35, 7, "#302e34");
disc(35, 12, "#25292e", 11);
for (let i = 0; i < 20; i++) {
const a = i * Math.PI * 2 / 20;
const x = Math.round(cx + 11.5 * Math.cos(a));
const y = Math.round(cy + 11.5 * Math.sin(a));
box(x, y, 35, x, y, 38, "#25282e");
}
for (let z of [36, 38]) disc(z, 12, "#292c32", 11);
// Lantern-room sill, glass walls, and stout metal mullions.
disc(35, 7, "#34363a");
disc(36, 7, "#45464a", 5);
for (let z = 37; z <= 40; z++) {
for (let x = cx - 6; x <= cx + 6; x++)
for (let y = cy - 6; y <= cy + 6; y++) {
const d = Math.hypot(x - cx, y - cy);
if (d > 5 && d <= 6) {
const glass = y < cy ? "#8bdce5" : "#54aab9";
set(x, y, z, rand() < 0.14 ? "#d5f7ed" : glass);
}
}
}
for (let i = 0; i < 8; i++) {
const a = i * Math.PI / 4;
const x = Math.round(cx + 6 * Math.cos(a));
const y = Math.round(cy + 6 * Math.sin(a));
box(x, y, 36, x, y, 41, "#30333a");
}
disc(40, 7, "#36363a", 6);
// Broad red cone roof, ending in a small golden finial.
const roofRadii = [8, 7, 5, 3, 1];
for (let i = 0; i < roofRadii.length; i++) {
const z = 41 + i, r = roofRadii[i];
for (let x = cx - r; x <= cx + r; x++)
for (let y = cy - r; y <= cy + r; y++)
if (Math.hypot(x - cx, y - cy) <= r)
set(x, y, z, y < cy ? "#e84738" : "#bd2d31");
}
disc(41, 8, "#8e292e", 7);
set(cx, cy, 45, "#ffce65");
// The animated beacon sits inside the glass, with a bright front-facing glow.
part("lanternLight", [cx, cy, 39]);
sphere(cx, cy, 38, 2, "#ffdd67");
sphere(cx, 19, 38, 2, "#fff2a1");
set(cx, 17, 38, "#fff9d6");
animate("lanternLight", {
type: "colors",
palette: ["#ffc442", "#ffe26d", "#fff4aa", "#fffbea"],
pattern: "pulse",
glow: 0.8
});import { draw } from "./assets/voxel";
import { faro } from "./assets/faro";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, faro, 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 faro
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["faro"] })
# It lands in client/assets/faro.ts
# https://fogon.page/object/faro