← Asian3D assetfogon/oni
Oni
Drag to turn it// «Oni» · gpt-6-sol (medium)
// A chunky cartoon oni demon standing facing front: bright red skin, two short cream horns, wild black hair, big angry eyes with yellow irises, two small tusks, a tiger-striped loincloth, and a big black iron club with studs held over one shoulder.
const red = "#d92d22", redLight = "#f04430", redDark = "#a9191c";
const hair = "#16171c", hairLight = "#303039";
const cream = "#fff0c7", creamShade = "#d8c69b";
const iron = "#252a30", ironLight = "#495158";
// Legs pivot independently at the hips.
function leg(name, x, speed) {
part(name, [x, 24, 16]);
ellipsoid(x, 24, 9, 3.7, 4, 8, redDark);
ellipsoid(x, 23, 10, 3.4, 3.7, 7, red);
ellipsoid(x, 20, 3, 4, 5, 3, red);
ellipsoid(x, 17, 2, 4, 2.5, 1.7, redLight);
for (let dx = -2; dx <= 2; dx += 2)
box(x + dx, 14, 1, x + dx + 1, 15, 2, creamShade);
animate(name, { type: "swing", axis: "x", speed, amplitude: 0.3 });
}
leg("leftLeg", 18, 4);
leg("rightLeg", 30, -4);
part("body");
// Hips, broad chest, and red lacquer-like highlights.
ellipsoid(24, 24, 18, 9, 6, 5, redDark);
ellipsoid(24, 24, 24, 10, 7, 9, red);
ellipsoid(24, 22, 26, 9, 6, 6, redLight);
ellipsoid(24, 24, 19, 8, 6, 5, red);
ellipsoid(20, 17, 26, 3.5, 1.5, 3, redLight);
ellipsoid(28, 17, 26, 3.5, 1.5, 3, redLight);
line(24, 16, 25, 24, 17, 20, 0, redDark);
box(22, 16, 20, 26, 16, 20, redDark);
// Wide belt and tiger-striped loincloth.
box(16, 18, 16, 32, 30, 18, "#432c24");
box(16, 17, 18, 32, 18, 19, "#f6bd4a");
box(17, 16, 18, 31, 16, 18, "#8b551e");
box(22, 15, 17, 26, 15, 20, "#e9bb54");
box(23, 14, 18, 25, 14, 19, "#fff0b0");
ellipsoid(24, 17, 14, 6.5, 2, 6, "#eaa735");
box(19, 15, 11, 29, 16, 18, "#f1b843");
line(19, 14, 18, 23, 14, 14, 1, hair);
line(29, 14, 18, 25, 14, 13, 1, hair);
line(23, 14, 18, 22, 14, 11, 1, hair);
line(26, 14, 17, 28, 14, 11, 1, hair);
box(21, 14, 10, 27, 14, 10, "#8b551e");
// Left arm hangs forward, with a gold wrist cuff.
ellipsoid(13, 23, 25, 4.5, 4, 5, redDark);
line(14, 22, 26, 11, 19, 19, 3, red);
ellipsoid(12, 17, 17, 3, 3, 3, redLight);
cylinder(11, 19, 19, 3.2, 2, "#d99d31");
cylinder(11, 19, 20, 3, 1, "#ffe083");
// Neck and oversized, scowling face.
cylinder(24, 23, 29, 4.5, 5, redDark);
ellipsoid(24, 22, 34, 9, 7.5, 8, redDark);
ellipsoid(24, 21, 34, 8.5, 7, 7.5, red);
ellipsoid(24, 15, 31, 6, 2, 3, redLight);
ellipsoid(24, 14, 33, 2.2, 2, 2.4, redLight);
box(23, 12, 32, 25, 12, 32, redDark);
ellipsoid(16, 21, 33, 2, 2, 3, red);
ellipsoid(32, 21, 33, 2, 2, 3, red);
// Angry yellow eyes, dark pupils, and slanted brows.
for (const x of [20, 28]) {
ellipsoid(x, 14, 35, 2.8, 1.3, 2, cream);
ellipsoid(x, 12.8, 35, 1.25, 0.8, 1.4, "#f5bf25");
box(x, 12, 35, x, 12, 36, "#19181a");
set(x - 1, 11, 36, "#fff8df");
}
line(17, 13, 39, 22, 12, 37, 1, hair);
line(26, 12, 37, 31, 13, 39, 1, hair);
// Snarling mouth and two small upward tusks.
ellipsoid(24, 14, 28.5, 4.3, 1.2, 1.4, "#501718");
box(22, 12, 29, 26, 12, 29, cream);
line(20, 13, 28, 21, 12, 31, 1, cream);
line(28, 13, 28, 27, 12, 31, 1, cream);
set(21, 11, 31, "#ffffff");
set(27, 11, 31, "#ffffff");
// Wild, chunky black hair and pointed sideburns.
ellipsoid(24, 23, 40, 9.5, 8, 3.4, hair);
ellipsoid(24, 17, 41, 8.5, 4, 2.5, hairLight);
line(16, 19, 40, 11, 22, 43, 2, hair);
line(31, 19, 40, 36, 22, 43, 2, hair);
line(19, 19, 42, 16, 17, 45, 1, hair);
line(28, 19, 42, 31, 16, 45, 1, hair);
line(23, 17, 42, 21, 14, 40, 2, hair);
line(27, 17, 42, 29, 14, 40, 2, hair);
line(16, 19, 37, 17, 16, 31, 1, hair);
line(32, 19, 37, 31, 16, 31, 1, hair);
// Two short ivory horns emerging through the hair.
for (const [x, lean] of [[19, -1], [29, 1]]) {
cylinder(x, 20, 40, 2.3, 2, creamShade);
cylinder(x, 20, 42, 1.8, 2, cream);
sphere(x + lean, 20, 44, 1.2, cream);
set(x + lean, 20, 45, "#fff9e5");
}
// Club arm: shoulder, bent elbow, gripping fist, and iron weapon share one pivot.
part("clubArm", [33, 23, 28]);
ellipsoid(34, 23, 27, 4, 4, 4, redDark);
line(34, 22, 27, 35, 18, 22, 3, red);
ellipsoid(36, 17, 25, 3, 3, 3, redLight);
cylinder(35, 19, 22, 3.1, 2, "#ba8029");
cylinder(35, 19, 23, 3, 1, "#f7cc62");
// The handle angles back over the shoulder.
line(36, 16, 25, 40, 25, 37, 1.5, "#16191e");
line(37, 18, 28, 40, 25, 36, 0, ironLight);
for (let z = 26; z <= 30; z += 2)
line(36 + (z - 25) * 0.3, 17 + (z - 25) * 0.65, z,
38 + (z - 25) * 0.3, 17 + (z - 25) * 0.65, z,
0, "#8b7047");
// Heavy studded club head.
ellipsoid(40, 25, 39, 3.4, 3.3, 6, iron);
cylinder(40, 25, 35, 3, 9, iron);
ellipsoid(39, 23, 40, 2, 1, 4, ironLight);
cylinder(40, 25, 34, 3.5, 1, "#5d6265");
cylinder(40, 25, 43, 3.2, 1, "#5d6265");
for (const z of [36, 39, 42]) {
for (const [dx, dy] of [[3, 0], [-3, 0], [0, 3], [0, -3]]) {
sphere(40 + dx, 25 + dy, z, 1.1, "#858a84");
set(40 + dx + Math.sign(dx), 25 + dy + Math.sign(dy), z, "#c0bda9");
}
}
sphere(40, 25, 45, 1, "#858a84");
animate("clubArm", { type: "swing", axis: "x", speed: 3, amplitude: 0.4 });import { draw } from "./assets/voxel";
import { oni } from "./assets/oni";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, oni, 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 oni
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["oni"] })
# It lands in client/assets/oni.ts
# https://fogon.page/object/oni