← Ancient and prehistory3D assetfogon/volcan
Volcán
Drag to turn it// «Volcán» · gpt-6-sol (medium)
// A cartoon volcano: a wide cone of dark brown and charcoal rock with rough layered sides, a crater on top glowing with bright orange lava, and a few streams of lava running down the sides. A puff of grey smoke above the crater.
const cx = 24, cy = 24;
const rock = ["#393735", "#49413a", "#5b4a3c", "#6b5542", "#786049"];
function radiusAt(z, a) {
return 20.3 - 0.435 * z
+ 0.65 * Math.sin(5 * a + 0.39 * z)
+ 0.38 * Math.sin(9 * a - 0.27 * z);
}
// A solid, uneven cone with broad horizontal bands of volcanic rock.
for (let z = 0; z <= 29; z++) {
for (let x = 3; x <= 45; x++) {
for (let y = 3; y <= 45; y++) {
const dx = x - cx, dy = y - cy;
const r = Math.hypot(dx, dy);
const a = Math.atan2(dx, -dy);
const edge = radiusAt(z, a);
if (r > edge || (z >= 26 && r < 4.65)) continue;
const band = Math.sin(z * 1.13 + a * 1.6);
let shade = band > 0.55 ? 3 : band < -0.55 ? 1 : 2;
if (z < 5) shade--;
if (r > edge - 2 && rand() < 0.19) shade += rand() < 0.5 ? -1 : 1;
shade = Math.max(0, Math.min(4, shade));
set(x, y, z, rock[shade]);
}
}
}
// Chunky, broken rim around the open crater.
for (let z = 30; z <= 32; z++) {
for (let x = 15; x <= 33; x++) {
for (let y = 15; y <= 33; y++) {
const dx = x - cx, dy = y - cy;
const a = Math.atan2(dx, -dy);
const r = Math.hypot(dx, dy);
const outer = (z === 30 ? 8.15 : z === 31 ? 7.65 : 7.1)
+ 0.5 * Math.sin(5 * a + 0.7);
if (r >= 4.7 && r <= outer &&
(z < 32 || Math.sin(7 * a + 2) > -0.25)) {
set(x, y, z, rand() < 0.24 ? "#786049" : "#49413a");
}
}
}
}
// A few dark boulders anchor the wide base.
for (const [x, y, rx, ry, rz] of [
[9, 17, 3, 3, 3], [37, 12, 3, 2, 3],
[11, 34, 3, 3, 2], [39, 32, 3, 3, 3]
]) {
ellipsoid(x, y, 1, rx, ry, rz, "#393735");
}
// The crater pool and all three downhill streams glow together.
part("lava", [cx, cy, 28]);
for (let z = 26; z <= 29; z++) {
const r = z === 29 ? 4.75 : 4.9;
for (let x = 19; x <= 29; x++) {
for (let y = 19; y <= 29; y++) {
if (Math.hypot(x - cx, y - cy) <= r) {
set(x, y, z, rand() < 0.22 ? "#ffca48" : "#f66b20");
}
}
}
}
const streams = [
{ angle: -0.42, bottom: 2, width: 1.75 },
{ angle: 0.79, bottom: 7, width: 1.55 },
{ angle: -1.19, bottom: 12, width: 1.25 }
];
for (const s of streams) {
for (let z = s.bottom; z <= 31; z++) {
const a = s.angle + 0.07 * Math.sin(z * 0.53 + s.angle * 4);
const surface = z > 29 ? (z === 31 ? 7.6 : 8.1) : radiusAt(z, a);
for (let x = 3; x <= 45; x++) {
for (let y = 3; y <= 45; y++) {
const dx = x - cx, dy = y - cy;
const r = Math.hypot(dx, dy);
const angle = Math.atan2(dx, -dy);
let difference = angle - a;
while (difference > Math.PI) difference -= 2 * Math.PI;
while (difference < -Math.PI) difference += 2 * Math.PI;
if (Math.abs(difference) * r <= s.width &&
r >= surface - 0.7 && r <= surface + 1.1) {
set(x, y, z, rand() < 0.23 ? "#ffca48" : "#ee5720");
}
}
}
}
}
animate("lava", {
type: "colors", palette: ["#a52e19", "#f26a1e", "#ffd04a"],
pattern: "wave", glow: 0.9
});
// A soft, lumpy puff rises clear of the crater.
part("smoke", [25, 23, 37]);
sphere(24, 23, 35, 2, "#747570");
sphere(25, 23, 38, 3, "#898b86");
sphere(27, 23, 41, 3, "#9b9d98");
sphere(24, 22, 43, 3, "#aaa9a2");
sphere(29, 22, 43, 2, "#aaa9a2");
sphere(23, 21, 44, 1, "#c0bfb7");
sphere(27, 21, 44, 1, "#c0bfb7");
animate("smoke", { type: "bob", axis: "z", speed: 1, amplitude: 2 });import { draw } from "./assets/voxel";
import { volcan } from "./assets/volcan";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, volcan, 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 volcan
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["volcan"] })
# It lands in client/assets/volcan.ts
# https://fogon.page/object/volcan