← Medieval3D assetfogon/princesa
Princesa
Drag to turn it// «Princesa» · gpt-6-sol (medium)
// A chunky cartoon medieval princess: a wide bell-shaped pink dress with white lace trim, a big round head with long golden braided hair, black dot eyes, pink cheeks and a small silver tiara.
// Chunky storybook princess, facing -y.
const pink = ["#b94f79", "#d96893", "#eb83aa", "#f39bbb"];
const cream = "#fff2e8";
const laceShadow = "#e5d4d0";
const gold = ["#ad751e", "#d8992b", "#f2bc48", "#ffdb75"];
const skin = "#f5c6a7";
function skirtRadius(z) {
const t = Math.min(z, 22) / 22;
return [18 - 10 * Math.pow(t, 1.35), 14 - 7 * Math.pow(t, 1.35)];
}
function frontY(x, z) {
const [rx, ry] = skirtRadius(z);
const dx = (x - 24) / rx;
return Math.round(24 - ry * Math.sqrt(Math.max(0, 1 - dx * dx)));
}
// Solid, wide bell skirt.
for (let z = 0; z <= 22; z++) {
const [rx, ry] = skirtRadius(z);
for (let x = Math.ceil(24 - rx); x <= Math.floor(24 + rx); x++) {
for (let y = Math.ceil(24 - ry); y <= Math.floor(24 + ry); y++) {
const d = ((x - 24) / rx) ** 2 + ((y - 24) / ry) ** 2;
if (d > 1) continue;
let c = z < 2 ? cream : pink[z < 5 ? 0 : z < 13 ? 1 : 2];
if (z >= 5 && d < 0.84 && y < 24) c = pink[3];
if (z >= 5 && rand() < 0.045) c = pink[1];
set(x, y, z, c);
}
}
}
// Scalloped lace along the front hem and a darker ribbon above it.
for (let x = 8; x <= 40; x++) {
for (let z = 2; z <= 5; z++) {
const [rx] = skirtRadius(z);
if (Math.abs(x - 24) > rx - 1) continue;
const y = frontY(x, z) - 1;
if (z === 2 || (z === 3 && x % 4 !== 0) || (z === 4 && x % 4 === 2))
set(x, y, z, cream);
if (z === 5) set(x, y, z, "#a83e68");
}
}
// Pleated front panels and tiny embroidered flowers.
for (const x of [15, 19, 29, 33]) {
for (let z = 7; z <= 17; z++) {
const [rx] = skirtRadius(z);
if (Math.abs(x - 24) < rx - 1)
set(x, frontY(x, z) - 1, z, z % 5 === 0 ? "#ffe0b4" : "#f5a8bf");
}
}
for (const x of [13, 24, 35]) {
const z = x === 24 ? 10 : 8;
const y = frontY(x, z) - 2;
set(x, y, z, "#ffe3aa");
set(x - 1, y, z, cream);
set(x + 1, y, z, cream);
set(x, y, z + 1, cream);
set(x, y, z - 1, cream);
}
// Fitted bodice and ivory collar.
ellipsoid(24, 24, 25, 8, 6, 6, "#d4658e");
box(20, 17, 23, 28, 18, 27, "#e77da2");
box(21, 16, 23, 27, 16, 24, "#a8476b");
for (let x = 19; x <= 29; x++) {
const z = 30 - Math.abs(x - 24) / 2;
set(x, 18, z, cream);
}
box(22, 16, 26, 26, 16, 27, "#315184");
box(23, 15, 27, 25, 15, 28, "#f4c859");
set(24, 14, 27, "#ab354b");
// Golden hair behind the head, with long chunky braided pigtails.
ellipsoid(24, 25, 36, 9, 8, 9, gold[1]);
box(17, 27, 27, 31, 31, 38, gold[0]);
for (const side of [-1, 1]) {
const x = 24 + side * 10;
for (let z = 23; z <= 38; z += 3) {
const drift = z < 29 ? side : 0;
ellipsoid(x + drift, 19 + (z % 2), z, 2.5, 2.5, 2.4,
gold[(Math.floor(z / 3) % 2) ? 2 : 1]);
set(x + drift - 1, 16, z + 1, gold[3]);
}
ellipsoid(x + side, 19, 22, 2, 2, 2, gold[2]);
box(x + side - 1, 17, 19, x + side + 1, 20, 20, "#b7476e");
}
// Big round face.
ellipsoid(24, 23, 35, 8, 7, 8, skin);
ellipsoid(24, 22, 38, 7, 6, 4, "#ffd6b5");
// Hair framing the face and a swept, blocky fringe.
for (let z = 34; z <= 41; z++) {
set(16, 18, z, gold[2]);
set(32, 18, z, gold[1]);
}
box(19, 16, 41, 29, 19, 43, gold[1]);
box(18, 16, 39, 22, 17, 41, gold[2]);
box(23, 16, 40, 30, 17, 42, gold[2]);
box(21, 15, 39, 23, 16, 40, gold[3]);
// Simple face: black dot eyes, rosy cheeks, tiny smile.
for (const x of [21, 27]) {
box(x, 15, 35, x + 1, 15, 36, "#25202b");
set(x, 14, 36, "#25202b");
set(x + 1, 14, 36, "#25202b");
set(x, 14, 37, "#fff9ed");
}
for (const x of [18, 29]) {
box(x, 16, 32, x + 1, 16, 33, "#ec91a0");
}
set(24, 14, 33, "#d99c89");
box(23, 15, 31, 25, 15, 31, "#ba6170");
set(24, 14, 30, "#f9a7a7");
// Small silver tiara with three points and a blue jewel.
box(20, 16, 43, 28, 18, 44, "#a6b1bc");
box(21, 15, 44, 27, 16, 44, "#edf4f4");
box(21, 16, 45, 22, 17, 45, "#d3dfe2");
box(26, 16, 45, 27, 17, 45, "#d3dfe2");
box(23, 16, 45, 25, 17, 46, "#e4edef");
set(24, 15, 44, "#39699c");
// Independent, gently swinging arms.
for (const side of [-1, 1]) {
const x = 24 + side * 9;
const name = side < 0 ? "leftArm" : "rightArm";
part(name, [x, 22, 28]);
ellipsoid(x, 22, 26, 3.5, 3.5, 4, "#e77da2");
ellipsoid(x + side * 1.5, 21, 24, 2.4, 2.5, 3, "#f19abd");
box(x + side * 2 - 1, 18, 21, x + side * 2 + 1, 22, 22, cream);
ellipsoid(x + side * 2, 20, 19, 2, 2, 2.5, skin);
animate(name, {
type: "swing", axis: "x", speed: side < 0 ? 2 : -2, amplitude: 0.25
});
}
part("body", [24, 24, 0]);import { draw } from "./assets/voxel";
import { princesa } from "./assets/princesa";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, princesa, 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 princesa
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["princesa"] })
# It lands in client/assets/princesa.ts
# https://fogon.page/object/princesa