← Medieval3D assetfogon/torre-de-asedio
Torre de asedio
Drag to turn it// «Torre de asedio» · gpt-6-sol (medium)
// A tall wooden siege tower: a square plank tower on six solid wooden wheels, three floors with ladders visible through side openings, the front covered with brown hides, a drawbridge ramp at the top front folded up, and a red banner on top. Much taller than wide.
const wood = "#70452c";
const woodLight = "#92603a";
const woodDark = "#4a3025";
const edge = "#382820";
const iron = "#252a2c";
const ironLight = "#545556";
const gold = "#d3aa58";
const red = "#a33235";
// Three heavy axles and six solid wheels.
for (const wy of [17, 25, 33]) {
box(12, wy, 4, 35, wy, 6, woodDark);
for (const wx of [10, 35]) {
cylinder(wx, wy, 4, 4, 3, wood, "x");
const outerX = wx === 10 ? 9 : 38;
// Iron tire, wooden spokes, and a bright central hub.
for (let dy = -4; dy <= 4; dy++) {
for (let dz = -4; dz <= 4; dz++) {
const d = Math.hypot(dy, dz);
if (d >= 3.45 && d <= 4.55)
set(outerX, wy + dy, 4 + dz, d > 3.9 ? iron : ironLight);
else if (d < 3.45)
set(outerX, wy + dy, 4 + dz, woodDark);
}
}
for (let a = 0; a < 8; a++) {
const t = a * Math.PI / 4;
line(outerX, wy, 4,
outerX, wy + Math.round(3 * Math.cos(t)),
4 + Math.round(3 * Math.sin(t)), 0, woodLight);
}
cylinder(outerX, wy, 4, 1, 1, gold, "x");
set(outerX - (wx === 10 ? 1 : -1), wy, 4, iron);
}
}
// The tower stands on a broad, timber-framed carriage.
box(14, 13, 8, 33, 37, 10, woodDark);
for (let y = 14; y <= 36; y += 3)
box(15, y, 11, 32, y + 1, 11, y % 2 ? woodLight : wood);
for (const x of [14, 33]) {
box(x, 13, 9, x, 37, 11, edge);
box(x, 13, 12, x, 37, 12, woodLight);
}
// Three solid floors, with individually readable planks.
for (const z of [21, 32, 38]) {
box(15, 14, z, 32, 36, z, woodDark);
for (let y = 14; y <= 36; y += 3)
box(15, y, z + 1, 32, y + 1, z + 1, woodLight);
for (const x of [14, 33])
box(x, 13, z, x, 37, z + 1, edge);
box(14, 13, z, 33, 13, z + 1, edge);
box(14, 37, z, 33, 37, z + 1, edge);
}
// Open timber sides: their broad bays leave the ladders visible.
for (const x of [14, 33]) {
for (const y of [13, 19, 28, 37]) {
box(x, y, 11, x, y + 1, 39, woodDark);
box(x, y, 13, x, y, 38, wood);
for (const z of [15, 27, 36])
set(x, y, z, iron);
}
for (const z of [12, 21, 32, 39]) {
box(x, 13, z, x, 37, z + 1, edge);
box(x, 14, z + 1, x, 36, z + 1, woodLight);
}
// Diagonal braces at the ends, without closing the central opening.
for (const z of [13, 23, 34]) {
line(x, 14, z, x, 19, z + 5, 0, woodLight);
line(x, 31, z + 5, x, 36, z, 0, woodLight);
}
}
// Back framing and narrow planked panels.
for (const x of [14, 21, 27, 33])
box(x, 37, 11, x + 1, 37, 39, woodDark);
for (const z of [16, 27, 36])
box(14, 37, z, 33, 37, z + 1, wood);
for (let x = 16; x <= 31; x += 3) {
box(x, 37, 13, x + 1, 37, 20, wood);
box(x, 37, 23, x + 1, 37, 31, woodLight);
}
// Two ladders stand behind the open side bays, one per upper floor.
for (const [x, z0, z1] of [[31, 12, 23], [31, 23, 34]]) {
for (const y of [21, 27])
box(x, y, z0, x, y, z1, woodLight);
for (let z = z0 + 2; z < z1; z += 2)
box(x, 21, z, x, 27, z, wood);
}
// An outer ladder makes the right-side silhouette especially clear.
for (const y of [21, 27])
box(34, y, 12, 34, y, 34, woodDark);
for (let z = 14; z <= 33; z += 2)
box(34, 21, z, 34, 27, z, woodLight);
// The front is armored in irregular, stitched brown hides.
box(14, 13, 11, 15, 13, 39, edge);
box(32, 13, 11, 33, 13, 39, edge);
for (let z = 13; z <= 32; z++) {
for (let x = 16; x <= 31; x++) {
const patch = Math.floor((x - 16) / 5) + Math.floor((z - 13) / 6);
let c = ["#81563b", "#a0744c", "#765038", "#956846"][patch % 4];
if (rand() < 0.11) c = "#b08558";
set(x, 12, z, c);
}
}
for (const x of [20, 25, 30]) {
box(x, 11, 14, x, 11, 31, "#50382c");
for (let z = 16; z <= 30; z += 3) set(x, 10, z, gold);
}
for (const z of [18, 24, 30]) {
box(16, 11, z, 31, 11, z, "#60412e");
for (let x = 18; x <= 30; x += 4) set(x, 10, z, "#c4a078");
}
// Iron straps and rivets around the hide-covered face.
for (const z of [12, 22, 33]) {
box(15, 11, z, 32, 11, z, iron);
for (const x of [16, 21, 26, 31]) set(x, 10, z, ironLight);
}
// Top-front drawbridge, folded upright at its floor hinge.
box(17, 9, 34, 30, 11, 39, woodDark);
for (let z = 35; z <= 39; z += 2)
box(18, 8, z, 29, 8, z, woodLight);
for (const x of [17, 30]) {
box(x, 8, 34, x, 8, 39, edge);
for (const z of [35, 38]) set(x, 7, z, ironLight);
box(x, 9, 33, x + 1, 12, 34, iron);
}
box(17, 8, 39, 30, 8, 39, iron);
for (const [x0, x1] of [[15, 18], [32, 29]])
line(x0, 12, 39, x1, 8, 37, 0, ironLight);
// A low crenellated crown, with dark iron fasteners.
for (const x of [14, 19, 24, 29, 33]) {
box(x, 13, 40, Math.min(x + 1, 33), 13, 41, woodDark);
box(x, 37, 40, Math.min(x + 1, 33), 37, 41, woodDark);
}
for (const y of [14, 20, 26, 32, 36]) {
box(14, y, 40, 14, y + 1, 41, woodDark);
box(33, y, 40, 33, y + 1, 41, woodDark);
}
box(14, 13, 39, 33, 13, 39, woodLight);
box(14, 37, 39, 33, 37, 39, woodLight);
// Pole stays fixed; only the red, gold-edged banner swings.
box(24, 24, 39, 24, 24, 45, edge);
set(24, 24, 45, gold);
part("banner", [24, 24, 44]);
box(25, 24, 42, 32, 24, 45, "#9e3037");
box(25, 23, 45, 32, 23, 45, gold);
box(25, 23, 42, 25, 23, 44, gold);
box(27, 23, 43, 30, 23, 44, "#bd4242");
set(28, 22, 44, gold);
set(29, 22, 44, gold);
box(33, 24, 44, 34, 24, 45, "#9e3037");
set(33, 23, 45, gold);
animate("banner", { type: "swing", axis: "z", speed: 3, amplitude: 0.3 });
part("body");import { draw } from "./assets/voxel";
import { torreDeAsedio } from "./assets/torre-de-asedio";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, torreDeAsedio, 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 torre-de-asedio
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["torre-de-asedio"] })
# It lands in client/assets/torre-de-asedio.ts
# https://fogon.page/object/torre-de-asedio