← Parties and Christmas3D assetfogon/fuegos-artificiales
Fuegos artificiales
Drag to turn it// «Fuegos artificiales» · gpt-6-sol (medium)
// A fireworks launch: a small wooden crate with three thick tubes in red, blue and gold pointing up, and above them three big exploding star bursts of glowing sparks in different colors, held up by thin trails of sparks rising from the tubes.
// Wooden launch crate
box(9, 17, 0, 39, 32, 8, "#a66b39");
box(10, 17, 7, 38, 31, 9, "#d69850");
box(11, 18, 9, 37, 30, 9, "#f1bc70");
// Planks and their darker seams
for (const z of [1, 4, 7]) {
box(10, 16, z, 38, 16, z + 2, z === 4 ? "#c48647" : "#d99a56");
box(9, 18, z, 9, 31, z + 2, "#b6783e");
box(39, 18, z, 39, 31, z + 2, "#a96c37");
}
for (const z of [3, 6]) {
box(10, 16, z, 38, 16, z, "#754526");
box(9, 18, z, 9, 31, z, "#754526");
box(39, 18, z, 39, 31, z, "#754526");
}
for (const x of [12, 36]) {
box(x, 15, 0, x + 1, 16, 8, "#f0bd68");
for (const z of [2, 7]) set(x, 14, z, "#fff0b5");
}
box(9, 16, 0, 39, 17, 0, "#734627");
box(10, 16, 8, 38, 16, 8, "#f4c47a");
// Three upright launch tubes
const tubes = [
{ x: 15, body: "#d9393d", light: "#ff7372", dark: "#961e35", rim: "#ffb0a0" },
{ x: 24, body: "#3289d7", light: "#82d5f5", dark: "#22528e", rim: "#c4f5ff" },
{ x: 33, body: "#e9ad30", light: "#ffe17a", dark: "#a66a22", rim: "#fff1ae" }
];
for (const t of tubes) {
cylinder(t.x, 24, 9, 3, 9, t.dark);
cylinder(t.x, 24, 11, 3, 6, t.body);
box(t.x - 1, 21, 11, t.x + 1, 21, 16, t.light);
cylinder(t.x, 24, 17, 4, 2, t.rim);
cylinder(t.x, 24, 19, 3, 1, t.dark);
cylinder(t.x, 24, 19, 2, 1, "#342f45");
set(t.x, 24, 19, "#fff4ce");
box(t.x - 2, 20, 12, t.x - 2, 20, 14, "#fff1c3");
}
// Fine rising spark trails, kept separate from the animated bursts
const trails = [
{ x0: 15, x1: 11, y1: 18, top: 29, colors: ["#ffca58", "#ff8055", "#fff0a5"] },
{ x0: 24, x1: 24, y1: 26, top: 33, colors: ["#91e9ff", "#e4fcff", "#50bddb"] },
{ x0: 33, x1: 37, y1: 18, top: 30, colors: ["#ffe58a", "#ffb4de", "#fff5cf"] }
];
for (const t of trails) {
for (let z = 20; z <= t.top; z++) {
const f = (z - 20) / (t.top - 20);
const x = Math.round(t.x0 + (t.x1 - t.x0) * f);
const y = Math.round(24 + (t.y1 - 24) * f);
if (z % 4 !== 1) set(x, y, z, t.colors[z % 3]);
if (z % 3 === 0) {
set(x - 1, y - 1, z + 1, t.colors[(z + 1) % 3]);
set(x + 1, y, z - 1, t.colors[(z + 2) % 3]);
}
}
}
// Each burst is its own flickering part. Rays spread across the front
// silhouette, with shorter rays reaching toward and away from the viewer.
function burst(name, cx, cy, cz, reach, colors) {
part(name, [cx, cy, cz]);
sphere(cx, cy, cz, 2, colors[0]);
sphere(cx, cy - 1, cz + 1, 1, colors[2]);
const rays = [
[1, 0, 0], [-1, 0, 0], [0, 0, 1], [0, 0, -1],
[0.72, 0, 0.72], [-0.72, 0, 0.72],
[0.72, 0, -0.72], [-0.72, 0, -0.72],
[0.42, -0.43, 0.8], [-0.42, -0.43, 0.8],
[0.42, -0.43, -0.8], [-0.42, -0.43, -0.8],
[0.75, 0.48, 0.35], [-0.75, 0.48, 0.35],
[0, -0.85, 0.45], [0, -0.85, -0.45]
];
rays.forEach(([dx, dy, dz], i) => {
const length = reach - (i % 5 === 0 ? 1 : 0);
const ex = Math.round(cx + dx * length);
const ey = Math.round(cy + dy * length);
const ez = Math.round(cz + dz * length);
line(cx, cy, cz, ex, ey, ez, 0, colors[i % colors.length]);
sphere(ex, ey, ez, i % 3 === 0 ? 1.4 : 1, colors[(i + 1) % colors.length]);
// Little detached glints make the explosions look lively.
if (i % 2 === 0) {
set(ex + (dx >= 0 ? 1 : -1), ey - 1, ez + (dz >= 0 ? 1 : -1), colors[2]);
}
});
animate(name, {
type: "colors",
palette: colors,
pattern: "flicker",
glow: 1
});
}
burst("redBurst", 11, 18, 33, 7, ["#ff4949", "#ff9a3e", "#ffe766", "#fff3b2"]);
burst("blueBurst", 24, 26, 38, 7, ["#409aff", "#51e4ef", "#f4ffff", "#acebff"]);
burst("pinkBurst", 37, 18, 34, 7, ["#ff86cf", "#bc83f5", "#ffda69", "#fff0ba"]);import { draw } from "./assets/voxel";
import { fuegosArtificiales } from "./assets/fuegos-artificiales";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, fuegosArtificiales, 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 fuegos-artificiales
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["fuegos-artificiales"] })
# It lands in client/assets/fuegos-artificiales.ts
# https://fogon.page/object/fuegos-artificiales