← Medieval3D assetfogon/mesa-de-alquimista
Mesa de alquimista
Drag to turn it// «Mesa de alquimista» · gpt-6-sol (medium)
// A medieval alchemist's workbench: a heavy dark wooden table with glass flasks and bottles of bubbling colored liquids (green, purple, blue), a brass alembic distiller with coiled tubes, an open old book, a skull with a candle on top, and scrolls rolled up.
const wood = "#3b241c", woodLight = "#69422c", woodDark = "#291b18";
const brass = "#bb873e", brassLight = "#e5bd69", brassDark = "#76532d";
const iron = "#28292b", parchment = "#ead9ae";
// Four massive legs and the heavy timber frame.
for (const x of [7, 37]) for (const y of [11, 35]) {
box(x, y, 0, x + 4, y + 4, 17, wood);
box(x, y, 0, x + 4, y + 4, 2, woodDark);
box(x, y, 13, x + 4, y + 4, 14, iron);
for (const dx of [0, 4]) set(x + dx, y, 14, brassDark);
}
box(10, 12, 6, 40, 14, 9, woodDark);
box(10, 36, 6, 40, 38, 9, woodDark);
box(9, 14, 7, 11, 37, 9, woodDark);
box(39, 14, 7, 41, 37, 9, woodDark);
box(5, 9, 12, 42, 11, 17, woodDark);
box(5, 37, 12, 42, 39, 17, woodDark);
// Wide, worn plank top, with visible grain and iron-bound edges.
box(4, 8, 17, 43, 40, 19, wood);
for (let x = 5; x <= 42; x++)
for (let y = 9; y <= 39; y++) {
let c = (Math.floor(x / 8) + y) % 5 === 0 ? woodLight : "#563522";
if (rand() < 0.075) c = rand() < 0.5 ? "#754b30" : "#43291e";
set(x, y, 19, c);
}
for (const x of [13, 23, 33]) box(x, 9, 19, x, 39, 19, woodDark);
box(4, 8, 16, 43, 8, 17, iron);
box(4, 40, 16, 43, 40, 17, iron);
for (let x = 7; x <= 40; x += 6) {
set(x, 8, 17, brassDark);
set(x, 40, 17, brassDark);
}
// Three little drawers face the viewer.
for (const x of [15, 24, 33]) {
box(x, 8, 12, x + 7, 8, 16, "#73492f");
box(x + 1, 7, 13, x + 6, 7, 15, woodLight);
box(x + 3, 6, 14, x + 4, 7, 14, brass);
}
box(5, 39, 20, 42, 40, 23, woodDark);
box(5, 38, 23, 42, 40, 23, woodLight);
for (let x = 8; x <= 40; x += 5) set(x, 39, 22, brassDark);
// Alembic furnace: warm stone, dark grate, and a squat copper boiler.
box(7, 27, 20, 17, 37, 22, "#746d61");
box(8, 27, 22, 16, 36, 23, "#999084");
box(10, 26, 20, 14, 26, 22, iron);
for (const x of [11, 13]) {
set(x, 25, 21, "#e78330");
set(x, 26, 22, "#c84e25");
}
ellipsoid(12, 32, 27, 5, 5, 4, brassDark);
ellipsoid(12, 31, 28, 4, 4, 3, brass);
box(9, 27, 27, 14, 27, 28, brassLight);
for (let x = 9; x <= 15; x += 2)
set(x, 31, 31, brassLight);
cylinder(12, 32, 30, 2, 6, brass);
cylinder(12, 32, 36, 2.5, 1, brassLight);
box(11, 31, 37, 13, 33, 37, brassDark);
// Long spout and a visibly winding condensation coil.
line(14, 32, 35, 19, 32, 35, 1, brassDark);
line(15, 31, 36, 19, 31, 36, 0, brassLight);
line(19, 32, 35, 20, 34, 33, 1, brass);
const coil = [
[20,34,33], [22,35,33], [24,35,32], [24,33,31],
[22,32,31], [20,32,30], [20,35,29], [23,36,29],
[24,34,28], [22,33,27], [22,35,26], [24,36,25]
];
for (let i = 1; i < coil.length; i++)
line(...coil[i - 1], ...coil[i], 0, i % 3 ? brass : brassLight);
box(22, 35, 20, 27, 38, 21, "#514238");
cylinder(25, 36, 21, 2, 5, "#637d7b");
cylinder(25, 36, 25, 2, 1, "#b4d7d0");
// Glass vessels: thick outlines, narrow necks, broad readable shapes.
function flask(x, y, tint) {
ellipsoid(x, y, 23, 3.5, 3.5, 3.5, tint);
cylinder(x, y, 26, 1, 5, tint);
cylinder(x, y, 31, 2, 1, "#c9e4db");
cylinder(x, y, 32, 1, 1, "#506d70");
set(x - 2, y - 2, 24, "#d9f5e8");
set(x - 3, y - 1, 23, "#aacdc5");
set(x - 1, y - 1, 29, "#e3f6eb");
set(x + 2, y + 1, 22, "#466066");
}
flask(19, 23, "#709c8c");
flask(28, 27, "#927eaa");
flask(35, 20, "#779eb5");
for (const [x, y] of [[19, 23], [28, 27], [35, 20]]) {
box(x - 4, y - 4, 20, x + 4, y + 4, 20, "#34302a");
for (const dx of [-3, 3]) set(x + dx, y, 20, brassDark);
}
// Open book: red leather cover, two creamy pages and ink strokes.
box(20, 10, 20, 32, 18, 20, "#682d30");
box(19, 11, 20, 19, 17, 20, brass);
box(33, 11, 20, 33, 17, 20, brass);
box(20, 11, 21, 25, 17, 21, "#c8b68f");
box(27, 11, 21, 32, 17, 21, "#c8b68f");
box(21, 11, 22, 25, 16, 22, parchment);
box(27, 11, 22, 31, 16, 22, parchment);
box(26, 10, 21, 26, 18, 22, "#58302c");
for (const y of [12, 14, 16]) {
box(22, y, 22, 24, y, 22, "#75644e");
box(28, y, 22, 30, y, 22, "#75644e");
}
set(29, 13, 23, "#9f3332");
set(30, 13, 23, brass);
// Two rolled scrolls, tied with royal-blue cord and wax.
for (const [y, len] of [[13, 9], [18, 7]]) {
cylinder(8, y, 22, 1.5, len, parchment, "x");
cylinder(8, y, 22, 2, 1, "#b69d73", "x");
cylinder(8 + len, y, 22, 2, 1, "#b69d73", "x");
cylinder(11, y, 22, 2, 1, "#283d70", "x");
set(11, y - 2, 22, brass);
}
set(12, 11, 22, "#a43a33");
// Skull behind the book, with deep sockets and chunky teeth.
ellipsoid(37, 32, 25, 3.5, 3, 3.5, "#c6bb9e");
ellipsoid(37, 31, 26, 3, 2.5, 2.5, "#eee2bf");
box(35, 29, 22, 39, 32, 24, "#d0c2a3");
for (const x of [35, 38]) {
box(x, 28, 25, x + 1, 29, 26, "#302b2b");
set(x, 28, 27, "#a99b7e");
}
set(37, 28, 23, "#473a34");
for (const x of [35, 36, 38, 39])
set(x, 28, 22, "#f3e8c9");
// Wax candle balanced on the skull; a small golden flame.
box(36, 31, 28, 38, 33, 34, "#efe2bb");
box(36, 30, 30, 36, 30, 31, "#cfc09d");
box(38, 30, 29, 38, 30, 30, "#d6c59e");
set(37, 32, 35, iron);
sphere(37, 32, 36, 1, "#f5aa39");
set(37, 32, 37, "#ffe6a0");
// Liquids are one animated part, distinct from their stationary glass.
part("liquids", [24, 25, 23]);
for (const [x, y, color] of [
[19, 23, "#48be58"],
[28, 27, "#8b51be"],
[35, 20, "#408ecb"]
]) {
ellipsoid(x, y, 22, 2.5, 2.5, 1.5, color);
box(x - 2, y - 1, 23, x + 2, y + 1, 23, color);
set(x - 1, y - 2, 24, "#b6e5a2");
set(x + 1, y - 1, 24, "#d6c4f0");
set(x, y, 26, color);
set(x + 1, y, 28, "#a6e4de");
}
animate("liquids", {
type: "colors",
palette: ["#35aa55", "#9be36a", "#9654be", "#398fd1"],
pattern: "pulse",
glow: 0.6
});
part("body", [24, 24, 0]);import { draw } from "./assets/voxel";
import { mesaDeAlquimista } from "./assets/mesa-de-alquimista";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, mesaDeAlquimista, 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 mesa-de-alquimista
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["mesa-de-alquimista"] })
# It lands in client/assets/mesa-de-alquimista.ts
# https://fogon.page/object/mesa-de-alquimista