// === BUILD PLAN ===
// Style: Victorian institutional (asymmetric, cross gables, bay window, wrap porch, gingerbread trim)
// Footprint: T/cross plan — main range x24..40 z36..52 + front cross-gable bay x28..36 z52..57
// + round DRUM tower r=7 @ (48,44) on the east flank. Wrap porch on the south front.
// Height: floorY11 / walkY12 · floor2 slab Y17 / walkY18 · wall top Y23
// main ridge Y32 (along Z) · front cross gable ridge Y28 (along Z, gable faces SOUTH) => 2 ridges
// drum wall Y11..Y34 · copper DRUM ring Y35..Y37 · CAP Y38..Y45 · CROWN finial Y46
//
// GROUND FLOOR (1 char = 1 block, Z down):
// ############## ....#####....
// # LIBRARY # ..# #..
// # #==A== .# ROTUNDA #. A = arched opening range<->drum
// ##### ####### .# (drum r7) #.
// # HALL # ..# #..
// # [stair] # ....#####....
// #### #####
// # BAY # BAY = front cross-gable projection + bay window
// ##[D]## D = main door, wrap porch in front
//
// SOUTH ELEVATION:
// _.-**-._ <- copper CAP = stacked shrinking cylinders (r 7,6,6,5,4,3,2,1)
// /\ | drum | + CROWN finial (never leave the apex open)
// / \ /\ |========| <- cut_copper drum ring + slab cornice
// / MAIN\ /BAY\ | W W |
// |WW WW | | WW | | W W |
// |WW WW | |[BW] | |________|
// ==porch=====porch======
//
// MATERIALS PLAN (what / where / WHY):
// wing : gradientPalette Y12->Y23 stone_bricks(0) -> bricks(.30) -> white_terracotta(.78), noise .25
// WHY: stone plinth -> brick body -> pale stucco upper = a VALUE RAMP that fakes AO low & light high
// trim : stripped_birch_log pilasters + quartz_stairs cornice — WHY: light trim CONTRASTS the brick (Victorian)
// drum : gradientPalette stone_bricks -> smooth_stone -> diorite -> polished_diorite — WHY: rendered stucco drum,
// lighter as it rises so the CYLINDER reads round rather than as a flat grey tube
// dome : per Clean Dome/Cupola — oxidation kept LOW: weathered(0) -> exposed(.20) -> cut_copper(.45) ->
// copper_block(.70). WHY: heavy oxidized copper reads as MOSS/foliage, not metal
// roof : noisePalette deepslate_tile/deepslate_brick/polished_deepslate STAIRS (palette into the stair MATERIAL)
// + polished_deepslate SOLID ridge beam — WHY: slate variety, and a solid ridge can never gap
// Rooms: Library (shelf walls, lectern, reading chairs, rug), Entrance Hall + Bay (table, chairs, bay seat,
// chandelier, stair), Rotunda (instrument plinth, benches), Study/map room (desks, charts, shelves),
// Telescope floor (brass telescope on a yoke pointing through the slit, chests, charts)
// STAIR PLAN: hall walkY12 -> floor2 walkY18 (D=6) via staircase() dir north; floor2 -> telescope floor is FLAT
// (both at walkY18) through an arched opening at x40/41 => fully navigable with ONE flight.
// === END PLAN ===
var padY = 10;
var floorY = 11, walkY = 12;
var f2Y = 17, walkY2 = 18;
var topY = 23, roofBaseY = 24;
var mx1 = 24, mx2 = 40, mz1 = 36, mz2 = 52;
var bx1 = 28, bx2 = 36, bz1 = 52, bz2 = 57;
var dcx = 48, dcz = 44, DR = 7;
var drumTopY = 34, ringY = 35, capY = 38;
// ---------- palettes ----------
var wingMat = gradientPalette(walkY, topY, [
{ block: 'stone_bricks', from: 0 },
{ block: 'bricks', from: 0.30 },
{ block: 'white_terracotta', from: 0.78 }
], { noise: 0.25, seed: 12 });
var drumMat = gradientPalette(floorY, drumTopY, [
{ block: 'stone_bricks', from: 0 },
{ block: 'smooth_stone', from: 0.32 },
{ block: 'diorite', from: 0.66 },
{ block: 'polished_diorite', from: 0.88 }
], { noise: 0.18, seed: 27 });
// Clean Dome rule: keep oxidation LOW, weathered only at the bottom
var domeMat = gradientPalette(capY, capY + 9, [
{ block: 'cut_copper', from: 0 },
{ block: 'exposed_copper', from: 0.16 },
{ block: 'weathered_copper', from: 0.38 },
{ block: 'oxidized_copper', from: 0.60 }
], { noise: 0.20, seed: 33 });
var roofMat = noisePalette([
{ block: 'deepslate_tile_stairs', weight: 45 },
{ block: 'deepslate_brick_stairs', weight: 30 },
{ block: 'polished_deepslate_stairs', weight: 25 }
], { seed: 6, freq: 0.1 });
var stoneFloorMat = noisePalette([
{ block: 'polished_diorite', weight: 40 },
{ block: 'polished_andesite', weight: 35 },
{ block: 'smooth_stone', weight: 25 }
], { seed: 44, freq: 0.14 });
var plankMat = noisePalette([
{ block: 'dark_oak_planks', weight: 60 },
{ block: 'spruce_planks', weight: 40 }
], { seed: 55, freq: 0.16 });
function boxWalls(x1, y1, z1, x2, y2, z2, mat) {
fill(x1, y1, z1, x2, y2, z1, mat);
fill(x1, y1, z2, x2, y2, z2, mat);
fill(x1, y1, z1, x1, y2, z2, mat);
fill(x2, y1, z1, x2, y2, z2, mat);
}
// === TERRAIN (blob + hills + flatten pad; flatten's return is what surface() gets) ===
var land = blob(38, 42, 35, { irregularity: 0.38, seed: 17 });
var hilly = hills({ base: 5, amp: 6, scale: 0.03, seed: 22 });
var padFn = flatten(hilly, { cx: 36, cz: 45, r: 26 }, padY, 10);
var groundMat = patches(['grass_block', 'grass_block', 'podzol'], 0.05, 7);
surface(land, padFn, groundMat, { sub: 'dirt', deep: 'stone', depth: 4 });
fill(20, floorY, 22, 58, 48, 62, 'air'); // no ground may intrude into the built volume
// === MAIN RANGE + FRONT BAY (shell) ===
fill(mx1, floorY, mz1, mx2, floorY, mz2, stoneFloorMat);
fill(bx1, floorY, bz1, bx2, floorY, bz2, stoneFloorMat);
boxWalls(mx1, walkY, mz1, mx2, topY, mz2, wingMat);
boxWalls(bx1, walkY, bz1, bx2, topY, bz2, wingMat);
// open the bay into the hall
fill(bx1 + 1, walkY, bz1, bx2 - 1, topY - 1, bz1, 'air');
// plinth (protruding stone base) + string course + cornice = horizontal relief
boxWalls(mx1 - 1, floorY, mz1 - 1, mx2 + 1, floorY + 2, mz2 + 1, 'stone_bricks');
boxWalls(bx1 - 1, floorY, bz1 - 1, bx2 + 1, floorY + 2, bz2 + 1, 'stone_bricks');
boxWalls(mx1 - 1, f2Y, mz1 - 1, mx2 + 1, f2Y, mz2 + 1, 'quartz_slab[type=top]');
boxWalls(bx1 - 1, f2Y, bz1 - 1, bx2 + 1, f2Y, bz2 + 1, 'quartz_slab[type=top]');
boxWalls(mx1 - 1, topY, mz1 - 1, mx2 + 1, topY, mz2 + 1, 'quartz_block');
boxWalls(bx1 - 1, topY, bz1 - 1, bx2 + 1, topY, bz2 + 1, 'quartz_block');
// pilasters (light birch trim against brick) every 4 blocks
var pzs = [39, 43, 47, 51];
for (var pi = 0; pi < pzs.length; pi++) {
fill(mx1 - 1, walkY, pzs[pi], mx1 - 1, topY - 1, pzs[pi], 'stripped_birch_log[axis=y]');
fill(mx2 + 1, walkY, pzs[pi], mx2 + 1, topY - 1, pzs[pi], 'stripped_birch_log[axis=y]');
}
fill(bx1 - 1, walkY, bz2 + 1, bx1 - 1, topY - 1, bz2 + 1, 'stripped_birch_log[axis=y]');
fill(bx2 + 1, walkY, bz2 + 1, bx2 + 1, topY - 1, bz2 + 1, 'stripped_birch_log[axis=y]');
// clear interiors, then floors/ceiling
fill(mx1 + 1, walkY, mz1 + 1, mx2 - 1, topY - 1, mz2 - 1, 'air');
fill(bx1 + 1, walkY, bz1 + 1, bx2 - 1, topY - 1, bz2 - 1, 'air');
fill(mx1 + 1, f2Y, mz1 + 1, mx2 - 1, f2Y, mz2 - 1, plankMat);
fill(bx1 + 1, f2Y, bz1, bx2 - 1, f2Y, bz2 - 1, plankMat);
fill(mx1 + 1, topY, mz1 + 1, mx2 - 1, topY, mz2 - 1, 'spruce_planks');
fill(bx1 + 1, topY, bz1, bx2 - 1, topY, bz2 - 1, 'spruce_planks');
// ROUND-ARCH windows, recessed 1 block, with sill (Round Arch Patterns span-3: centre taller than jambs)
function archWindow(ax, ay, az, axis, face) {
// axis 'x' = window sits in a wall running along X (north/south face); 'z' = east/west face
var k;
for (k = 0; k < 3; k++) {
var hgt = (k === 1) ? 4 : 3;
var j;
for (j = 0; j < hgt; j++) {
if (axis === 'x') pb(ax - 1 + k, ay + j, az, 'glass_pane');
else pb(ax, ay + j, az - 1 + k, 'glass_pane');
}
// arch head stone above each opening column
if (axis === 'x') pb(ax - 1 + k, ay + hgt, az, 'quartz_block');
else pb(ax, ay + hgt, az - 1 + k, 'quartz_block');
}
// sill
if (axis === 'x') { ps(ax - 1, ay - 1, az, 'quartz_stairs[facing=' + face + ',half=top]'); ps(ax, ay - 1, az, 'quartz_stairs[facing=' + face + ',half=top]'); ps(ax + 1, ay - 1, az, 'quartz_stairs[facing=' + face + ',half=top]'); }
else { ps(ax, ay - 1, az - 1, 'quartz_stairs[facing=' + face + ',half=top]'); ps(ax, ay - 1, az, 'quartz_stairs[facing=' + face + ',half=top]'); ps(ax, ay - 1, az + 1, 'quartz_stairs[facing=' + face + ',half=top]'); }
}
var wz = [38, 42, 46, 50];
for (var wi = 0; wi < wz.length; wi++) {
archWindow(mx1, walkY + 1, wz[wi], 'z', 'west');
archWindow(mx1, walkY2 + 1, wz[wi], 'z', 'west');
}
archWindow(mx2, walkY + 1, 38, 'z', 'east');
archWindow(mx2, walkY2 + 1, 38, 'z', 'east');
archWindow(mx2, walkY2 + 1, 50, 'z', 'east');
archWindow(28, walkY + 1, mz1, 'x', 'north');
archWindow(36, walkY + 1, mz1, 'x', 'north');
archWindow(28, walkY2 + 1, mz1, 'x', 'north');
archWindow(36, walkY2 + 1, mz1, 'x', 'north');
archWindow(32, walkY2 + 1, bz2, 'x', 'south');
// VICTORIAN BAY WINDOW — 3-wide bump-out, 1 deep, on the bay's south face
fill(31, walkY, bz2 + 1, 33, topY - 4, bz2 + 1, 'stripped_birch_log[axis=y]');
fill(31, walkY, bz2 + 1, 33, walkY - 1, bz2 + 1, 'stone_bricks');
fill(31, walkY + 1, bz2 + 1, 33, walkY + 3, bz2 + 1, 'glass_pane');
fill(30, walkY + 1, bz2, 30, walkY + 3, bz2 + 1, 'glass_pane');
fill(34, walkY + 1, bz2, 34, walkY + 3, bz2 + 1, 'glass_pane');
fill(30, walkY + 4, bz2 + 1, 34, walkY + 4, bz2 + 1, 'quartz_slab[type=bottom]');
fill(30, walkY, bz2, 34, walkY + 4, bz2, 'air');
fill(30, floorY, bz2 + 1, 34, floorY, bz2 + 1, 'stone_bricks');
// === DRUM TOWER ===
for (var yy = floorY; yy <= drumTopY; yy++) {
var isBase = (yy <= floorY + 2);
var rOut = isBase ? DR + 1 : DR;
for (var dx = -DR - 3; dx <= DR + 3; dx++) {
for (var dz = -DR - 3; dz <= DR + 3; dz++) {
var dd = Math.sqrt(dx * dx + dz * dz);
if (dd > rOut + 0.5 || dd <= rOut - 0.95) continue;
var bx = dcx + dx, bz = dcz + dz;
var ang = Math.atan2(dz, dx) * 180 / Math.PI; if (ang < 0) ang += 360;
var win = false;
var tg = [60, 120, 180, 240, 300];
for (var ti = 0; ti < tg.length; ti++) {
var da = Math.abs(ang - tg[ti]); if (da > 180) da = 360 - da;
var mh = -1;
if (da <= 4) mh = 5; else if (da <= 8) mh = 4; else if (da <= 11) mh = 2;
if (mh < 0) continue;
if (yy >= 14 && yy <= 14 + mh) win = true; // rotunda: tall arched windows
if (yy >= 26 && yy <= 26 + mh) win = true; // telescope floor: tall arched windows
}
if (win && !isBase) pb(bx, yy, bz, 'glass_pane');
else pb(bx, yy, bz, drumMat(bx, yy, bz));
}
}
}
// tapered BUTTRESSES (depth 3 at the base -> 1 at the top) between the windows
var bAng = [30, 90, 150, 210, 270, 330];
for (var bi = 0; bi < bAng.length; bi++) {
var ra = bAng[bi] * Math.PI / 180;
for (var by = floorY; by <= drumTopY - 1; by++) {
var dep = Math.max(1, Math.ceil((topY + 2 - by) / 5));
if (by > topY + 2) dep = 1;
for (var k2 = 0; k2 < dep; k2++) {
var qx = dcx + Math.round((DR + k2) * Math.cos(ra));
var qz = dcz + Math.round((DR + k2) * Math.sin(ra));
pb(qx, by, qz, k2 === 0 ? 'polished_andesite' : 'stone_bricks');
}
}
var tx = dcx + Math.round(DR * Math.cos(ra));
var tz = dcz + Math.round(DR * Math.sin(ra));
ps(tx, drumTopY, tz, 'stone_brick_stairs[facing=north,half=top]');
}
// cornice ring at the top of the drum (1-block overhang, 2 courses)
for (var cy = drumTopY - 1; cy <= drumTopY; cy++) {
for (var ax = -DR - 2; ax <= DR + 2; ax++) {
for (var az = -DR - 2; az <= DR + 2; az++) {
var d3 = Math.sqrt(ax * ax + az * az);
if (d3 > DR + 1.5 || d3 <= DR + 0.05) continue;
pb(dcx + ax, cy, dcz + az, cy === drumTopY ? 'quartz_block' : 'chiseled_stone_bricks');
}
}
}
// === DOME: DRUM ring -> stacked shrinking cylinders CAP -> CROWN ===
makeCylinder(dcx, ringY, dcz, 'cut_copper', DR, 3, false);
for (var rx2 = -DR - 2; rx2 <= DR + 2; rx2++) {
for (var rz2 = -DR - 2; rz2 <= DR + 2; rz2++) {
var d4 = Math.sqrt(rx2 * rx2 + rz2 * rz2);
if (d4 > DR + 1.4 || d4 <= DR - 0.1) continue;
pb(dcx + rx2, ringY + 2, dcz + rz2, 'cut_copper_slab[type=top]'); // cornice on the copper drum
}
}
// hemispherical CAP: hold the radius wide at the springing, 2-block-thick rings so the steps read round
var capR = [7, 7, 7, 6, 6, 5, 4, 3, 1];
for (var ci = 0; ci < capR.length; ci++) {
var oR2 = capR[ci];
var iR2 = (ci >= 7) ? -1 : oR2 - 2;
for (var kx = -oR2; kx <= oR2; kx++) {
for (var kz = -oR2; kz <= oR2; kz++) {
var kd = kx * kx + kz * kz;
if (kd > oR2 * oR2 + oR2) continue;
if (iR2 >= 0 && kd <= iR2 * iR2) continue;
pb(dcx + kx, capY + ci, dcz + kz, domeMat(dcx + kx, capY + ci, dcz + kz));
}
}
}
// CROWN — never leave the apex open
pb(dcx, capY + 9, dcz, 'oxidized_copper');
pb(dcx, capY + 10, dcz, 'lightning_rod[facing=up]');
// observing SLIT on the +Z flank (stops short of the crown)
fill(dcx - 2, capY, dcz + 1, dcx + 2, capY + 5, dcz + DR + 1, 'air');
fill(dcx - 2, ringY, dcz + DR - 1, dcx + 2, ringY + 2, dcz + DR + 1, 'air');
for (var sy = ringY; sy <= capY + 5; sy++) {
pb(dcx - 3, sy, dcz + 4, 'cut_copper');
pb(dcx + 3, sy, dcz + 4, 'cut_copper');
}
// === SLATE ROOFS (palette fed into the stair MATERIAL so facing survives) ===
// main range: ridge along Z at x=32
var halfW = 9;
for (var rz = mz1 - 1; rz <= mz2 + 1; rz++) {
for (var st = 0; st < halfW; st++) {
var exL = mx1 - 1 + st, exR = mx2 + 1 - st;
if (!(exR === mx2 + 1 && rz >= 41 && rz <= 47)) roofStair(exR, roofBaseY + st, rz, roofMat(exR, 0, rz), 'east');
roofStair(exL, roofBaseY + st, rz, roofMat(exL, 0, rz), 'west');
}
pb(32, roofBaseY + halfW - 1, rz, 'polished_deepslate'); // SOLID ridge beam
}
// gable triangles north & south of the main range
for (var gs = 0; gs < halfW; gs++) {
for (var gx = mx1 - 1 + gs; gx <= mx2 + 1 - gs; gx++) {
pb(gx, roofBaseY + gs, mz1, wingMat(gx, topY, mz1));
pb(gx, roofBaseY + gs, mz2, wingMat(gx, topY, mz2));
}
}
// front cross gable over the bay: ridge along Z at x=32, lower (Y28) => 2 intersecting ridges
var halfB = 5;
for (var rz3 = bz1; rz3 <= bz2 + 1; rz3++) {
for (var st2 = 0; st2 < halfB; st2++) {
roofStair(bx1 - 1 + st2, roofBaseY + st2, rz3, roofMat(bx1 - 1 + st2, 0, rz3), 'west');
roofStair(bx2 + 1 - st2, roofBaseY + st2, rz3, roofMat(bx2 + 1 - st2, 0, rz3), 'east');
}
pb(32, roofBaseY + halfB - 1, rz3, 'polished_deepslate');
}
// bay south gable triangle + junction fill against the main range (multi-volume junction rule)
for (var gs2 = 0; gs2 < halfB; gs2++) {
for (var gx2 = bx1 - 1 + gs2; gx2 <= bx2 + 1 - gs2; gx2++) {
pb(gx2, roofBaseY + gs2, bz2, wingMat(gx2, topY, bz2));
pb(gx2, roofBaseY + gs2, bz1, wingMat(gx2, topY, bz1));
}
}
// gingerbread trim under the eaves (Victorian)
for (var tz2 = mz1; tz2 <= mz2; tz2 += 1) {
if (tz2 % 2 === 0) { pb(mx1 - 1, roofBaseY - 1, tz2, 'iron_bars'); pb(mx2 + 1, roofBaseY - 1, tz2, 'iron_bars'); }
}
for (var tx2 = bx1 - 1; tx2 <= bx2 + 1; tx2++) {
ps(tx2, roofBaseY - 1, bz2 + 1, 'spruce_trapdoor[facing=south,half=top,open=false]');
}
// chimney
fill(26, walkY, 37, 27, roofBaseY + 11, 38, 'bricks');
fill(26, roofBaseY + 12, 37, 27, roofBaseY + 12, 38, 'brick_slab[type=bottom]');
pb(26, roofBaseY + 12, 37, 'campfire[lit=true]');
// === OPENINGS ===
fill(mx2, walkY, 43, dcx - DR, walkY + 2, 45, 'air'); // ground: hall/library <-> rotunda
ps(mx2, walkY + 3, 43, 'quartz_stairs[facing=east,half=top]');
ps(mx2, walkY + 3, 45, 'quartz_stairs[facing=east,half=top]');
fill(mx2, walkY2, 43, dcx - DR, walkY2 + 2, 45, 'air'); // floor2 <-> telescope floor (both walkY18)
fill(32, walkY, bz2, 32, walkY + 1, bz2, 'air'); // main door hole
ps(32, walkY, bz2, 'spruce_door[facing=south,half=lower,hinge=left]');
ps(32, walkY + 1, bz2, 'spruce_door[facing=south,half=upper,hinge=left]');
// interior partition: library (north) / hall (south), doorway at x=32
fill(mx1 + 1, walkY, 44, mx2 - 1, topY - 7, 44, 'stone_bricks');
fill(31, walkY, 44, 33, walkY + 2, 44, 'air');
ps(31, walkY + 3, 44, 'quartz_stairs[facing=south,half=top]');
ps(33, walkY + 3, 44, 'quartz_stairs[facing=south,half=top]');
// === DRUM INTERIOR: rotunda floor, telescope floor ===
for (var fx = -DR; fx <= DR; fx++) {
for (var fz = -DR; fz <= DR; fz++) {
var fd = Math.sqrt(fx * fx + fz * fz);
if (fd > DR - 0.6) continue;
pb(dcx + fx, floorY, dcz + fz, ((fx + fz) % 4 + 4) % 4 < 2 ? 'polished_diorite' : 'polished_andesite');
pb(dcx + fx, f2Y, dcz + fz, plankMat(dcx + fx, f2Y, dcz + fz));
}
}
// ring beam so the telescope floor doesn't look like a floating disc
for (var rb = -DR; rb <= DR; rb++) {
for (var rc = -DR; rc <= DR; rc++) {
var rd = Math.sqrt(rb * rb + rc * rc);
if (rd > DR - 0.6 || rd <= DR - 1.7) continue;
pb(dcx + rb, f2Y - 1, dcz + rc, 'dark_oak_log[axis=y]');
}
}
// === STAIR: hall walkY12 -> floor2 walkY18 (one navigable flight) ===
try {
staircase(27, 50, walkY, walkY2, 'north', { width: 2, material: 'dark_oak_stairs', rail: 'oak_fence' });
} catch (e1) {
staircase(27, 50, walkY, walkY2, 'north');
}
// === INTERIOR: ENTRANCE HALL + BAY (z45..z57) ===
rug(30, walkY, 47, 5, 5, 'red', 'orange');
pb(33, walkY, 49, 'dark_oak_fence'); pb(33, walkY + 1, 49, 'dark_oak_pressure_plate');
pb(34, walkY, 49, 'dark_oak_fence'); pb(34, walkY + 1, 49, 'dark_oak_pressure_plate');
chairStair(33, walkY, 48, 'dark_oak_stairs', 'south');
chairStair(34, walkY, 50, 'dark_oak_stairs', 'north');
chairStair(30, walkY, 55, 'spruce_stairs', 'south'); // bay window seat
chairStair(31, walkY, 55, 'spruce_stairs', 'south');
chairStair(33, walkY, 55, 'spruce_stairs', 'south');
pb(32, walkY, 55, 'oak_fence'); pb(32, walkY + 1, 55, 'oak_pressure_plate');
pb(35, walkY, 54, 'flower_pot'); pb(29, walkY, 54, 'flower_pot');
pb(37, walkY, 46, 'lectern[facing=west]');
pb(38, walkY, 50, 'barrel'); pb(38, walkY, 51, 'chest[facing=west]');
pb(32, f2Y - 1, 48, 'chain[axis=y]'); pb(32, f2Y - 2, 48, 'lantern[hanging=true]');
pb(31, f2Y - 2, 48, 'lantern[hanging=true]'); pb(33, f2Y - 2, 48, 'lantern[hanging=true]');
for (var sc = 46; sc <= 52; sc += 3) {
pb(mx1 + 1, walkY + 3, sc, 'stone_brick_wall'); pb(mx1 + 1, walkY + 2, sc, 'lantern[hanging=true]');
}
// === INTERIOR: LIBRARY (z37..z43) ===
try { shelfWall(mx1 + 1, walkY, 38, 'north', 2, 3); } catch (e2) { }
for (var lz = 38; lz <= 43; lz++) { pb(mx1 + 1, walkY, lz, 'bookshelf'); pb(mx1 + 1, walkY + 1, lz, 'bookshelf'); pb(mx1 + 1, walkY + 2, lz, 'bookshelf'); }
for (var lx = 26; lx <= 38; lx++) { pb(lx, walkY, mz1 + 1, 'bookshelf'); pb(lx, walkY + 1, mz1 + 1, 'bookshelf'); }
for (var lx2 = 34; lx2 <= 38; lx2++) { pb(lx2, walkY, 43, 'bookshelf'); pb(lx2, walkY + 1, 43, 'bookshelf'); }
rug(29, walkY, 39, 6, 4, 'green', 'lime');
pb(31, walkY, 40, 'lectern[facing=south]');
chairStair(31, walkY, 41, 'dark_oak_stairs', 'north');
chairStair(29, walkY, 41, 'spruce_stairs', 'east');
chairStair(33, walkY, 41, 'spruce_stairs', 'west');
pb(31, walkY, 42, 'dark_oak_fence'); pb(31, walkY + 1, 42, 'dark_oak_pressure_plate');
pb(31, f2Y - 1, 40, 'chain[axis=y]'); pb(31, f2Y - 2, 40, 'lantern[hanging=true]');
pb(36, f2Y - 1, 40, 'chain[axis=y]'); pb(36, f2Y - 2, 40, 'lantern[hanging=true]');
pb(37, walkY, 38, 'cartography_table');
// === INTERIOR: STUDY / MAP ROOM (floor 2) ===
rug(29, walkY2, 46, 7, 6, 'light_blue', 'white');
fill(30, walkY2, 40, 33, walkY2, 40, 'dark_oak_fence');
fill(30, walkY2 + 1, 40, 33, walkY2 + 1, 40, 'dark_oak_pressure_plate');
chairStair(31, walkY2, 41, 'dark_oak_stairs', 'north');
chairStair(32, walkY2, 39, 'dark_oak_stairs', 'south');
for (var sx = 26; sx <= 36; sx++) { pb(sx, walkY2, mz1 + 1, 'bookshelf'); pb(sx, walkY2 + 1, mz1 + 1, 'bookshelf'); }
pb(37, walkY2, 42, 'cartography_table'); pb(38, walkY2, 42, 'lectern[facing=west]');
pb(38, walkY2, 46, 'barrel'); pb(38, walkY2, 47, 'chest[facing=west]');
pb(30, walkY2, 55, 'flower_pot');
chairStair(31, walkY2, 55, 'spruce_stairs', 'south'); chairStair(33, walkY2, 55, 'spruce_stairs', 'south');
for (var sc2 = 40; sc2 <= 52; sc2 += 6) { pb(sc2 === 40 ? 31 : 32, topY - 1, sc2, 'chain[axis=y]'); pb(sc2 === 40 ? 31 : 32, topY - 2, sc2, 'lantern[hanging=true]'); }
pb(35, walkY2, 50, 'end_rod[facing=up]');
// === INTERIOR: ROTUNDA (drum ground) ===
rug(dcx - 2, walkY, dcz - 2, 5, 5, 'blue', 'light_blue');
fill(dcx - 1, walkY, dcz - 1, dcx + 1, walkY, dcz + 1, 'polished_andesite');
pb(dcx, walkY + 1, dcz, 'chiseled_stone_bricks');
pb(dcx, walkY + 2, dcz, 'gold_block');
pb(dcx - 1, walkY + 2, dcz, 'copper_block'); pb(dcx + 1, walkY + 2, dcz, 'copper_block');
pb(dcx, walkY + 2, dcz - 1, 'copper_block'); pb(dcx, walkY + 2, dcz + 1, 'copper_block');
pb(dcx, walkY + 3, dcz, 'end_rod[facing=up]');
chairStair(dcx - 4, walkY, dcz + 3, 'dark_oak_stairs', 'north');
chairStair(dcx - 3, walkY, dcz + 3, 'dark_oak_stairs', 'north');
chairStair(dcx + 4, walkY, dcz - 3, 'dark_oak_stairs', 'south');
pb(dcx + 4, walkY, dcz + 3, 'barrel');
pb(dcx - 5, walkY, dcz - 2, 'lectern[facing=east]');
pb(dcx + 3, walkY, dcz + 4, 'bookshelf'); pb(dcx + 3, walkY + 1, dcz + 4, 'bookshelf');
// === INTERIOR: TELESCOPE FLOOR (walkY18, brass telescope pointing through the slit) ===
fill(dcx - 2, walkY2, dcz - 2, dcx - 2, walkY2 + 2, dcz - 2, 'polished_andesite');
fill(dcx + 2, walkY2, dcz - 2, dcx + 2, walkY2 + 2, dcz - 2, 'polished_andesite');
fill(dcx - 2, walkY2 + 2, dcz - 2, dcx + 2, walkY2 + 2, dcz - 2, 'polished_andesite');
fill(dcx - 3, walkY2, dcz - 3, dcx + 3, walkY2, dcz - 3, 'polished_andesite_slab[type=bottom]');
for (var tt = 0; tt <= 16; tt++) {
var ty = walkY2 + 2 + tt;
var tz = dcz - 2 + Math.round(tt * 6 / 16);
pb(dcx, ty, tz, tt % 4 === 0 ? 'gold_block' : 'copper_block');
if (tt === 16) { pb(dcx - 1, ty, tz, 'copper_block'); pb(dcx + 1, ty, tz, 'copper_block'); pb(dcx, ty + 1, tz, 'glass'); }
}
pb(dcx - 4, walkY2, dcz + 2, 'chest[facing=east]');
pb(dcx - 5, walkY2, dcz + 1, 'barrel');
pb(dcx + 4, walkY2, dcz + 2, 'lectern[facing=west]');
chairStair(dcx + 4, walkY2, dcz + 4, 'dark_oak_stairs', 'north');
pb(dcx - 4, walkY2, dcz - 3, 'bookshelf'); pb(dcx - 4, walkY2 + 1, dcz - 3, 'bookshelf');
pb(dcx + 2, walkY2, dcz + 5, 'cartography_table');
rug(dcx + 1, walkY2, dcz + 3, 3, 3, 'red', 'orange');
var lampA = [45, 135, 225, 315];
for (var li = 0; li < lampA.length; li++) {
var la2 = lampA[li] * Math.PI / 180;
var lx = dcx + Math.round((DR - 1.5) * Math.cos(la2));
var lz = dcz + Math.round((DR - 1.5) * Math.sin(la2));
pb(lx, walkY + 4, lz, 'stone_brick_wall'); pb(lx, walkY + 3, lz, 'lantern[hanging=true]');
pb(lx, walkY2 + 5, lz, 'stone_brick_wall'); pb(lx, walkY2 + 4, lz, 'lantern[hanging=true]');
}
// === WRAP PORCH (Victorian) + EXTERIOR ===
fill(26, floorY, bz2 + 2, 38, floorY, bz2 + 4, 'spruce_slab[type=top]');
fill(26, floorY, bz1, 27, floorY, bz2 + 4, 'spruce_slab[type=top]');
fill(37, floorY, bz1, 38, floorY, bz2 + 4, 'spruce_slab[type=top]');
var ppx = [26, 29, 32, 35, 38];
for (var qi = 0; qi < ppx.length; qi++) {
fill(ppx[qi], walkY, bz2 + 4, ppx[qi], walkY + 3, bz2 + 4, 'stripped_birch_log[axis=y]');
pb(ppx[qi], walkY + 3, bz2 + 3, 'spruce_fence');
}
fill(26, walkY + 4, bz2 + 2, 38, walkY + 4, bz2 + 4, 'spruce_planks');
for (var pr = 0; pr < 2; pr++) {
for (var pxx = 26; pxx <= 38; pxx++) roofStair(pxx, walkY + 5 + pr, bz2 + 4 - pr, roofMat(pxx, 0, bz2 + 4 - pr), 'south');
}
fill(26, walkY + 7, bz2 + 2, 38, walkY + 7, bz2 + 2, 'polished_deepslate');
pb(26, walkY + 3, bz2 + 4, 'lantern'); pb(38, walkY + 3, bz2 + 4, 'lantern');
// porch steps down to the path
fill(31, floorY, bz2 + 5, 33, floorY, bz2 + 5, 'stone_brick_slab[type=bottom]');
// path
for (var pz2 = 63; pz2 <= 74; pz2++) {
var wob = Math.round(Math.sin(pz2 * 0.35) * 1.5);
for (var pxi = -1; pxi <= 1; pxi++) {
var pxv = 32 + wob + pxi;
pb(pxv, padY, pz2, ((pxv * 11 + pz2 * 5) % 4 === 0) ? 'cobblestone' : 'gravel');
}
}
try { lampPost(28, floorY, 65, 4, 'cobblestone_wall'); lampPost(37, floorY, 69, 4, 'cobblestone_wall'); }
catch (e3) {
fill(28, floorY, 65, 28, floorY + 3, 65, 'cobblestone_wall'); pb(28, floorY + 4, 65, 'lantern');
fill(37, floorY, 69, 37, floorY + 3, 69, 'cobblestone_wall'); pb(37, floorY + 4, 69, 'lantern');
}
for (var gwz = 63; gwz <= 73; gwz++) { pb(24, padY + 1, gwz, 'cobblestone_wall'); pb(42, padY + 1, gwz, 'cobblestone_wall'); }
for (var gwx = 24; gwx <= 42; gwx++) pb(gwx, padY + 1, 73, 'cobblestone_wall');
pb(32, padY + 1, 73, 'air'); pb(33, padY + 1, 73, 'air');
function tree(tx, tz, hgt, logId, leafId) {
var i3; for (i3 = 0; i3 < hgt; i3++) pb(tx, padY + 1 + i3, tz, logId);
makeSphere(tx, padY + hgt, tz, leafId, 3, false);
makeSphere(tx, padY + hgt + 2, tz, leafId, 2, false);
}
tree(17, 60, 6, 'oak_log[axis=y]', 'oak_leaves[persistent=true]');
tree(60, 62, 5, 'birch_log[axis=y]', 'birch_leaves[persistent=true]');
tree(14, 33, 6, 'spruce_log[axis=y]', 'spruce_leaves[persistent=true]');
tree(62, 32, 5, 'oak_log[axis=y]', 'oak_leaves[persistent=true]');
tree(50, 66, 6, 'spruce_log[axis=y]', 'spruce_leaves[persistent=true]');
for (var fx2 = 8; fx2 <= 70; fx2++) {
for (var fz2 = 20; fz2 <= 74; fz2++) {
var hsh = (fx2 * 61 + fz2 * 137) % 43;
if (hsh > 4) continue;
if (fx2 >= 22 && fx2 <= 58 && fz2 >= 33 && fz2 <= 60) continue;
var fbl = (hsh === 0) ? 'poppy' : (hsh === 1 ? 'oxeye_daisy' : (hsh === 2 ? 'cornflower' : (hsh === 3 ? 'short_grass' : 'azure_bluet')));
pb(fx2, padY + 1, fz2, fbl);
}
}
// meridian marker stone in the lawn
fill(54, padY + 1, 60, 55, padY + 3, 61, 'chiseled_stone_bricks');
pb(54, padY + 4, 60, 'polished_diorite_slab[type=bottom]');
pb(55, padY + 4, 61, 'end_rod[facing=up]');