← Fantasy3D assetfogon/hada
Hada
Drag to turn it// «Hada» · gpt-6-sol (medium)
// A small cartoon fairy: a girl with a big head, rosy cheeks, big eyes and pointy ears, a short pink-and-lilac petal dress, messy golden hair with a little flower, holding a tiny wand with a star tip. Four large translucent-looking wings (pale cyan and lilac with darker veins) on her back. She hovers above a small glowing ring of sparkles on the floor.
// A fairy hovering above a ring of magic.
const C = {
skin: "#ffd5b2", skinLight: "#ffe3c8", skinShade: "#e9a987",
blush: "#f48fa6", hair: "#f5ba43", hairLight: "#ffdc70",
hairShade: "#c88730", pink: "#f276b5", pinkLight: "#ff9dcb",
lilac: "#b982e8", lilacLight: "#dbb0fa",
cyan: "#b5f8f5", cyanLight: "#dcffff", cyanVein: "#66bfc9",
violetWing: "#d9c3ff", violetVein: "#a689d5"
};
// Broken, sparkling magic circle on the floor.
for (let i = 0; i < 144; i++) {
const a = i * Math.PI * 2 / 144;
const r = 10 + (rand() - 0.5) * 0.9;
const x = Math.round(24 + Math.cos(a) * r);
const y = Math.round(24 + Math.sin(a) * r);
if (i % 19 < 16) {
set(x, y, 0, i % 5 === 0 ? "#f4b5ff" : "#75e9e4");
if (i % 13 === 0) set(x, y, 1, "#e5ffff");
}
}
for (let i = 0; i < 18; i++) {
const a = i * Math.PI * 2 / 18;
const r = 10 + (i % 3 - 1) * 1.4;
const x = Math.round(24 + Math.cos(a) * r);
const y = Math.round(24 + Math.sin(a) * r);
set(x, y, 1, i % 2 ? "#dc8bff" : "#a1ffff");
if (i % 3 === 0) {
set(x - 1, y, 1, "#b6faff");
set(x + 1, y, 1, "#b6faff");
set(x, y, 2, "#ffffff");
}
}
set(24, 24, 0, "#bc8cff");
set(24, 24, 1, "#e7c6ff");
// Each side's pair of wings belongs to one flapping part.
// The ellipses are angled in the x-z plane and given a thin luminous edge.
function wing(cx, cz, dx, dz, length, width, tint) {
const vein = tint === "cyan" ? C.cyanVein : C.violetVein;
const fill = tint === "cyan" ? C.cyan : C.violetWing;
const light = tint === "cyan" ? C.cyanLight : C.lilacLight;
for (let x = Math.floor(cx - length - width); x <= Math.ceil(cx + length + width); x++) {
for (let z = Math.floor(cz - length - width); z <= Math.ceil(cz + length + width); z++) {
const xx = x - cx, zz = z - cz;
const u = (xx * dx + zz * dz) / length;
const v = (-xx * dz + zz * dx) / width;
const d = u * u + v * v;
if (d > 1) continue;
const color = d > 0.82 ? light : (rand() < 0.14 ? light : fill);
set(x, 30, z, color);
if (d < 0.75) set(x, 31, z, fill);
if (d < 0.42) set(x, 29, z, light);
}
}
// A dark central rib and delicate branching veins on the visible side.
line(Math.round(cx - dx * length * 0.82), 29, Math.round(cz - dz * length * 0.82),
Math.round(cx + dx * length * 0.78), 29, Math.round(cz + dz * length * 0.78), 0, vein);
for (const t of [-0.35, 0.08, 0.42]) {
const bx = cx + dx * length * t, bz = cz + dz * length * t;
for (const s of [-1, 1]) {
line(bx, 29, bz,
bx + dx * length * 0.13 - dz * width * s * 0.65,
29,
bz + dz * length * 0.13 + dx * width * s * 0.65,
0, vein);
}
}
}
part("leftWings", [20, 29, 28]);
wing(13, 35, -0.84, 0.54, 11, 4.6, "cyan");
wing(13, 22, -0.88, -0.48, 10, 4.1, "violet");
animate("leftWings", { type: "swing", axis: "y", speed: 10, amplitude: 0.5 });
part("rightWings", [28, 29, 28]);
wing(35, 35, 0.84, 0.54, 11, 4.6, "violet");
wing(35, 22, 0.88, -0.48, 10, 4.1, "cyan");
animate("rightWings", { type: "swing", axis: "y", speed: -10, amplitude: 0.5 });
part("body", [24, 23, 25]);
// Dangling legs, little stockings, and rounded slippers.
line(21, 23, 18, 20, 22, 11, 2, C.skin);
line(27, 23, 18, 28, 22, 11, 2, C.skin);
box(19, 20, 10, 21, 23, 12, "#fff0f0");
box(27, 20, 10, 29, 23, 12, "#fff0f0");
ellipsoid(20, 19, 9, 3, 3, 2, C.lilac);
ellipsoid(28, 19, 9, 3, 3, 2, C.pink);
set(20, 17, 10, "#f9d9ff");
set(28, 17, 10, "#ffe1ef");
// Short, scalloped petal skirt.
for (let z = 17; z <= 23; z++) {
const radius = [7.2, 8, 8, 7.4, 6.6, 5.8, 5][z - 17];
for (let x = 16; x <= 32; x++) for (let y = 15; y <= 31; y++) {
const d = ((x - 24) / radius) ** 2 + ((y - 23) / (radius * 0.78)) ** 2;
if (d <= 1) set(x, y, z,
z < 19 ? "#a967c9" : rand() < 0.13 ? C.pinkLight : C.pink);
}
}
for (let i = 0; i < 9; i++) {
const a = i * Math.PI * 2 / 9;
const px = 24 + Math.cos(a) * 5.3;
const py = 23 + Math.sin(a) * 4.2;
ellipsoid(px, py, 20, 2.5, 2, 3.5, i % 2 ? C.lilac : C.pinkLight);
sphere(px + Math.cos(a), py + Math.sin(a), 17, 1.4,
i % 2 ? C.lilacLight : C.pinkLight);
}
ellipsoid(24, 22, 26, 4.7, 3.7, 5, C.lilac);
box(21, 17, 23, 27, 19, 24, "#ffe3aa");
set(24, 16, 24, "#fff7ce");
// Arms: one waving, one holding a tiny wand.
line(20, 21, 27, 16, 17, 24, 2, C.skin);
sphere(16, 17, 24, 2, C.skinLight);
line(28, 21, 27, 34, 17, 24, 2, C.skin);
sphere(34, 17, 24, 2, C.skinLight);
ellipsoid(19, 21, 27, 2.7, 2.6, 2.5, C.pinkLight);
ellipsoid(29, 21, 27, 2.7, 2.6, 2.5, C.pinkLight);
// Wand shaft, gold collar, and five-point magical star.
line(34, 16, 24, 39, 15, 34, 0, "#a47744");
line(35, 16, 26, 39, 15, 34, 0, "#f5ca69");
sphere(39, 15, 34, 1.5, "#fff4a9");
line(39, 14, 31, 39, 14, 38, 0, "#ffe77a");
line(35, 14, 35, 43, 14, 35, 0, "#ffe77a");
line(37, 14, 32, 41, 14, 38, 0, "#fff3a7");
line(41, 14, 32, 37, 14, 38, 0, "#fff3a7");
sphere(39, 13, 35, 1.5, "#ffffff");
set(43, 14, 39, "#b9ffff");
set(35, 14, 38, "#e4b4ff");
// Pointed ears peek out behind the hair.
line(18, 21, 35, 13, 20, 38, 2, C.skin);
line(30, 21, 35, 35, 20, 38, 2, C.skin);
line(16, 19, 36, 13, 19, 38, 0, C.blush);
line(32, 19, 36, 35, 19, 38, 0, C.blush);
// Big golden hair silhouette, then the round face in front of it.
ellipsoid(24, 23, 35, 9, 7, 9, C.hairShade);
ellipsoid(24, 22, 37, 9, 7, 7, C.hair);
ellipsoid(24, 21, 34, 7, 6, 7, C.skin);
ellipsoid(24, 16, 31, 4, 1.5, 2, C.skinLight);
// Messy side curls, swept bangs, and a few flyaway locks.
ellipsoid(16, 21, 34, 2.3, 3.1, 5, C.hair);
ellipsoid(32, 21, 34, 2.3, 3.1, 5, C.hair);
sphere(16, 20, 30, 2.3, C.hairLight);
sphere(33, 22, 31, 2.2, C.hairShade);
ellipsoid(21, 16, 40, 5, 2.4, 2.7, C.hairLight);
ellipsoid(27, 16, 40, 4.7, 2.1, 2.8, C.hair);
line(18, 16, 40, 20, 15, 37, 1.5, C.hairLight);
line(23, 15, 41, 24, 15, 38, 1.5, C.hair);
line(29, 16, 40, 28, 15, 37, 1.5, C.hairLight);
line(18, 21, 41, 15, 21, 43, 1.4, C.hairLight);
line(28, 22, 42, 32, 23, 44, 1.3, C.hairLight);
set(21, 19, 44, "#ffe37d");
set(30, 24, 43, "#ffe37d");
// Eyes sit proud of the face, with dark pupils and bright catchlights.
for (const x of [21, 27]) {
ellipsoid(x, 15, 35, 2, 1.3, 2.5, "#fffaf6");
ellipsoid(x, 13.5, 35, 1.1, 1, 1.8, "#466574");
set(x, 12, 35, "#192d42");
set(x - 1, 12, 36, "#ffffff");
set(x + 1, 14, 33, "#e6a38e");
}
sphere(18, 16, 32, 1.5, C.blush);
sphere(30, 16, 32, 1.5, C.blush);
set(24, 14, 32, C.skinShade);
set(23, 15, 30, "#bb6576");
set(24, 14, 30, "#c8667c");
set(25, 15, 30, "#bb6576");
// A tiny flower tucked into her hair.
for (const [dx, dz] of [[-2, 0], [2, 0], [0, -2], [0, 2], [-1, 2]]) {
sphere(30 + dx, 16, 41 + dz, 1.3, dx === 0 ? "#ffc5ec" : "#e494e8");
}
sphere(30, 14, 41, 1.4, "#ffe584");
set(30, 13, 41, "#fff9c8");import { draw } from "./assets/voxel";
import { hada } from "./assets/hada";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, hada, 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 hada
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["hada"] })
# It lands in client/assets/hada.ts
# https://fogon.page/object/hada