← Basics3D assetfogon/mecedora-que-se-mece
Mecedora que se mece
Drag to turn it// «Mecedora que se mece» · gpt-6-sol (medium)
// Rocking chair («Mecedora que se mece»).
// A warm, carved wooden rocking chair.
part("rocking_chair", [23.5, 23.5, 1.5]);
const dark = "#774318";
const shadow = "#93551f";
const wood = "#b97831";
const light = "#d99a48";
const highlight = "#edb563";
function timber(x0, y0, z0, x1, y1, z1) {
box(x0, y0, z0, x1, y1, z1, dark);
if (z1 > z0) box(x0, y0, z0 + 1, x1, y1, z1, wood);
box(x0, y0, z1, x1, y1, z1, light);
if (x1 > x0 && y1 > y0) {
line(x0, y0, z1, x1, y0, z1, 0, highlight);
}
}
// Two long rockers, rising gracefully at both ends.
for (const x of [10, 35]) {
for (let y = 3; y <= 43; y++) {
let rise = 0;
if (y < 10) rise = Math.ceil((10 - y) * 0.75);
if (y > 36) rise = Math.ceil((y - 36) * 0.75);
box(x, y, rise, x + 4, y, rise + 2, shadow);
box(x, y, rise + 1, x + 4, y, rise + 2, wood);
box(x, y, rise + 2, x + 4, y, rise + 2, light);
set(x, y, rise + 1, dark);
}
// Subtle shaped tips and thickened mounting points.
timber(x, 3, 5, x + 4, 5, 7);
timber(x, 41, 4, x + 4, 43, 6);
for (const y of [14, 32]) timber(x, y - 1, 2, x + 4, y + 2, 4);
}
// Legs and the open framework under the seat.
for (const x of [12, 35]) {
timber(x, 14, 3, x + 3, 17, 17);
timber(x, 31, 3, x + 3, 34, 19);
box(x, 14, 5, x + 3, 14, 12, light); // front-facing edge
box(x, 31, 5, x + 3, 31, 12, light);
}
timber(15, 15, 8, 35, 16, 10);
timber(15, 32, 8, 35, 33, 10);
timber(13, 18, 8, 14, 31, 10);
timber(36, 18, 8, 37, 31, 10);
// Seat frame: deep front apron and slimmer side aprons.
timber(12, 12, 14, 38, 15, 18);
timber(13, 30, 14, 37, 33, 18);
timber(12, 16, 14, 15, 30, 17);
timber(35, 16, 14, 38, 30, 17);
box(15, 12, 15, 34, 12, 16, light);
for (const x of [15, 35]) {
box(x, 12, 15, x + 2, 12, 16, highlight);
}
// Individual broad planks, with narrow dark joints and wood grain.
for (const [a, b] of [[14, 19], [21, 26], [28, 33], [35, 37]]) {
timber(a, 15, 18, b, 32, 19);
for (let i = 0; i < 9; i++) {
const gx = a + Math.floor(rand() * (b - a + 1));
const gy = 17 + Math.floor(rand() * 13);
const len = 1 + Math.floor(rand() * 4);
line(gx, gy, 19, gx, Math.min(31, gy + len), 19, 0,
rand() < 0.5 ? "#c58a3c" : "#e3a758");
}
}
for (const x of [20, 27, 34]) box(x, 17, 19, x, 31, 19, shadow);
// Tall back posts lean slightly away from the seat.
for (const x of [12, 35]) {
for (let z = 18; z <= 39; z++) {
const y = 32 + Math.floor((z - 18) / 7);
box(x, y, z, x + 3, y + 2, z, wood);
box(x, y, z, x + 3, y, z, light);
set(x, y + 2, z, shadow);
}
timber(x - 1, 35, 38, x + 4, 38, 40);
timber(x, 36, 41, x + 3, 37, 42);
set(x + 1, 36, 43, highlight);
}
// Lower back rail, turned vertical spindles, and broad top rail.
timber(15, 33, 20, 35, 35, 22);
for (const x of [17, 20, 23, 26, 29, 32]) {
for (let z = 23; z <= 36; z++) {
const y = 33 + Math.floor((z - 22) / 7);
set(x, y, z, z % 5 === 0 ? light : wood);
set(x, y + 1, z, shadow);
}
timber(x - 1, 33, 23, x + 1, 35, 24);
timber(x - 1, 34, 33, x + 1, 36, 34);
box(x - 1, 34, 28, x + 1, 35, 29, light);
}
timber(14, 35, 36, 37, 38, 39);
box(17, 35, 39, 34, 36, 39, highlight);
for (const x of [18, 25, 32]) {
box(x, 35, 35, x + 1, 37, 36, dark);
box(x, 35, 36, x + 1, 36, 36, light);
}
// Upright arm supports, then long, slightly overhanging armrests.
for (const x of [12, 35]) {
timber(x, 14, 19, x + 2, 16, 24);
timber(x - 1, 13, 23, x + 3, 17, 24);
box(x, 14, 21, x + 2, 14, 22, highlight);
timber(x, 29, 20, x + 2, 32, 25);
}
timber(10, 12, 25, 16, 34, 26);
timber(33, 12, 25, 39, 34, 26);
box(11, 12, 27, 15, 31, 27, highlight);
box(34, 12, 27, 38, 31, 27, highlight);
for (const x of [10, 33]) {
timber(x, 11, 24, x + 6, 15, 27);
box(x + 1, 11, 26, x + 5, 11, 27, light);
}
animate("rocking_chair", {
type: "swing", axis: "x", speed: 1.4, amplitude: 0.12
});import { draw } from "./assets/voxel";
import { mecedoraQueSeMece } from "./assets/mecedora-que-se-mece";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, mecedoraQueSeMece, 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 mecedora-que-se-mece
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["mecedora-que-se-mece"] })
# It lands in client/assets/mecedora-que-se-mece.ts
# https://fogon.page/object/mecedora-que-se-mece