← AnimalesObjeto 3Dfogon/mariposa
Mariposa
Arrastrá para girarlo// «Mariposa» · gpt-6-sol (medium)
// A big cartoon butterfly seen from above but standing on the floor, body along y: a thin black body with antennae and four big wings in bright orange with black veins and white spots on the edges (monarch style).
const black = "#211d21";
const edge = "#17191d";
const white = "#fff7e5";
const fore = [
[20,14], [16,11], [10,8], [6,8], [4,10], [2,15],
[3,19], [7,23], [13,26], [20,26]
];
const hind = [
[20,25], [13,25], [8,27], [5,31], [6,36],
[10,40], [16,41], [19,38], [20,34]
];
function inside(x, y, poly) {
let hit = false;
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
const a = poly[i], b = poly[j];
if ((a[1] > y) !== (b[1] > y) &&
x < (b[0] - a[0]) * (y - a[1]) / (b[1] - a[1]) + a[0]) hit = !hit;
}
return hit;
}
function edgeDistance(x, y, poly) {
let best = 100;
for (let i = 0; i < poly.length; i++) {
const a = poly[i], b = poly[(i + 1) % poly.length];
const dx = b[0] - a[0], dy = b[1] - a[1];
const t = Math.max(0, Math.min(1,
((x - a[0]) * dx + (y - a[1]) * dy) / (dx * dx + dy * dy)));
best = Math.min(best, Math.hypot(x - a[0] - t * dx, y - a[1] - t * dy));
}
return best;
}
function wing(side, kind) {
const front = kind === "fore";
const poly = front ? fore : hind;
const mirror = x => side === "left" ? x : 48 - x;
const pivot = [mirror(20), front ? 20 : 30, 5];
const name = `${side}_${kind}`;
part(name, pivot);
for (let y = 7; y <= 42; y++) {
for (let x = 2; x <= 20; x++) {
if (!inside(x + 0.5, y + 0.5, poly)) continue;
const d = edgeDistance(x + 0.5, y + 0.5, poly);
const border = d < 2.1;
const outerOrange = d < 3.5;
const X = mirror(x);
set(X, y, 3, border ? edge : "#a94914");
set(X, y, 4, border ? edge : "#d76618");
set(X, y, 5, border ? black : "#ee831c");
set(X, y, 6, border ? edge :
outerOrange ? "#dc6816" :
rand() < 0.13 ? "#ffac32" : rand() < 0.13 ? "#e97419" : "#f68d20");
// Warm golden patches near the root of each wing.
const rootY = front ? 22 : 28;
if (!border && x > 13 && Math.hypot(x - 20, (y - rootY) * 1.2) < 7)
set(X, y, 6, rand() < 0.2 ? "#ffcf55" : "#ffac2d");
}
}
// Fine black monarch veins, radiating from the wing joints.
const veins = front ? [
[[19,23],[7,10]], [[19,23],[4,14]], [[19,23],[4,19]],
[[19,23],[9,24]], [[16,18],[11,9]]
] : [
[[19,27],[8,28]], [[19,27],[7,33]], [[19,27],[10,38]],
[[19,27],[16,39]], [[13,31],[7,35]]
];
for (const [a, b] of veins) {
const steps = Math.ceil(Math.hypot(b[0] - a[0], b[1] - a[1]) * 3);
for (let i = 0; i <= steps; i++) {
const t = i / steps;
const x = Math.round(a[0] + (b[0] - a[0]) * t);
const y = Math.round(a[1] + (b[1] - a[1]) * t);
if (inside(x + 0.5, y + 0.5, poly)) set(mirror(x), y, 7, black);
}
}
// Oversized ivory spots along the black outer margins.
const spots = front
? [[7,10],[5,13],[4,17],[5,20],[8,22],[11,24],[12,11],[16,14]]
: [[9,28],[7,31],[8,35],[11,38],[15,39],[18,36]];
for (const [sx, sy] of spots) {
for (let dy = -1; dy <= 1; dy++)
for (let dx = -1; dx <= 1; dx++) {
const x = sx + dx, y = sy + dy;
if (dx * dx + dy * dy <= 1 && inside(x + 0.5, y + 0.5, poly))
set(mirror(x), y, 7, white);
}
if (inside(sx + 0.5, sy + 0.5, poly))
set(mirror(sx), sy, 8, "#ffffff");
}
animate(name, {
type: "swing", axis: "y",
speed: side === "left" ? 8 : -8, amplitude: 0.6
});
}
wing("left", "hind");
wing("right", "hind");
wing("left", "fore");
wing("right", "fore");
part("body", [24,24,5]);
// Little feet hold the butterfly above the floor.
for (const y of [19,29]) {
for (const x of [21,27]) {
line(24, y, 5, x, y + 2, 0, 0, black);
box(x - 1, y + 1, 0, x + 1, y + 3, 0, "#30272a");
}
}
// Slim segmented body, with a round toy-like head.
ellipsoid(24, 31, 6, 3, 8, 3, "#30262a");
ellipsoid(24, 22, 7, 4, 6, 3, "#30282a");
ellipsoid(24, 13, 7, 4, 5, 4, "#45332c");
ellipsoid(24, 12, 9, 3, 4, 2, "#574037");
for (const y of [28,32,36])
box(22, y, 9, 26, y, 9, "#71503a");
line(24, 18, 10, 24, 26, 10, 0, "#765038");
// Simple, bright eyes read clearly from above.
for (const x of [22,26]) {
box(x - 1, 11, 11, x, 13, 11, "#151619");
set(x - 1, 11, 12, "#ffffff");
}
// Curled antennae reach forward of the head.
line(23, 9, 9, 20, 5, 9, 0, black);
line(20, 5, 9, 17, 4, 9, 0, black);
line(25, 9, 9, 28, 5, 9, 0, black);
line(28, 5, 9, 31, 4, 9, 0, black);
sphere(17, 4, 9, 1, "#342428");
sphere(31, 4, 9, 1, "#342428");import { draw } from "./assets/voxel";
import { mariposa } from "./assets/mariposa";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, mariposa, x, y, { size: 64, angle: 0, t: performance.now() / 1000 });
// size: lo que mide en px su lado más largo
// angle: giro sobre el piso, en radianes
// t: segundos; si se mueve, se anima solo con eso# En una terminal, en la carpeta del juego
fogon assets add mariposa
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["mariposa"] })
# Queda en client/assets/mariposa.ts
# https://fogon.page/object/mariposa