← Fantasy3D assetfogon/huevo-de-dragon
Huevo de dragón
Drag to turn it// «Huevo de dragón» · gpt-6-sol (medium)
// A big dragon egg resting in a nest of dark twigs and straw: an oval egg with scaly texture in deep red with gold speckles and a thin glowing orange crack across it.
// A warm, scaly dragon egg tucked into a dark twig nest.
const cx = 24, cy = 24;
const wood = ["#241c22", "#32252a", "#403034", "#513a38"];
const straw = ["#80613c", "#a37a42", "#c49a57", "#dfb36b"];
function eggRadii(z) {
const t = (z - 24) / 19;
if (Math.abs(t) > 1) return null;
const taper = 1 - 0.16 * t;
const round = Math.sqrt(1 - t * t);
return [13.5 * taper * round, 12.5 * taper * round];
}
function frontY(x, z) {
const radii = eggRadii(z);
if (!radii) return null;
const [rx, ry] = radii;
const q = (x - cx) / rx;
if (Math.abs(q) > 1) return null;
return Math.round(cy - ry * Math.sqrt(1 - q * q)) - 1;
}
// A broad, low bowl of matted straw.
for (let z = 0; z <= 4; z++) {
for (let x = 2; x <= 46; x++) {
for (let y = 3; y <= 45; y++) {
const d = Math.sqrt(((x - cx) / 20.5) ** 2 + ((y - cy) / 18.5) ** 2);
if (d < 1.01 - z * 0.045 && rand() > 0.055) {
set(x, y, z, d > 0.7
? wood[Math.floor(rand() * wood.length)]
: ["#35292a", "#47342f", "#594132"][Math.floor(rand() * 3)]);
}
}
}
}
// Chunky, uneven raised rim; the front lip frames the egg.
for (let x = 2; x <= 46; x++) {
for (let y = 3; y <= 45; y++) {
const d = Math.sqrt(((x - cx) / 20) ** 2 + ((y - cy) / 18) ** 2);
if (d > 0.72 && d < 1.12) {
const height = Math.max(3, Math.round(7 - Math.abs(d - 0.91) * 17 + rand() * 2));
for (let z = 2; z <= height; z++) {
if (rand() > 0.09) set(x, y, z, wood[Math.floor(rand() * wood.length)]);
}
if (rand() < 0.22) set(x, y, height + 1, straw[Math.floor(rand() * straw.length)]);
}
}
}
// Individual crossed twigs, mostly tangent to the nest rim.
for (let i = 0; i < 125; i++) {
const a = rand() * Math.PI * 2;
const r = 0.77 + rand() * 0.31;
const x = cx + Math.cos(a) * 20 * r;
const y = cy + Math.sin(a) * 18 * r;
const length = 3 + rand() * 8;
const tilt = (rand() - 0.5) * 0.8;
const z = 4 + Math.floor(rand() * 5);
line(
x - Math.sin(a) * length / 2, y + Math.cos(a) * length / 2, z,
x + Math.sin(a) * length / 2, y - Math.cos(a) * length / 2, z + tilt,
rand() < 0.2 ? 1 : 0,
wood[Math.floor(rand() * wood.length)]
);
}
// Pale, loose strands woven over the dark wood.
for (let i = 0; i < 165; i++) {
const a = rand() * Math.PI * 2;
const r = 0.68 + rand() * 0.39;
const x = cx + Math.cos(a) * 20 * r;
const y = cy + Math.sin(a) * 18 * r;
const length = 2 + rand() * 6;
const z = 5 + Math.floor(rand() * 5);
line(x, y, z,
x - Math.sin(a) * length, y + Math.cos(a) * length, z + (rand() - 0.5) * 2,
0, straw[Math.floor(rand() * straw.length)]);
}
// Solid egg: broad at the bottom and gently tapered toward its crown.
for (let z = 6; z <= 43; z++) {
const radii = eggRadii(z);
if (!radii) continue;
const [rx, ry] = radii;
for (let x = Math.floor(cx - rx); x <= Math.ceil(cx + rx); x++) {
for (let y = Math.floor(cy - ry); y <= Math.ceil(cy + ry); y++) {
const d = ((x - cx) / rx) ** 2 + ((y - cy) / ry) ** 2;
if (d > 1) continue;
const exposed = d > 0.79;
let color = "#792932";
if (exposed) {
const light = z > 30 || (x < cx && z > 16);
const palette = light
? ["#862b39", "#963342", "#a74049", "#b64a50"]
: ["#68232f", "#762631", "#842936", "#96313c"];
color = palette[Math.floor(rand() * palette.length)];
// Staggered, overlapping scale edges follow the curved surface.
const angle = Math.atan2(y - cy, x - cx);
const row = Math.floor((z - 7) / 4);
const phase = (angle / (2 * Math.PI) * 26 + (row % 2) * 0.5);
const seam = Math.abs(phase - Math.round(phase));
const withinRow = (z - 7) % 4;
if (withinRow === 3 && seam < 0.36) color = "#5c202d";
else if (withinRow === 0 && seam < 0.34) color = "#ba4b50";
// Gold flecks, with occasional larger glints.
const fleck = rand();
if (fleck < 0.017) color = "#f1ba60";
else if (fleck < 0.043) color = "#bd8548";
}
set(x, y, z, color);
}
}
}
// A few deliberate, visible clusters of golden speckles on the front.
for (let i = 0; i < 32; i++) {
const x = 14 + Math.floor(rand() * 21);
const z = 14 + Math.floor(rand() * 25);
const y = frontY(x, z);
if (y !== null && get(x, y + 1, z)) {
set(x, y, z, rand() < 0.35 ? "#ffcf77" : "#ca914c");
}
}
// Dark split beneath the light, winding diagonally across the front.
function crackZ(x) {
const corners = [
[11, 25], [15, 27], [19, 26], [22, 30],
[26, 28], [29, 31], [33, 29], [37, 32]
];
for (let i = 0; i < corners.length - 1; i++) {
const [x0, z0] = corners[i], [x1, z1] = corners[i + 1];
if (x <= x1) return Math.round(z0 + (z1 - z0) * (x - x0) / (x1 - x0));
}
return 32;
}
for (let x = 11; x <= 37; x++) {
const z = crackZ(x);
for (let dz = -2; dz <= 2; dz++) {
const y = frontY(x, z + dz);
if (y !== null && get(x, y + 1, z + dz)) {
set(x, y, z + dz, Math.abs(dz) === 2 ? "#a94536" : "#53202a");
}
}
}
// The glowing fissure is its own animated part.
part("crack", [24, 12, 29]);
for (let x = 11; x <= 37; x++) {
const z = crackZ(x);
const y = frontY(x, z);
if (y === null) continue;
set(x, y - 1, z, "#ff922e");
if (x % 3 !== 0) set(x, y - 1, z + 1, "#ffd054");
if (x % 6 === 2) set(x, y - 2, z, "#ffe69a");
}
animate("crack", {
type: "colors",
palette: ["#ff702a", "#ffd052", "#d93b32"],
pattern: "pulse",
glow: 0.9
});import { draw } from "./assets/voxel";
import { huevoDeDragon } from "./assets/huevo-de-dragon";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, huevoDeDragon, 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 huevo-de-dragon
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["huevo-de-dragon"] })
# It lands in client/assets/huevo-de-dragon.ts
# https://fogon.page/object/huevo-de-dragon