← Medieval3D assetfogon/puesto-de-mercado
Puesto de mercado
Drag to turn it// «Puesto de mercado» · gpt-6-sol (medium)
// A medieval market stall: a dark brown timber frame with four posts holding a sloped striped awning in deep red and cream cloth, a wooden counter in front covered with small goods (red apples, yellow cheese wheels, round brown bread loaves, a couple of clay jugs), and two wicker baskets on the ground at the sides.
const timber = "#493020", timberLight = "#65422a", timberDark = "#301f18";
const iron = "#282a2b", gold = "#d2a64e";
const stone = ["#88847b", "#a09b8f", "#706f69"];
const wicker = "#a5743e", wickerLight = "#c29153", wickerDark = "#78502d";
// Uneven stone paving beneath the stall.
for (let x = 10; x <= 38; x++)
for (let y = 12; y <= 37; y++) {
set(x, y, 0, stone[Math.floor(rand() * stone.length)]);
if (rand() < 0.025) set(x, y, 0, "#718063");
}
// Four stout posts, with stone feet and iron straps.
for (const x of [9, 39]) for (const y of [11, 35]) {
box(x - 1, y - 1, 0, x + 1, y + 1, 2, "#89857b");
box(x - 1, y - 1, 3, x + 1, y + 1, y === 35 ? 32 : 27, timber);
box(x - 1, y - 1, 5, x + 1, y + 1, 5, iron);
box(x - 1, y - 1, 23, x + 1, y + 1, 23, iron);
set(x, y - 2, 5, "#b3aaa0");
set(x, y - 2, 23, "#b3aaa0");
box(x - 1, y - 1, 3, x - 1, y - 1, y === 35 ? 32 : 27, timberLight);
}
// Heavy framing beneath the sloping awning.
line(9, 10, 27, 9, 36, 33, 1, timberDark);
line(39, 10, 27, 39, 36, 33, 1, timberDark);
box(9, 35, 30, 39, 36, 32, timber);
box(9, 10, 25, 39, 11, 27, timber);
box(9, 34, 15, 39, 35, 16, timberDark);
for (const x of [15, 33]) {
line(x, 35, 17, x, 35, 30, 0, timberLight);
}
// Front counter: thick plank top, broad paneled front, and iron nails.
box(11, 11, 3, 12, 19, 12, timberDark);
box(36, 11, 3, 37, 19, 12, timberDark);
box(12, 12, 4, 36, 13, 11, timber);
for (let x = 16; x <= 33; x += 6)
box(x, 11, 4, x, 11, 10, timberDark);
box(10, 10, 12, 38, 20, 14, timberDark);
box(10, 10, 14, 38, 20, 15, timberLight);
box(10, 10, 15, 38, 10, 15, "#815534");
for (let x = 13; x <= 36; x += 5) {
set(x, 10, 6, iron);
set(x, 10, 10, iron);
}
box(12, 13, 8, 36, 19, 8, timberLight);
// Rear display shelves and a little heraldic sign.
box(14, 31, 9, 34, 35, 10, timberLight);
box(14, 31, 16, 34, 35, 17, timberLight);
box(21, 34, 19, 27, 34, 24, gold);
box(22, 33, 20, 26, 33, 23, "#294c86");
box(24, 32, 20, 24, 32, 23, gold);
box(22, 32, 21, 26, 32, 21, gold);
// Bread: browned crust with a few pale score marks.
function bread(x, y, z, rx = 2, ry = 2) {
ellipsoid(x, y, z, rx, ry, 1.7, "#85502c");
ellipsoid(x, y, z + 1, rx - 0.3, ry - 0.3, 0.8, "#bd7d40");
for (let dx = -1; dx <= 1; dx++)
set(x + dx, y, z + 2, "#e2ad68");
}
for (const [x, y] of [[14, 14], [20, 16], [33, 16]])
bread(x, y, 16);
for (const x of [17, 23, 30])
bread(x, 32, 12, 2, 1.5);
// Small red apples with stems and leaves.
function apple(x, y, z) {
sphere(x, y, z, 1.35, "#a72d2a");
set(x, y - 1, z, "#cf5140");
set(x, y, z + 2, timberDark);
set(x + 1, y, z + 2, "#648244");
}
for (const [x, y] of [[25, 13], [28, 15], [31, 13], [26, 18], [30, 18]])
apple(x, y, 17);
// Chunky yellow cheese wheels and cut wedges.
for (const [x, y] of [[16, 18], [35, 13]]) {
cylinder(x, y, 16, 2, 2, "#c38a30");
cylinder(x, y, 18, 2, 1, "#efd06b");
set(x + 1, y - 1, 18, "#b98632");
}
box(34, 17, 16, 36, 19, 17, "#e9c45b");
set(36, 17, 17, "#b98632");
// Two clay jugs with narrow necks, lips, and angular handles.
function jug(x, y) {
cylinder(x, y, 16, 1.7, 4, "#a66646");
cylinder(x, y, 20, 1, 2, "#bc7d55");
cylinder(x, y, 22, 1.4, 1, "#76452f");
set(x, y, 22, "#382b26");
line(x + 2, y, 19, x + 3, y, 19, 0, "#995b3b");
line(x + 3, y, 19, x + 3, y, 21, 0, "#995b3b");
line(x + 3, y, 21, x + 1, y, 21, 0, "#995b3b");
}
jug(15, 33);
jug(33, 33);
// Open-topped wicker baskets resting beside the stall.
function basket(cx, cy) {
for (let z = 1; z <= 6; z++) {
const r = z <= 2 ? 3 : 4;
for (let dx = -r; dx <= r; dx++)
for (let dy = -r; dy <= r; dy++) {
const d = Math.sqrt(dx * dx + dy * dy);
if (d <= r && (z <= 2 || d >= r - 1.25))
set(cx + dx, cy + dy, z,
(dx + dy + z) % 3 === 0 ? wickerLight : wicker);
}
}
for (let z of [2, 4, 6])
for (let dx = -4; dx <= 4; dx++)
for (let dy = -4; dy <= 4; dy++) {
const d = Math.sqrt(dx * dx + dy * dy);
if (d >= 3.4 && d <= 4.35)
set(cx + dx, cy + dy, z, z === 6 ? wickerLight : wickerDark);
}
box(cx - 2, cy - 2, 2, cx + 2, cy + 2, 3, wickerDark);
}
basket(5, 25);
basket(43, 25);
for (const [x, y] of [[4, 24], [7, 26], [42, 24], [44, 26]])
apple(x, y, 6);
// The striped cloth alone pivots about its rear attachment.
part("awning", [24, 36, 33]);
const red = ["#922b31", "#a6383a", "#b54543"];
const cream = ["#e4d4ad", "#f1dfb9", "#d4c298"];
function clothColor(x, y) {
const stripe = Math.floor((x - 7) / 5);
const shades = stripe % 2 === 0 ? red : cream;
return shades[rand() < 0.78 ? 0 : (rand() < 0.5 ? 1 : 2)];
}
for (let y = 8; y <= 37; y++) {
const z = 26 + Math.floor((y - 8) / 5);
for (let x = 7; x <= 41; x++) {
set(x, y, z - 1, clothColor(x, y));
set(x, y, z, clothColor(x, y));
if (x === 7 || x === 41) set(x, y, z - 2, clothColor(x, y));
}
}
// Deep scalloped fringe along the front, with golden tassel tips.
for (let x = 7; x <= 41; x++) {
const stripe = Math.floor((x - 7) / 5);
const drop = (x - 7) % 5 === 2 ? 4 : 3;
for (let z = 26 - drop; z <= 25; z++)
set(x, 7, z, clothColor(x, 7));
if ((x - 7) % 5 === 2)
set(x, 7, 25 - drop, stripe % 2 ? "#c6a35f" : gold);
}
animate("awning", { type: "swing", axis: "x", speed: 1.5, amplitude: 0.08 });import { draw } from "./assets/voxel";
import { puestoDeMercado } from "./assets/puesto-de-mercado";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, puestoDeMercado, 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 puesto-de-mercado
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["puesto-de-mercado"] })
# It lands in client/assets/puesto-de-mercado.ts
# https://fogon.page/object/puesto-de-mercado