← Monsters and enemies3D assetfogon/pez-abisal
Pez abisal
Drag to turn it// «Pez abisal» · gpt-6-sol (medium)
// A cartoon anglerfish floating, horizontal, facing -y: a round dark navy-black body with a huge underbite mouth full of long white needle teeth, tiny glowing eyes, small fins, and a long thin stalk on top of its head ending in a glowing cyan-yellow lure.
// Chunky cartoon anglerfish, facing -y.
part("body", [24, 24, 19]);
animate("body", { type: "bob", axis: "z", speed: 2, amplitude: 2 });
const navy = "#101b36";
const shadow = "#091225";
const mid = "#182b50";
const light = "#294467";
// Round, solid body with a lighter crown and dark underside.
for (let x = 10; x <= 38; x++)
for (let y = 9; y <= 41; y++)
for (let z = 6; z <= 33; z++) {
const d = ((x - 24) / 14) ** 2 +
((y - 25) / 16) ** 2 +
((z - 20) / 13) ** 2;
if (d > 1) continue;
let color = z < 14 ? shadow : z > 27 ? mid : navy;
if (z > 28 && y < 29) color = light;
if (d > 0.72 && rand() < 0.13) color = z < 18 ? navy : mid;
set(x, y, z, color);
}
// Open a big, readable mouth in the front of the body.
for (let x = 12; x <= 36; x++)
for (let y = 7; y <= 20; y++)
for (let z = 11; z <= 21; z++) {
const halfWidth = y < 13 ? 10 : 12;
if (Math.abs(x - 24) <= halfWidth && get(x, y, z)) set(x, y, z, null);
}
// Deep, subtly purple mouth interior.
for (let x = 15; x <= 33; x++)
for (let z = 12; z <= 20; z++)
if (((x - 24) / 10) ** 2 + ((z - 16) / 6) ** 2 < 1)
set(x, 20, z, z < 15 ? "#32203f" : "#170e2b");
ellipsoid(24, 14, 9, 11, 8, 4, shadow); // enormous underbite
ellipsoid(24, 12, 11, 10, 5, 2, mid); // lower lip
ellipsoid(24, 13, 23, 11, 6, 3, navy); // upper snout
ellipsoid(24, 9, 21, 10, 2, 2, light); // upper lip edge
line(13, 13, 15, 15, 9, 11, 1, mid);
line(35, 13, 15, 33, 9, 11, 1, mid);
// Long tapered ivory teeth, alternating from the two jaws.
const upperTeeth = [16, 19, 22, 25, 28, 31, 34];
for (let i = 0; i < upperTeeth.length; i++) {
const x = upperTeeth[i];
const length = i === 0 || i === 6 ? 5 : (i % 2 ? 8 : 7);
for (let t = 0; t < length; t++) {
const z = 20 - t;
set(x, 8, z, t < length - 2 ? "#f1f4dc" : "#ffffff");
if (t < length - 3) set(x, 9, z, "#bacbd1");
if (t < 3) set(x + 1, 9, z, "#e4e9d8");
}
}
for (const x of [17, 21, 24, 27, 30, 33]) {
for (let t = 0; t < 6; t++) {
set(x, 8, 12 + t, t > 3 ? "#ffffff" : "#e8eedf");
if (t < 3) set(x, 9, 12 + t, "#aebfca");
}
}
// Tiny bright eyes in dark sockets, visible above the jaws.
for (const x of [16, 32]) {
ellipsoid(x, 12, 27, 3, 2, 3, shadow);
ellipsoid(x, 10, 27, 2, 1, 2, "#50dcca");
set(x, 8, 28, "#eaff8c");
set(x + 1, 8, 27, "#102443");
set(x - 1, 9, 29, "#ffffff");
}
// Small swept pectoral fins and their lighter ribs.
for (const side of [-1, 1]) {
const root = 24 + side * 12;
line(root, 27, 19, 24 + side * 20, 34, 14, 2, mid);
line(root, 27, 18, 24 + side * 20, 34, 11, 1, navy);
line(root, 27, 20, 24 + side * 18, 33, 16, 0, light);
ellipsoid(root, 27, 18, 2, 3, 3, navy);
}
// Small dorsal ridge and a pointed ventral fin reaching z=0.
line(24, 29, 31, 24, 35, 37, 2, mid);
line(24, 30, 34, 24, 35, 37, 0, light);
line(24, 30, 9, 24, 35, 0, 2, shadow);
line(24, 33, 4, 24, 35, 0, 0, mid);
// Short tail and broad, notched tail fin.
line(24, 39, 20, 24, 44, 20, 3, navy);
for (let x = 16; x <= 32; x++) {
const spread = Math.abs(x - 24);
const rear = 44 + Math.floor(spread / 3);
for (let y = 43; y <= Math.min(47, rear); y++)
for (let z = 17 - Math.floor(spread / 3); z <= 23 + Math.floor(spread / 3); z++)
set(x, y, z, z < 19 ? shadow : mid);
}
line(24, 43, 20, 17, 47, 25, 0, light);
line(24, 43, 20, 31, 47, 25, 0, light);
// Flexible forehead stalk, leaning toward the viewer.
line(24, 14, 31, 24, 12, 36, 1, shadow);
line(24, 12, 36, 24, 8, 41, 1, mid);
line(24, 13, 34, 24, 9, 39, 0, "#4a7890");
// The luminous bulb is its own animated color part.
part("lure", [24, 7, 42]);
ellipsoid(24, 7, 42, 3, 3, 3, "#71f5ec");
sphere(24, 6, 43, 2, "#e9ffad");
set(23, 4, 44, "#ffffff");
animate("lure", {
type: "colors",
palette: ["#38dfe9", "#83fff1", "#f2ff9b", "#ffffff"],
pattern: "pulse",
glow: 1
});import { draw } from "./assets/voxel";
import { pezAbisal } from "./assets/pez-abisal";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, pezAbisal, 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 pez-abisal
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["pez-abisal"] })
# It lands in client/assets/pez-abisal.ts
# https://fogon.page/object/pez-abisal