← Parties and Christmas3D assetfogon/huevo-de-pascua
Huevo de Pascua
Drag to turn it// «Huevo de Pascua» · gpt-6-sol (medium)
// A giant decorated chocolate Easter egg standing upright on a small nest of yellow paper grass: dark brown chocolate with shiny highlights, decorated with stripes of white and pink icing, little sugar flowers and a big shiny red ribbon bow around the middle.
const cx = 24, cy = 24;
function eggRadius(z) {
const t = (z - 5) / 38;
if (t <= 0 || t >= 1) return 0;
return 15.3 * Math.pow(Math.sin(Math.PI * t), 0.72) * (1.12 - 0.38 * t);
}
function frontY(x, z) {
const r = eggRadius(z);
return cy - Math.sqrt(Math.max(0, r * r - (x - cx) ** 2));
}
// A low, springy nest of curled yellow paper grass.
ellipsoid(24, 24, 1, 16, 14, 2, "#c88d25");
ellipsoid(24, 24, 2, 13, 11, 2, "#e9b83e");
for (let x = 6; x <= 42; x++) {
for (let y = 7; y <= 41; y++) {
const d = Math.sqrt(((x - 24) / 18) ** 2 + ((y - 24) / 16) ** 2);
if (d > 0.67 && d < 1.04 && rand() < 0.72) {
set(x, y, 1 + Math.floor(rand() * 3),
rand() < 0.45 ? "#ffdf68" : "#db9e2f");
}
}
}
const grass = ["#f8cf4d", "#ffe47c", "#d99a2c", "#fff0a2"];
for (let i = 0; i < 205; i++) {
const a = rand() * Math.PI * 2;
const radius = 11 + rand() * 7;
const x = 24 + Math.cos(a) * radius;
const y = 24 + Math.sin(a) * radius * 0.88;
const tang = a + Math.PI / 2;
const length = 2 + rand() * 5;
const z = 1 + Math.floor(rand() * 3);
line(x - Math.cos(tang) * length / 2, y - Math.sin(tang) * length / 2, z,
x + Math.cos(tang) * length / 2, y + Math.sin(tang) * length / 2,
z + (rand() < 0.5 ? 1 : 0), 0, grass[Math.floor(rand() * grass.length)]);
}
// Solid, upright chocolate egg, with a softly lit front-left side.
for (let z = 5; z <= 42; z++) {
const r = eggRadius(z);
for (let x = Math.floor(cx - r); x <= Math.ceil(cx + r); x++) {
for (let y = Math.floor(cy - r); y <= Math.ceil(cy + r); y++) {
const d2 = (x - cx) ** 2 + (y - cy) ** 2;
if (d2 > r * r) continue;
const surface = r - Math.sqrt(d2) < 1.35;
let color = "#613021";
if (surface) {
const light = (24 - y) * 0.6 + (24 - x) * 0.25 + z * 0.065;
color = light > 10 ? "#965037" :
light > 5 ? "#7c3e2a" :
light > 0 ? "#693322" : "#51271d";
if (rand() < 0.045) color = light > 5 ? "#a65d3d" : "#723826";
}
set(x, y, z, color);
}
}
}
// Narrow glossy chocolate reflections, tucked between decorations.
for (let z = 26; z <= 38; z++) {
const x = z < 31 ? 18 : 19;
if (Math.abs(x - cx) < eggRadius(z) - 1)
set(x, Math.round(frontY(x, z)) - 1, z,
z % 3 === 0 ? "#d28a5d" : "#b86d48");
}
for (let z = 29; z <= 33; z++) {
const x = 21;
set(x, Math.round(frontY(x, z)) - 1, z, "#ac6241");
}
// Raised, gently wavy icing bands wrapping all the way around the egg.
function icingBand(height, wave, base, highlight) {
for (let a = 0; a < Math.PI * 2; a += 0.038) {
const z = height + Math.sin(a * 3 + wave) * 0.75;
const r = eggRadius(z);
const x = cx + Math.sin(a) * r;
const y = cy - Math.cos(a) * r;
sphere(x, y, z, 1.05, base);
set(x, y, z + 1, highlight);
}
}
icingBand(12, 0.2, "#f0a5bc", "#ffd1de");
icingBand(15, 1.0, "#f6e6d5", "#ffffff");
icingBand(32, 2.1, "#f0a5bc", "#ffd8e5");
icingBand(35, 0.4, "#f6e6d5", "#ffffff");
// Tiny piped dots between the broad stripes.
for (let a = 0; a < Math.PI * 2; a += 0.29) {
for (const z of [18, 38]) {
const r = eggRadius(z);
sphere(cx + Math.sin(a) * r, cy - Math.cos(a) * r, z,
0.75, z === 18 ? "#ffd0de" : "#fff4df");
}
}
// The red satin ribbon encircles the middle; its upper edge catches light.
for (let a = 0; a < Math.PI * 2; a += 0.022) {
for (let z = 20; z <= 24; z++) {
const r = eggRadius(z);
for (const depth of [0, 0.7]) {
const x = cx + Math.sin(a) * (r + depth);
const y = cy - Math.cos(a) * (r + depth);
set(x, y, z, z === 20 ? "#8f2030" :
z >= 23 ? "#ed4753" : "#c52d3d");
}
}
}
for (let a = 0; a < Math.PI * 2; a += 0.037) {
const r = eggRadius(25);
set(cx + Math.sin(a) * r, cy - Math.cos(a) * r, 25, "#ff9b9a");
}
// Ribbon tails trail from beneath the bow.
line(21, 9, 23, 17, 8, 16, 1.9, "#a92335");
line(27, 9, 23, 31, 8, 16, 1.9, "#b9293c");
line(20, 7, 22, 17, 7, 17, 0, "#f56c70");
line(28, 7, 22, 31, 7, 17, 0, "#f56c70");
box(15, 7, 16, 18, 9, 17, "#bc2b3c");
box(30, 7, 16, 33, 9, 17, "#c83242");
set(16, 7, 16, "#6f1b2b");
set(32, 7, 16, "#791e2d");
// Two oversized, rounded bow loops with shaded folds.
function bowLoop(mx) {
ellipsoid(mx, 8, 26, 5.5, 2.3, 4.2, "#a71f32");
ellipsoid(mx, 6, 26, 4.7, 1.3, 3.3, "#ed4353");
ellipsoid(mx, 5, 26, 2.55, 0.8, 1.65, "#982235");
for (let x = Math.round(mx - 4); x <= mx + 4; x++) {
const shape = 1 - ((x - mx) / 5.5) ** 2;
if (shape > 0.15) {
const z = 26 + Math.sqrt(shape) * 3.5;
set(x, 5, z, "#ff9292");
}
}
}
bowLoop(18.5);
bowLoop(29.5);
ellipsoid(24, 5, 25, 3, 2.3, 3, "#ad2334");
ellipsoid(24, 3, 25.5, 2.45, 0.9, 2.4, "#ed4652");
line(22, 2, 27, 25, 2, 27, 0, "#ffaaa4");
// Little five-petal sugar flowers, attached to the curved front.
function flower(fx, fz, petal, center) {
const offsets = [[0, 2], [2, 1], [2, -1], [-2, 1], [-2, -1]];
for (const [dx, dz] of offsets) {
const x = fx + dx, z = fz + dz;
const y = frontY(x, z) - 1.6;
sphere(x, y, z, 1.35, petal);
set(x, y - 1, z + 1, "#ffffff");
}
sphere(fx, frontY(fx, fz) - 3, fz, 1.35, center);
set(fx, frontY(fx, fz) - 4, fz + 1, "#fff5ae");
}
flower(14, 29, "#ffe2ed", "#f6c44d");
flower(34, 29, "#fff0e8", "#f4bc42");
flower(18, 18, "#ffe1e9", "#ffd357");
flower(30, 38, "#fff0dc", "#f4bc42");
// A few bright sugar pearls finish the cheerful, toy-like surface.
for (const [x, z] of [[23, 39], [27, 37], [12, 25], [36, 26],
[15, 19], [34, 18], [22, 11], [27, 12]]) {
if (Math.abs(x - cx) < eggRadius(z) - 0.5)
sphere(x, frontY(x, z) - 1, z, 0.9, "#fff8e9");
}import { draw } from "./assets/voxel";
import { huevoDePascua } from "./assets/huevo-de-pascua";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, huevoDePascua, 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-pascua
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["huevo-de-pascua"] })
# It lands in client/assets/huevo-de-pascua.ts
# https://fogon.page/object/huevo-de-pascua