← Asian3D assetfogon/daruma
Daruma
Drag to turn it// «Daruma» · gpt-6-sol (medium)
// A round red Daruma doll standing on the ground: an egg-shaped body painted bright red with gold patterns on the sides, a white face area with a big black mustache and eyebrows, ONE eye painted black and the other left blank white.
part("doll", [24, 24, 0]);
const profile = [
[0, 8], [2, 11], [5, 14], [10, 17], [17, 18],
[23, 17.5], [29, 15], [34, 11], [38, 6], [39, 3]
];
function radius(z) {
for (let i = 1; i < profile.length; i++) {
if (z <= profile[i][0]) {
const [z0, r0] = profile[i - 1];
const [z1, r1] = profile[i];
return r0 + (r1 - r0) * (z - z0) / (z1 - z0);
}
}
return 0;
}
const front = Array.from({ length: 40 }, () => ({}));
// Solid, rounded lacquer body.
for (let z = 0; z <= 39; z++) {
const r = radius(z);
for (let x = Math.ceil(24 - r); x <= Math.floor(24 + r); x++) {
const reach = r * Math.sqrt(Math.max(0, 1 - ((x - 24) / r) ** 2));
for (let y = Math.ceil(24 - reach); y <= Math.floor(24 + reach); y++) {
if (front[z][x] === undefined) front[z][x] = y;
let color = "#d92524";
if (z < 4) color = "#9d171b";
else if (y > 29 || z < 9) color = "#b91c20";
else if (z > 23 && x < 29) color = "#ed3430";
if (rand() < 0.035) color = z < 9 ? "#a71b1d" : "#e43b32";
set(x, y, z, color);
}
}
}
function paint(x, z, color) {
x = Math.round(x);
z = Math.round(z);
const y = front[z]?.[x];
if (y === undefined) return;
set(x, y - 1, z, color);
set(x, y, z, color);
}
function dot(cx, cz, r, color) {
for (let x = Math.floor(cx - r); x <= Math.ceil(cx + r); x++)
for (let z = Math.floor(cz - r); z <= Math.ceil(cz + r); z++)
if ((x - cx) ** 2 + (z - cz) ** 2 <= r * r)
paint(x, z, color);
}
function stroke(x0, z0, x1, z1, width, color) {
const steps = Math.ceil(Math.hypot(x1 - x0, z1 - z0) * 3);
for (let i = 0; i <= steps; i++) {
const t = i / steps;
dot(x0 + (x1 - x0) * t, z0 + (z1 - z0) * t, width, color);
}
}
function curve(points, width, color) {
for (let i = 1; i < points.length; i++)
stroke(...points[i - 1], ...points[i], width, color);
}
// Gold foot rim and small lacquer highlights.
for (let x = 11; x <= 37; x++) {
paint(x, 3, "#d7a346");
if (x % 3 !== 0) paint(x, 4, "#f2c966");
}
curve([[12, 8], [15, 7], [19, 6], [24, 6], [29, 6], [33, 7], [36, 8]],
0.55, "#e9b954");
// Raised gold frame around the face.
for (let a = 0; a < Math.PI * 2; a += 0.018) {
const x = 24 + 11.8 * Math.cos(a);
const z = 26.2 + 8.7 * Math.sin(a);
dot(x, z, 0.65, "#e7ac43");
}
// Cream-white painted face.
for (let z = 18; z <= 35; z++) {
for (let x = 12; x <= 36; x++) {
const u = (x - 24) / 10.9;
const v = (z - 26.2) / 7.8;
if (u * u + v * v <= 1) {
paint(x, z, z > 29 ? "#fff8e9" : x > 30 ? "#eee6d7" : "#fff4e4");
}
}
}
// Dark, expressive eyebrows.
curve([[16, 30], [18, 32], [20, 32], [22, 30.5]], 1.05, "#211b1c");
curve([[26, 30.5], [28, 32], [30, 32], [32, 30]], 1.05, "#211b1c");
stroke(17, 32.5, 20, 33, 0.35, "#44302a");
stroke(28, 33, 31, 32.5, 0.35, "#44302a");
// Only the viewer-left eye is painted; the right eye remains white.
for (let z = 24; z <= 29; z++)
for (let x = 16; x <= 22; x++)
if (((x - 19) / 2.1) ** 2 + ((z - 26.5) / 2.6) ** 2 <= 1)
paint(x, z, "#17191a");
paint(18, 28, "#fffdf1");
// Heavy, sweeping black mustache.
dot(24, 23, 1.35, "#211819");
curve([[24, 22], [21, 23], [19, 23], [17, 21], [16, 20]],
1.15, "#211819");
curve([[24, 22], [27, 23], [29, 23], [31, 21], [32, 20]],
1.15, "#211819");
dot(20, 22, 1.15, "#211819");
dot(28, 22, 1.15, "#211819");
// Mirrored gold cloud-scrolls and lotus petals on the red sides.
for (const s of [-1, 1]) {
const X = d => 24 + s * d;
curve([[X(13), 29], [X(16), 27], [X(17), 24], [X(15), 22],
[X(13), 23], [X(13), 25]], 0.8, "#f4cb68");
dot(X(13), 25, 0.8, "#ffe092");
curve([[X(11), 18], [X(15), 17], [X(17), 14], [X(16), 12],
[X(13), 12]], 0.8, "#e7ad43");
curve([[X(11), 18], [X(12), 14], [X(11), 11]], 0.65, "#ffd778");
curve([[X(11), 18], [X(9), 15], [X(9), 12]], 0.65, "#ffd778");
dot(X(11), 18, 1.05, "#f7ce68");
dot(X(15), 12, 0.8, "#ffe092");
for (const [d, z] of [[15, 30], [18, 19], [14, 9], [10, 11]])
dot(X(d), z, 0.8, "#f3c463");
}
// Little gold crest below the face.
curve([[20, 13], [22, 15], [24, 16], [26, 15], [28, 13]],
0.8, "#f4c766");
curve([[20, 13], [23, 12], [24, 10], [25, 12], [28, 13]],
0.65, "#e9af49");
dot(24, 14, 0.9, "#ffe299");
animate("doll", { type: "swing", axis: "y", speed: 2, amplitude: 0.2 });import { draw } from "./assets/voxel";
import { daruma } from "./assets/daruma";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, daruma, 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 daruma
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["daruma"] })
# It lands in client/assets/daruma.ts
# https://fogon.page/object/daruma