← Medieval3D assetfogon/establo
Establo
Drag to turn it// «Establo» · gpt-6-sol (medium)
// A small medieval stable: dark brown plank walls on a low stone base, a thatched straw roof, an open front with two stalls separated by a plank divider, each with a half door (the top open), hay on the floor and a wooden feeding trough, a horseshoe nailed above the entrance and a lantern hanging at one corner.
const stone = ["#827d70", "#999487", "#aaa596", "#69675f"];
const wood = ["#493021", "#573824", "#65432b", "#765036"];
const straw = ["#b98b42", "#c99b4e", "#d8ac5d", "#e6bc70", "#a97b38"];
const iron = "#252525";
// Solid stone foundation and a slightly raised timber floor.
for (let x = 8; x <= 40; x++) {
for (let y = 9; y <= 39; y++) {
for (let z = 0; z <= 3; z++) {
let c = stone[Math.floor(rand() * stone.length)];
if (z === 3 && rand() < 0.055) c = "#66765a";
set(x, y, z, c);
}
if (y >= 11 && y <= 36) {
set(x, y, 4, wood[(Math.floor(x / 3) + Math.floor(rand() * 2)) % wood.length]);
}
}
}
// Low stone courses under the three enclosing walls.
for (let y = 10; y <= 39; y++) {
for (let z = 4; z <= 6; z++) {
for (let x of [8, 9, 10, 38, 39, 40])
set(x, y, z, rand() < 0.07 ? "#68765a" : stone[Math.floor(rand() * 4)]);
}
}
for (let x = 8; x <= 40; x++)
for (let y = 37; y <= 39; y++)
for (let z = 4; z <= 6; z++)
set(x, y, z, rand() < 0.06 ? "#68765a" : stone[Math.floor(rand() * 4)]);
// Horizontal plank walls, with occasional lighter hand-hewn boards.
for (let z = 7; z <= 23; z++) {
let c = wood[Math.floor(z / 3) % wood.length];
for (let y = 10; y <= 39; y++) {
box(8, y, z, 10, y, z, c);
box(38, y, z, 40, y, z, c);
}
for (let x = 11; x <= 37; x++)
box(x, 37, z, x, 39, z, c);
}
// Thick corner posts, side studs, and front framing.
for (let x of [8, 38])
for (let y of [9, 37])
box(x, y, 4, x + 2, y + 2, 25, "#39271d");
for (let y of [18, 28])
for (let x of [8, 39])
box(x, y, 7, x + 1, y + 1, 24, "#412b1e");
box(8, 9, 5, 10, 11, 25, "#38271e");
box(23, 9, 4, 25, 11, 25, "#39271d");
box(38, 9, 5, 40, 11, 25, "#38271e");
box(8, 9, 22, 40, 11, 25, "#452d20");
box(9, 8, 24, 39, 9, 24, "#765036");
// A full-height divider set back behind the two half doors.
for (let y = 12; y <= 37; y++) {
for (let z = 5; z <= 19; z++)
box(23, y, z, 24, y, z, wood[Math.floor(z / 3) % wood.length]);
}
box(22, 12, 18, 25, 37, 19, "#422b1d");
for (let y of [14, 26, 36])
box(22, y, 5, 25, y + 1, 19, "#38271d");
// Front gable: pale plaster panels between dark framing.
for (let x = 10; x <= 38; x++) {
let roofHeight = 36 - Math.floor(Math.abs(x - 24) * 0.63);
for (let z = 25; z <= roofHeight - 3; z++) {
if (x > 11 && x < 37)
set(x, 9, z, rand() < 0.09 ? "#c6b99b" : "#e1d2ad");
}
}
line(10, 9, 25, 24, 9, 34, 1, "#422c20");
line(24, 9, 34, 38, 9, 25, 1, "#422c20");
box(23, 8, 25, 25, 9, 33, "#493020");
// Two individually planked half doors; the stall openings remain clear above.
for (let [a, b] of [[11, 22], [26, 37]]) {
for (let x = a; x <= b; x++) {
let c = wood[Math.floor((x - a) / 3) % wood.length];
box(x, 9, 5, x, 10, 12, c);
if ((x - a) % 3 === 0) box(x, 8, 5, x, 8, 12, "#493021");
}
box(a, 8, 5, b, 8, 5, "#34251c");
box(a, 8, 12, b, 10, 13, "#765036");
for (let z of [6, 10]) {
box(a, 7, z, a + 4, 7, z, iron);
set(a + 3, 6, z, "#a09878");
}
box(b - 2, 7, 9, b - 1, 7, 10, iron);
set(b - 2, 6, 10, "#b5a77d");
}
// A horseshoe nailed to the central timber above the entrances.
for (let z = 27; z <= 30; z++) {
set(22, 7, z, "#292b29");
set(26, 7, z, "#292b29");
}
set(23, 7, 26, "#292b29");
set(24, 7, 26, "#292b29");
set(25, 7, 26, "#292b29");
for (let x of [22, 26]) {
set(x, 6, 28, "#8b8b7a");
set(x, 6, 30, "#8b8b7a");
}
// Hay scattered across both stall floors.
for (let i = 0; i < 340; i++) {
let x = 12 + Math.floor(rand() * 25);
let y = 13 + Math.floor(rand() * 22);
if (x >= 22 && x <= 25) continue;
set(x, y, 5 + (rand() < 0.12 ? 1 : 0), straw[1 + Math.floor(rand() * 3)]);
}
for (let [cx, cy] of [[17, 29], [32, 28]]) {
ellipsoid(cx, cy, 5, 4, 3, 1, "#bd934a");
for (let i = 0; i < 55; i++) {
let x = cx - 4 + Math.floor(rand() * 9);
let y = cy - 3 + Math.floor(rand() * 7);
if (Math.abs(x - cx) + Math.abs(y - cy) < 6)
set(x, y, 6 + Math.floor(rand() * 2), straw[Math.floor(rand() * 4)]);
}
}
// Chunky wooden feeding trough in each stall.
for (let x0 of [13, 29]) {
box(x0, 23, 5, x0 + 7, 27, 6, "#38271d");
box(x0, 23, 7, x0 + 7, 23, 9, "#70492c");
box(x0, 27, 7, x0 + 7, 27, 9, "#573824");
box(x0, 24, 7, x0, 26, 9, "#70492c");
box(x0 + 7, 24, 7, x0 + 7, 26, 9, "#70492c");
box(x0 + 1, 24, 7, x0 + 6, 26, 8, "#a77d39");
for (let i = 0; i < 34; i++)
set(x0 + 1 + Math.floor(rand() * 6), 24 + Math.floor(rand() * 3),
9 + Math.floor(rand() * 2), straw[1 + Math.floor(rand() * 3)]);
for (let x of [x0 + 1, x0 + 6]) {
set(x, 22, 8, iron);
set(x, 28, 8, iron);
}
}
// Dark rafters beneath the overhanging thatch.
for (let y of [9, 19, 29, 40]) {
line(5, y, 22, 24, y, 34, 1, "#3e2b20");
line(24, y, 34, 43, y, 22, 1, "#3e2b20");
}
// Deep, uneven straw roof. Its ridge runs from front to back.
for (let x = 4; x <= 44; x++) {
let top = 36 - Math.floor(Math.abs(x - 24) * 0.63);
for (let y = 6; y <= 42; y++) {
let shade = straw[
Math.min(4, Math.max(0,
1 + (Math.floor(y / 3) % 3) + (rand() < 0.17 ? (rand() < 0.5 ? -1 : 1) : 0)
))
];
set(x, y, top - 2, "#765a31");
set(x, y, top - 1, "#967039");
set(x, y, top, shade);
if (rand() < 0.19) set(x, y, top + 1, straw[2 + Math.floor(rand() * 2)]);
if ((y === 6 || y === 42) && rand() < 0.8)
set(x, y, top - 3 - Math.floor(rand() * 2), straw[Math.floor(rand() * 3)]);
}
}
box(23, 5, 36, 25, 43, 36, "#e2b265");
for (let y = 6; y <= 42; y += 3)
box(23, y, 37, 25, y, 37, "#f0c477");
// Extra loose straw hanging from the side eaves.
for (let y = 7; y <= 41; y++) {
for (let x of [4, 44]) {
if (rand() < 0.75)
set(x, y, 21 + Math.floor(rand() * 2), straw[Math.floor(rand() * 4)]);
}
}
// Iron bracket and warm, glowing lantern at the front corner.
box(39, 7, 21, 43, 8, 21, iron);
box(42, 7, 18, 42, 7, 20, iron);
box(40, 6, 17, 44, 8, 17, iron);
box(41, 6, 13, 43, 8, 14, iron);
box(41, 6, 15, 43, 8, 16, "#edb951");
box(42, 5, 15, 42, 5, 16, "#ffe39a");
for (let x of [41, 43])
for (let y of [6, 8])
box(x, y, 14, x, y, 17, iron);
set(42, 7, 18, "#b19b72");import { draw } from "./assets/voxel";
import { establo } from "./assets/establo";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, establo, 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 establo
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["establo"] })
# It lands in client/assets/establo.ts
# https://fogon.page/object/establo