← Medieval3D assetfogon/mercader
Mercader
Drag to turn it// «Mercader» · gpt-6-sol (medium)
// A chunky cartoon medieval merchant: a plump body in a rich purple robe with gold trim and a wide belt with a coin pouch, a round head with a pointed grey beard and a big floppy blue hat, black dot eyes, holding a small balance scale in one hand.
const purple = "#653177", purpleLight = "#824695", purpleDark = "#482256";
const gold = "#e3b951", goldDark = "#a97930";
const skin = "#e9b985", skinShade = "#c98c68";
const blue = "#315b9d", blueLight = "#4877b6", blueDark = "#213e70";
// Sturdy little walking boots and trouser legs.
function leg(name, x, speed) {
part(name, [x, 24, 10]);
box(x - 3, 20, 2, x + 2, 28, 11, "#44354a");
box(x - 3, 18, 0, x + 3, 28, 4, "#493026");
box(x - 3, 18, 3, x + 3, 19, 4, "#654430");
box(x - 3, 18, 0, x + 3, 28, 0, "#30241f");
animate(name, { type: "swing", axis: "x", speed, amplitude: 0.3 });
}
leg("left leg", 19, 5);
leg("right leg", 29, -5);
// Broad, plump robe.
part("body", [24, 24, 18]);
ellipsoid(24, 24, 18, 11, 10, 12, purple);
forEach((x, y, z, color) => {
if (color !== purple) return;
if (z < 11 || y > 30) set(x, y, z, purpleDark);
else if (z > 23 && rand() < 0.36) set(x, y, z, purpleLight);
else if (rand() < 0.075) set(x, y, z, rand() < 0.5 ? purpleLight : purpleDark);
});
// Thick golden robe hem, following its rounded outline.
for (let x = 14; x <= 34; x++)
for (let y = 15; y <= 33; y++)
for (let z = 7; z <= 9; z++)
if (get(x, y, z) && (!get(x, y - 1, z) || !get(x, y, z - 1)))
set(x, y, z, z === 7 ? goldDark : gold);
// Front seam, wide leather belt, and square gold buckle.
box(23, 13, 9, 25, 15, 17, goldDark);
box(24, 12, 10, 24, 13, 16, gold);
box(16, 14, 17, 32, 17, 19, "#55351f");
box(17, 13, 19, 31, 15, 19, "#76502b");
box(21, 12, 16, 27, 13, 20, goldDark);
box(22, 11, 17, 26, 12, 19, gold);
box(23, 10, 17, 25, 10, 18, "#5b3923");
// Bulging coin pouch, with flap and one bright coin peeking out.
ellipsoid(32, 13, 13, 4, 3, 4, "#88532f");
box(29, 10, 15, 35, 12, 17, "#aa7040");
box(30, 9, 15, 34, 9, 15, "#6b4129");
box(31, 9, 16, 33, 9, 16, gold);
set(32, 8, 15, goldDark);
// Left sleeve and swinging hand.
part("left arm", [13, 23, 27]);
ellipsoid(11, 23, 22, 5, 6, 7, purpleDark);
ellipsoid(10, 21, 22, 4, 5, 6, purple);
box(8, 18, 16, 13, 26, 18, goldDark);
box(8, 18, 18, 13, 26, 19, gold);
ellipsoid(10, 20, 15, 3, 3, 2, skin);
box(9, 17, 13, 11, 18, 15, skinShade);
animate("left arm", { type: "swing", axis: "x", speed: -5, amplitude: 0.25 });
// Right sleeve, hand, and the little balance scale it carries.
part("right arm", [35, 23, 27]);
ellipsoid(37, 23, 22, 5, 6, 7, purpleDark);
ellipsoid(38, 20, 22, 4, 5, 6, purple);
box(36, 17, 17, 41, 25, 19, goldDark);
box(36, 17, 19, 41, 25, 20, gold);
ellipsoid(39, 17, 17, 3, 3, 2, skin);
box(38, 14, 17, 40, 17, 19, skinShade);
// Brass stem, finial, crossbar, chains, and two shallow weighing pans.
box(39, 13, 19, 40, 14, 29, goldDark);
box(39, 12, 21, 39, 12, 28, gold);
sphere(39, 13, 30, 2, gold);
line(33, 13, 27, 45, 13, 27, 1, goldDark);
line(34, 12, 28, 44, 12, 28, 0, gold);
for (const x of [34, 44]) {
line(x, 13, 26, x, 13, 22, 0, "#d1ad61");
line(x - 2, 13, 23, x, 13, 21, 0, goldDark);
line(x + 2, 13, 23, x, 13, 21, 0, goldDark);
ellipsoid(x, 13, 21, 3, 2, 1, goldDark);
box(x - 2, 12, 22, x + 2, 14, 22, gold);
}
animate("right arm", { type: "swing", axis: "x", speed: 5, amplitude: 0.25 });
// Collar, neck, and round, friendly face.
part("body", [24, 24, 18]);
box(20, 19, 27, 28, 27, 31, purpleDark);
box(19, 17, 29, 29, 20, 30, gold);
ellipsoid(24, 21, 35, 7, 6, 7, skin);
ellipsoid(17, 21, 34, 2, 2, 3, skinShade);
ellipsoid(31, 21, 34, 2, 2, 3, skinShade);
// Grey side whiskers and a broad beard tapering to a point.
const beard = "#a7a6a3", beardLight = "#c9c8c2", beardDark = "#777977";
for (let z = 26; z <= 34; z++) {
const width = Math.min(7, Math.floor((z - 25) * 0.9) + 1);
for (let x = 24 - width; x <= 24 + width; x++) {
const edge = Math.abs(x - 24) >= width - 1;
box(x, 14 + (edge ? 2 : 0), z, x, 16, z,
edge ? beardDark : (x < 24 ? beardLight : beard));
}
}
box(18, 15, 32, 22, 16, 34, beardLight);
box(26, 15, 32, 30, 16, 34, beard);
box(22, 13, 33, 26, 15, 34, skin);
set(24, 12, 33, skinShade);
box(20, 13, 36, 21, 15, 37, "#211d25");
box(27, 13, 36, 28, 15, 37, "#211d25");
set(21, 12, 37, "#fff2d8");
set(28, 12, 37, "#fff2d8");
box(19, 14, 39, 22, 15, 39, "#775b53");
box(26, 14, 39, 29, 15, 39, "#775b53");
// Oversized floppy blue hat: broad brim, pinched crown, drooping tip.
ellipsoid(24, 21, 41, 12, 10, 2, blueDark);
ellipsoid(23, 20, 42, 11, 9, 1, blueLight);
ellipsoid(22, 22, 44, 8, 7, 3, blue);
ellipsoid(24, 21, 46, 5, 4, 1, blueLight);
ellipsoid(30, 19, 43, 6, 5, 2, blue);
ellipsoid(34, 17, 40, 5, 4, 2, blueDark);
box(17, 13, 41, 29, 15, 41, goldDark);
box(20, 13, 42, 27, 14, 42, gold);import { draw } from "./assets/voxel";
import { mercader } from "./assets/mercader";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, mercader, 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 mercader
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["mercader"] })
# It lands in client/assets/mercader.ts
# https://fogon.page/object/mercader