← Fantasy3D assetfogon/cristal-magico
Cristal mágico
Drag to turn it// «Cristal mágico» · gpt-6-sol (medium)
// A cluster of magic crystals growing from a rough grey mossy rock: one tall central hexagonal crystal with a pointed tip, slightly tilted, and four or five smaller pointed crystals around it at different angles. The crystals are translucent-looking violet and cyan, lighter at the tips. The central crystal glows and floats a little above the rock.
// A rough, mossy stone nest for the floating crystal.
ellipsoid(24, 24, 3, 18, 15, 8, "#696b70");
ellipsoid(15, 25, 3, 9, 11, 6, "#696b70");
ellipsoid(34, 25, 3, 9, 10, 6, "#696b70");
ellipsoid(23, 17, 5, 12, 8, 7, "#696b70");
const stone = [];
forEach((x, y, z) => stone.push([x, y, z]));
for (const [x, y, z] of stone) {
const top = !get(x, y, z + 1);
const shades = z < 3
? ["#50545a", "#595d61", "#626569"]
: ["#62666b", "#707378", "#7b7d7c", "#858681"];
set(x, y, z, shades[Math.floor(rand() * shades.length)]);
if (top && z >= 4 && rand() < 0.29) {
set(x, y, z, ["#435b4e", "#56745b", "#688568", "#78946e"][Math.floor(rand() * 4)]);
if (rand() < 0.24 && !get(x, y, z + 1)) {
set(x, y, z + 1, "#72986b");
}
}
}
// Bright runes and scattered sparks across the stone.
for (let i = 0; i < 38; i++) {
const x = 9 + Math.floor(rand() * 30);
const y = 11 + Math.floor(rand() * 27);
for (let z = 13; z >= 0; z--) {
if (get(x, y, z)) {
if (rand() < 0.65) set(x, y, z + 1, rand() < 0.5 ? "#5acfc9" : "#ae74e1");
break;
}
}
}
function mushroom(x, y, cap) {
let z = 12;
while (z > 0 && !get(x, y, z)) z--;
z++;
box(x, y, z, x, y, z + 2, "#d9d3b7");
ellipsoid(x, y, z + 3, 2, 2, 1, cap);
set(x, y - 1, z + 4, "#f5dfd5");
}
mushroom(12, 15, "#c877aa");
mushroom(35, 15, "#dd9cba");
mushroom(12, 32, "#87b39b");
// A small pool of magic light sits below the hovering central crystal.
for (let z = 11; z <= 13; z++) {
for (let x = 18; x <= 30; x++) for (let y = 18; y <= 30; y++) {
const d = Math.hypot(x - 24, y - 24);
if (Math.abs(d - (z === 13 ? 4.4 : 5.5)) < 0.55) {
set(x, y, z, z === 13 ? "#8ef5e9" : "#a95de0");
}
}
}
set(24, 24, 13, "#ddfbfa");
set(23, 24, 13, "#80e8e7");
set(25, 24, 13, "#80e8e7");
// Solid six-sided prisms, with distinct shaded faces and faceted pointed tips.
function crystal(x0, y0, z0, dx, dy, height, radius, colors) {
for (let k = 0; k < height; k++) {
const t = k / (height - 1);
const cx = x0 + dx * t;
const cy = y0 + dy * t;
const r = t < 0.67
? radius * (k === 0 ? 0.84 : 1)
: Math.max(0.38, radius * (1 - (t - 0.67) / 0.33));
for (let x = Math.floor(cx - r - 1); x <= Math.ceil(cx + r + 1); x++) {
for (let y = Math.floor(cy - r - 1); y <= Math.ceil(cy + r + 1); y++) {
const a = Math.abs(x - cx), b = Math.abs(y - cy);
if (b > 0.866 * r || 0.866 * a + 0.5 * b > 0.866 * r) continue;
let color = y < cy - 0.5 ? colors[1] : colors[0];
if (x < cx - 0.5 && y <= cy) color = colors[2];
if (x > cx + 0.5 && y > cy) color = colors[3];
if (t > 0.68) color = colors[4];
if (t > 0.88) color = colors[5];
if (t < 0.68 && rand() < 0.045) color = colors[4];
set(x, y, z0 + k, color);
}
}
}
}
const violet = ["#773daa", "#a968d2", "#ca8be5", "#583b92", "#da9bf0", "#f1d7ff"];
const cyan = ["#279baf", "#6bdcdd", "#9ae9e8", "#35749e", "#aaf6ed", "#e4fffa"];
const pink = ["#a746a8", "#df83c7", "#eea8df", "#753c98", "#f6b9eb", "#ffe4fa"];
// Five smaller crystals fan out at different angles.
const satellites = [
["left", 15, 21, 9, -7, -3, 19, 3.1, violet],
["right", 33, 22, 9, 7, -3, 21, 3.2, cyan],
["front", 24, 15, 9, -2, -5, 17, 2.8, pink],
["back", 26, 31, 9, 3, 5, 22, 3.0, cyan],
["back_left", 16, 30, 8, -4, 4, 17, 2.6, violet]
];
for (const [name, x, y, z, dx, dy, h, r, palette] of satellites) {
part(name, [x, y, z]);
crystal(x, y, z, dx, dy, h, r, palette);
animate(name, {
type: "colors",
palette: [palette[0], palette[1], palette[4], palette[5]],
pattern: "wave",
speed: 0.65,
glow: 0.45
});
}
part("central", [24, 24, 16]);
crystal(24, 24, 16, 3, -2, 29, 5.3, violet);
animate("central", { type: "bob", axis: "z", speed: 1.6, amplitude: 1.5 });
animate("central", {
type: "colors",
palette: ["#a156df", "#ef6ac9", "#60e9ed", "#d4a0fa"],
pattern: "pulse",
speed: 1.4,
glow: 0.8
});import { draw } from "./assets/voxel";
import { cristalMagico } from "./assets/cristal-magico";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, cristalMagico, 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 cristal-magico
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["cristal-magico"] })
# It lands in client/assets/cristal-magico.ts
# https://fogon.page/object/cristal-magico