← Fantasy3D assetfogon/fantasma
Fantasma
Drag to turn it// «Fantasma» · gpt-6-sol (medium)
// A cute cartoon ghost: a tall rounded white sheet body with a dome head, the bottom edge wavy with three or four pointed tails, two little stubby arms raised as if saying boo, big oval black eyes and a small round open mouth, pale blue-lilac shading on the lower side. It floats a few blocks above a small grey shadow ellipse on the floor.
// A soft shadow anchors the floating ghost.
for (let x = 10; x <= 38; x++) {
for (let y = 17; y <= 31; y++) {
const d = ((x - 24) / 14) ** 2 + ((y - 24) / 7) ** 2;
if (d <= 1) {
const color = d > 0.78 ? "#b9b4c3" : d > 0.38 ? "#9690a2" : "#777185";
set(x, y, 0, color);
}
}
}
part("ghost", [24, 24, 24]);
animate("ghost", { type: "bob", axis: "z", speed: 2, amplitude: 2 });
function sheetColor(x, y, z, edge) {
let color;
if (z < 12) color = "#c3c7e8";
else if (z < 18) color = "#cdd0ec";
else if (z < 23) color = "#e2e1f3";
else color = "#f8f7ff";
if (edge && (x < 15 || x > 33 || y > 29)) {
color = z < 23 ? "#bdc4e6" : "#e6e5f4";
} else if (y <= 19 && z >= 24) {
color = "#ffffff";
}
if (rand() < 0.035) {
color = z < 23 ? "#dadcf0" : "#f0effa";
}
return color;
}
// Four tapered points make a gently scalloped, wavy sheet hem.
for (const [tipX, tipZ] of [[13, 8], [20, 7], [28, 7], [35, 8]]) {
for (let z = tipZ; z <= 15; z++) {
const t = (z - tipZ) / (15 - tipZ);
const rx = 0.8 + 2.9 * t;
const ry = 1.5 + 6.3 * t;
for (let x = Math.floor(tipX - rx); x <= Math.ceil(tipX + rx); x++) {
for (let y = Math.floor(24 - ry); y <= Math.ceil(24 + ry); y++) {
const d = ((x - tipX) / rx) ** 2 + ((y - 24) / ry) ** 2;
if (d <= 1) set(x, y, z, sheetColor(x, y, z, d > 0.65));
}
}
}
}
// Broad sheet body and smoothly domed head.
for (let z = 14; z <= 42; z++) {
const dome = z > 30 ? Math.sqrt(Math.max(0, 1 - ((z - 30) / 13) ** 2)) : 1;
const rx = 12.8 * dome;
const ry = 8.5 * dome;
for (let x = Math.floor(24 - rx); x <= Math.ceil(24 + rx); x++) {
for (let y = Math.floor(24 - ry); y <= Math.ceil(24 + ry); y++) {
const d = ((x - 24) / rx) ** 2 + ((y - 24) / ry) ** 2;
if (d <= 1) set(x, y, z, sheetColor(x, y, z, d > 0.72));
}
}
}
// Little raised, rounded "boo!" arms.
for (const side of [-1, 1]) {
ellipsoid(24 + side * 12, 24, 26, 4.3, 3.4, 3.7, "#e9e8f6");
ellipsoid(24 + side * 15, 23, 29, 4.2, 3.5, 3.7, "#f8f7ff");
sphere(24 + side * 17, 23, 31, 3.1, "#ffffff");
ellipsoid(24 + side * 15, 21, 32, 2.2, 1, 1.1, "#ffffff");
}
// Big ink-dark eyes, tiny glints, and a surprised open mouth.
for (const eyeX of [19, 29]) {
ellipsoid(eyeX, 15.7, 31, 2.8, 1.5, 4, "#dedbeb");
ellipsoid(eyeX, 14.8, 31, 2.35, 1.65, 3.5, "#242033");
sphere(eyeX - 0.7, 12.9, 32.7, 0.85, "#ffffff");
set(eyeX + 1, 13, 29, "#77728b");
}
ellipsoid(24, 15.6, 23, 2.5, 1.3, 2.7, "#d8cce6");
ellipsoid(24, 14.7, 23, 1.85, 1.45, 2, "#34283e");
set(24, 13, 22, "#8d6a91");
ellipsoid(15.5, 17.2, 25, 1.7, 0.8, 0.9, "#f1dbea");
ellipsoid(32.5, 17.2, 25, 1.7, 0.8, 0.9, "#f1dbea");import { draw } from "./assets/voxel";
import { fantasma } from "./assets/fantasma";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, fantasma, 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 fantasma
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["fantasma"] })
# It lands in client/assets/fantasma.ts
# https://fogon.page/object/fantasma