// === BUILD PLAN ===
// Style: 19th-century (Victorian) astronomical observatory, rendered stone + copper dome
// Footprint: COMPOSITE — round drum r=8 @ (24,40) + rectangular wing 21x13 (x33..53, z34..46) + south porch 5x3
// Height: drum wall Y9..Y29, dome Y30..Y38 (R=8). Wing walls Y9..Y21, slate gable roof Y22..Y28 (ridge along X)
//
// GROUND FLOOR (top-down, 1 char = 1 block, Z increases downward):
// ....######..... drum ring (r=8) = rotunda, stair up to telescope floor
// ..# #..#####################
// .# # #
// # ROTUNDA ==A== HALL | LIB# A = arched opening drum<->hall
// .# + stair # | # | = partition wall @ x=44 (door @ z=40)
// ..# #..#######D############# D = main door @ x=39 z=46
// ....######..... PORCH (x37..41, z47..49)
//
// FRONT (south) ELEVATION:
// ___
// / | \ <- copper dome R=8 with observing SLIT (x22..26, +Z side)
// | | |
// | drum | /\
// | W W | ___/ \___ <- slate gable, ridge along X @ Y28, 1-blk eave
// | W W | |W W W W|
// |_______| |W W##W W|
// ========= ====[D]=====
//
// MATERIALS PLAN (what / where / WHY):
// drum : gradientPalette Y9->Y29 cobblestone -> stone_bricks -> smooth_stone -> polished_diorite, noise .22
// WHY: patina-by-height on a big CURVED surface; dark low = fake AO, light high = the drum reads round & tall
// dome : noisePalette oxidized/weathered/exposed/copper_block — WHY: verdigris blotches, not one flat green
// wing : gradientPalette mossy_cobblestone -> stone_bricks -> andesite — WHY: same grey ramp, ties wing to drum
// frame : polished_andesite pilasters + deepslate_tile plinth — WHY: vertical rhythm = wall depth
// roof : noisePalette deepslate_tile/brick/cobbled STAIRS (palette fed into stair MATERIAL, facing preserved)
// + polished_deepslate SOLID ridge beam — WHY: slate variation; solid ridge = no ridge_gap
// glass : glass_pane arched windows (height tapers with angular distance -> arch head)
// Rooms: Rotunda (plinth+armillary, benches, lanterns, main stair), Entrance Hall (table, chairs, rug, coat pegs,
// lecterns, chandelier, stair to study), Library (bookshelf walls, lectern, reading chairs, rug),
// Study/map room (desks, shelves, charts), Telescope floor (brass telescope on yoke, chests, chairs)
// STAIR PLAN: hall walkY10 -> study walkY16 (D=6) staircase() north; rotunda walkY10 -> telescope walkY18 (D=8)
// staircase() north. Both via staircase() helper = navigable, headroom + floor hole guaranteed.
// === END PLAN ===
var cx = 24, cz = 40, R = 8;
var padY = 8;
var floorY = 9, walkY = 10; // ground floor
var wingF2Y = 15, walkY2w = 16; // wing second floor
var wingTopY = 21; // wing wall top / ceiling
var roofBaseY = 22, ridgeY = 28;
var teleFloorY = 17, walkYt = 18; // telescope floor inside drum
var drumTopY = 29, domeBaseY = 30;
var wx1 = 33, wx2 = 53, wz1 = 34, wz2 = 46;
// ---------- palettes ----------
var drumMat = gradientPalette(floorY, drumTopY, [
{ block: 'cobblestone', from: 0 },
{ block: 'stone_bricks', from: 0.22 },
{ block: 'smooth_stone', from: 0.58 },
{ block: 'polished_diorite', from: 0.86 }
], { noise: 0.22, seed: 5 });
var wingMat = gradientPalette(floorY, wingTopY, [
{ block: 'mossy_cobblestone', from: 0 },
{ block: 'stone_bricks', from: 0.28 },
{ block: 'andesite', from: 0.7 },
{ block: 'polished_andesite', from: 0.92 }
], { noise: 0.2, seed: 8 });
var domeMat = noisePalette([
{ block: 'oxidized_copper', weight: 45 },
{ block: 'weathered_copper', weight: 30 },
{ block: 'exposed_copper', weight: 15 },
{ block: 'copper_block', weight: 10 }
], { seed: 11, freq: 0.09 });
var roofMat = noisePalette([
{ block: 'deepslate_tile_stairs', weight: 50 },
{ block: 'deepslate_brick_stairs', weight: 30 },
{ block: 'cobbled_deepslate_stairs', weight: 20 }
], { seed: 3, freq: 0.11 });
var floorMat = noisePalette([
{ block: 'polished_andesite', weight: 45 },
{ block: 'polished_diorite', weight: 30 },
{ block: 'smooth_stone', weight: 25 }
], { seed: 21, freq: 0.13 });
var woodFloorMat = noisePalette([
{ block: 'dark_oak_planks', weight: 55 },
{ block: 'spruce_planks', weight: 45 }
], { seed: 31, freq: 0.15 });
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 === (superpowers: blob + hills + flatten pad, flatten's return fed to surface)
var land = blob(40, 40, 36, { irregularity: 0.35, seed: 9 });
var hilly = hills({ base: 4, amp: 5, scale: 0.033, seed: 4 });
var padFn = flatten(hilly, { cx: 33, cz: 42, r: 25 }, padY, 9);
var groundMat = patches(['grass_block', 'grass_block', 'coarse_dirt'], 0.055, 3);
surface(land, padFn, groundMat, { sub: 'dirt', deep: 'stone', depth: 4 });
// insurance: no ground may intrude into the built volume
fill(14, floorY, 30, 56, 40, 52, 'air');
// === DRUM (round tower) ===
// plinth (protruding base course) + ring wall with pilasters, arched windows, cornice
for (var yy = floorY; yy <= drumTopY; yy++) {
var isPlinth = (yy <= floorY + 2);
var rOut = isPlinth ? R + 1 : R;
for (var dx = -R - 2; dx <= R + 2; dx++) {
for (var dz = -R - 2; dz <= R + 2; dz++) {
var d = Math.sqrt(dx * dx + dz * dz);
if (d > rOut + 0.5 || d <= rOut - 0.95) continue;
var bx = cx + dx, bz = cz + dz;
var ang = Math.atan2(dz, dx) * 180 / Math.PI;
if (ang < 0) ang += 360;
// window test: arched heads (taller at the centre of the arc)
var isWin = false;
var targets = [90, 135, 180, 225, 270];
for (var ti = 0; ti < targets.length; ti++) {
var da = Math.abs(ang - targets[ti]);
if (da > 180) da = 360 - da;
var mh = -1;
if (da <= 4) mh = 4; else if (da <= 7) mh = 3; else if (da <= 10) mh = 2;
if (mh < 0) continue;
if (yy >= 12 && yy <= 12 + mh) isWin = true;
if (yy >= 20 && yy <= 20 + mh) isWin = true;
}
if (isWin && !isPlinth) { pb(bx, yy, bz, 'glass_pane'); }
else { pb(bx, yy, bz, drumMat(bx, yy, bz)); }
}
}
}
// pilasters between the windows -> real wall depth on a curved surface
var pilA = [67.5, 112.5, 157.5, 202.5, 247.5, 292.5];
for (var pi = 0; pi < pilA.length; pi++) {
var a = pilA[pi] * Math.PI / 180;
for (var rr = R; rr <= R + 1; rr++) {
var px = cx + Math.round(rr * Math.cos(a));
var pz = cz + Math.round(rr * Math.sin(a));
fill(px, floorY, pz, px, drumTopY - 1, pz, 'polished_andesite');
ps(px, drumTopY, pz, 'stone_brick_stairs[facing=north,half=top]');
}
}
// cornice ring under the dome (2 courses at R+1) -> shadow line, kills the flat cylinder look
for (var cy = drumTopY - 1; cy <= drumTopY; cy++) {
for (var ax = -R - 2; ax <= R + 2; ax++) {
for (var az = -R - 2; az <= R + 2; az++) {
var dd = Math.sqrt(ax * ax + az * az);
if (dd > R + 1.5 || dd <= R + 0.05) continue;
pb(cx + ax, cy, cz + az, cy === drumTopY ? 'polished_diorite' : 'chiseled_stone_bricks');
}
}
}
// === COPPER DOME (layer table: outerR = round(sqrt(R^2-dy^2))) ===
for (var dy = 0; dy <= R; dy++) {
var oR = Math.round(Math.sqrt(R * R - dy * dy));
var iR = Math.round(Math.sqrt(Math.max(0, (R - 1.6) * (R - 1.6) - dy * dy)));
for (var mx = -oR; mx <= oR; mx++) {
for (var mz = -oR; mz <= oR; mz++) {
var d2 = mx * mx + mz * mz;
if (d2 <= oR * oR + oR && !(d2 <= iR * iR)) {
pb(cx + mx, domeBaseY + dy, cz + mz, domeMat(cx + mx, domeBaseY + dy, cz + mz));
}
}
}
}
// observing SLIT (open shutter) on the +Z side, over the apex
fill(cx - 2, domeBaseY + 1, cz - 1, cx + 2, domeBaseY + R, cz + R + 1, 'air');
// slit shutter rails
for (var sy = domeBaseY + 1; sy <= domeBaseY + R; sy++) {
var half = Math.round(Math.sqrt(Math.max(0, R * R - (sy - domeBaseY) * (sy - domeBaseY))));
if (half < 3) continue;
pb(cx - 3, sy, cz + Math.min(half, 5), 'copper_block');
pb(cx + 3, sy, cz + Math.min(half, 5), 'copper_block');
}
// === WING (two storeys) ===
fill(wx1, floorY, wz1, wx2, floorY, wz2, floorMat);
boxWalls(wx1, walkY, wz1, wx2, wingTopY, wz2, wingMat);
// plinth: protruding base ring
boxWalls(wx1 - 1, floorY, wz1 - 1, wx2 + 1, floorY + 2, wz2 + 1, 'deepslate_tiles');
// string course between floors + cornice at the top -> horizontal relief
boxWalls(wx1 - 1, wingF2Y, wz1 - 1, wx2 + 1, wingF2Y, wz2 + 1, 'polished_andesite_slab[type=top]');
boxWalls(wx1 - 1, wingTopY, wz1 - 1, wx2 + 1, wingTopY, wz2 + 1, 'polished_andesite');
// pilasters on the long walls
var pxs = [36, 40, 44, 48, 52];
for (var qi = 0; qi < pxs.length; qi++) {
fill(pxs[qi], walkY, wz2 + 1, pxs[qi], wingTopY - 1, wz2 + 1, 'polished_andesite');
fill(pxs[qi], walkY, wz1 - 1, pxs[qi], wingTopY - 1, wz1 - 1, 'polished_andesite');
}
// clear interiors
fill(wx1 + 1, walkY, wz1 + 1, wx2 - 1, wingTopY - 1, wz2 - 1, 'air');
// second floor slab + ceiling
fill(wx1 + 1, wingF2Y, wz1 + 1, wx2 - 1, wingF2Y, wz2 - 1, woodFloorMat);
fill(wx1 + 1, wingTopY, wz1 + 1, wx2 - 1, wingTopY, wz2 - 1, 'spruce_planks');
// arched windows in the wing (recessed 1 block => wall depth)
function wingWindow(bx, bz, baseYw, wall) {
// wall: 's' south (z=wz2), 'n' north (z=wz1), 'e' east (x=wx2)
var h2 = 3;
var i2;
for (i2 = 0; i2 < h2; i2++) {
if (wall === 's') { pb(bx, baseYw + i2, wz2, 'glass_pane'); pb(bx - 1, baseYw + i2, wz2, 'polished_andesite'); pb(bx + 1, baseYw + i2, wz2, 'polished_andesite'); }
if (wall === 'n') { pb(bx, baseYw + i2, wz1, 'glass_pane'); pb(bx - 1, baseYw + i2, wz1, 'polished_andesite'); pb(bx + 1, baseYw + i2, wz1, 'polished_andesite'); }
if (wall === 'e') { pb(wx2, baseYw + i2, bz, 'glass_pane'); pb(wx2, baseYw + i2, bz - 1, 'polished_andesite'); pb(wx2, baseYw + i2, bz + 1, 'polished_andesite'); }
}
// arched head
if (wall === 's') { ps(bx, baseYw + h2, wz2, 'stone_brick_stairs[facing=south,half=top]'); }
if (wall === 'n') { ps(bx, baseYw + h2, wz1, 'stone_brick_stairs[facing=north,half=top]'); }
if (wall === 'e') { ps(wx2, baseYw + h2, bz, 'stone_brick_stairs[facing=east,half=top]'); }
}
var winXs = [36, 42, 46, 50];
for (var wi = 0; wi < winXs.length; wi++) {
wingWindow(winXs[wi], 0, walkY + 1, 's');
wingWindow(winXs[wi], 0, walkY2w + 1, 's');
wingWindow(winXs[wi], 0, walkY + 1, 'n');
wingWindow(winXs[wi], 0, walkY2w + 1, 'n');
}
var winZs = [37, 40, 43];
for (var wj = 0; wj < winZs.length; wj++) {
wingWindow(0, winZs[wj], walkY + 1, 'e');
wingWindow(0, winZs[wj], walkY2w + 1, 'e');
}
// === SLATE GABLE ROOF (ridge along X, slopes N/S) ===
var halfD = 7; // depth 13 -> ceil(13/2)
for (var rx = wx1; rx <= wx2 + 1; rx++) {
for (var st = 0; st < halfD; st++) {
roofStair(rx, roofBaseY + st, wz1 - 1 + st, roofMat(rx, 0, wz1 - 1 + st), 'north');
roofStair(rx, roofBaseY + st, wz2 + 1 - st, roofMat(rx, 0, wz2 + 1 - st), 'south');
}
pb(rx, ridgeY, cz, 'polished_deepslate'); // SOLID ridge beam -> never a ridge gap
}
// gable triangles (both ends) — the bit AI forgets
for (var gs = 0; gs < halfD; gs++) {
for (var gz = wz1 - 1 + gs; gz <= wz2 + 1 - gs; gz++) {
pb(wx1, roofBaseY + gs, gz, wingMat(wx1, wingTopY, gz));
pb(wx2, roofBaseY + gs, gz, wingMat(wx2, wingTopY, gz));
}
}
// chimney bump-out on the east gable
fill(51, walkY, wz2 + 1, 52, roofBaseY + 8, wz2 + 2, 'bricks');
fill(51, roofBaseY + 9, wz2 + 1, 52, roofBaseY + 9, wz2 + 2, 'brick_slab[type=bottom]');
pb(51, roofBaseY + 9, wz2 + 1, 'campfire[lit=true]');
// === OPENINGS ===
fill(31, walkY, 39, 34, walkY + 2, 41, 'air'); // grand arched drum <-> hall opening
ps(31, walkY + 3, 39, 'stone_brick_stairs[facing=east,half=top]');
ps(31, walkY + 3, 41, 'stone_brick_stairs[facing=east,half=top]');
fill(44, walkY, 39, 44, walkY + 1, 41, 'air'); // hall <-> library doorway
fill(39, walkY, wz2, 39, walkY + 1, wz2, 'air'); // main door hole
ps(39, walkY, wz2, 'oak_door[facing=south,half=lower,hinge=left]');
ps(39, walkY + 1, wz2, 'oak_door[facing=south,half=upper,hinge=left]');
ps(39, walkY + 2, wz2, 'stone_brick_stairs[facing=south,half=top]');
// partition wall between hall and library
fill(44, walkY, wz1 + 1, 44, wingF2Y - 1, wz2 - 1, 'stone_bricks');
fill(44, walkY, 39, 44, walkY + 1, 41, 'air');
// === DRUM INTERIOR: rotunda floor, telescope floor, stairs ===
for (var fx = -R; fx <= R; fx++) {
for (var fz = -R; fz <= R; fz++) {
var fd = Math.sqrt(fx * fx + fz * fz);
if (fd > R - 0.6) continue;
pb(cx + fx, floorY, cz + fz, (Math.abs(fx) + Math.abs(fz)) % 4 < 2 ? 'polished_andesite' : 'polished_diorite');
pb(cx + fx, teleFloorY, cz + fz, woodFloorMat(cx + fx, teleFloorY, cz + fz));
}
}
// main stair: rotunda walk10 -> telescope walk18
try {
staircase(21, 45, walkY, walkYt, 'north', { width: 2, material: 'polished_andesite_stairs', rail: 'oak_fence' });
} catch (e1) {
staircase(21, 45, walkY, walkYt, 'north');
}
// wing stair: hall walk10 -> study walk16
try {
staircase(36, 44, walkY, walkY2w, 'north', { width: 2, material: 'spruce_stairs', rail: 'oak_fence' });
} catch (e2) {
staircase(36, 44, walkY, walkY2w, 'north');
}
// === INTERIOR: ROTUNDA (ground, drum) ===
rug(cx - 2, walkY, cz - 2, 5, 5, 'blue', 'light_blue');
fill(cx - 1, walkY, cz - 1, cx + 1, walkY, cz + 1, 'polished_andesite'); // plinth
pb(cx, walkY + 1, cz, 'chiseled_stone_bricks');
pb(cx, walkY + 2, cz, 'gold_block'); // armillary sphere core
pb(cx - 1, walkY + 2, cz, 'gold_block'); pb(cx + 1, walkY + 2, cz, 'gold_block');
pb(cx, walkY + 2, cz - 1, 'gold_block'); pb(cx, walkY + 2, cz + 1, 'gold_block');
pb(cx, walkY + 3, cz, 'end_rod[facing=up]');
chairStair(cx - 4, walkY, cz + 3, 'dark_oak_stairs', 'north');
chairStair(cx - 3, walkY, cz + 3, 'dark_oak_stairs', 'north');
chairStair(cx + 3, walkY, cz - 3, 'dark_oak_stairs', 'south');
pb(cx + 4, walkY, cz + 3, 'barrel');
pb(cx - 5, walkY, cz - 3, 'lectern[facing=east]');
var lampA = [45, 135, 225, 315];
for (var li = 0; li < lampA.length; li++) {
var la = lampA[li] * Math.PI / 180;
var lx = cx + Math.round((R - 1.5) * Math.cos(la));
var lz = cz + Math.round((R - 1.5) * Math.sin(la));
pb(lx, walkY + 3, lz, 'stone_brick_wall');
pb(lx, walkY + 2, lz, 'lantern[hanging=true]');
pb(lx, walkYt + 4, lz, 'stone_brick_wall');
pb(lx, walkYt + 3, lz, 'lantern[hanging=true]');
}
// === INTERIOR: TELESCOPE FLOOR ===
// yoke + brass telescope pointing up through the slit (+Z)
fill(cx - 2, walkYt, cz - 2, cx + 2, walkYt, cz - 2, 'polished_andesite');
fill(cx - 2, walkYt, cz - 2, cx - 2, walkYt + 2, cz - 2, 'polished_andesite');
fill(cx + 2, walkYt, cz - 2, cx + 2, walkYt + 2, cz - 2, 'polished_andesite');
for (var tt = 0; tt <= 11; tt++) {
var ty = walkYt + 1 + tt;
var tz = cz - 2 + Math.round(tt * 7 / 11);
pb(cx, ty, tz, tt % 3 === 0 ? 'gold_block' : 'copper_block');
if (tt === 11) {
pb(cx - 1, ty, tz, 'copper_block'); pb(cx + 1, ty, tz, 'copper_block');
pb(cx, ty + 1, tz, 'glass');
}
if (tt === 0) { pb(cx, ty - 1, tz, 'chiseled_stone_bricks'); }
}
pb(cx - 4, walkYt, cz + 2, 'chest[facing=east]');
pb(cx - 5, walkYt, cz + 1, 'barrel');
pb(cx + 4, walkYt, cz + 2, 'lectern[facing=west]');
chairStair(cx + 4, walkYt, cz + 4, 'dark_oak_stairs', 'north');
pb(cx - 4, walkYt, cz - 3, 'bookshelf'); pb(cx - 4, walkYt + 1, cz - 3, 'bookshelf');
pb(cx - 5, walkYt, cz - 2, 'bookshelf');
rug(cx + 2, walkYt, cz + 3, 3, 3, 'red', 'orange');
// === INTERIOR: ENTRANCE HALL (x34..43, z35..45) ===
rug(37, walkY, 39, 5, 5, 'red', 'yellow');
pb(40, walkY, 41, 'dark_oak_fence'); pb(40, walkY + 1, 41, 'dark_oak_pressure_plate');
pb(41, walkY, 41, 'dark_oak_fence'); pb(41, walkY + 1, 41, 'dark_oak_pressure_plate');
chairStair(40, walkY, 40, 'dark_oak_stairs', 'south');
chairStair(41, walkY, 42, 'dark_oak_stairs', 'north');
pb(42, walkY, 36, 'lectern[facing=south]');
pb(34, walkY, 37, 'barrel'); pb(34, walkY, 38, 'chest[facing=east]');
pb(35, walkY, 36, 'flower_pot');
pb(43, walkY, 44, 'oak_fence'); pb(43, walkY + 1, 44, 'oak_pressure_plate');
pb(43, walkY + 2, 44, 'lantern');
// chandelier over the hall
pb(39, wingF2Y - 1, 40, 'chain[axis=y]');
pb(39, wingF2Y - 2, 40, 'lantern[hanging=true]');
pb(38, wingF2Y - 2, 40, 'lantern[hanging=true]');
pb(40, wingF2Y - 2, 40, 'lantern[hanging=true]');
// wall sconces
for (var sc = 37; sc <= 43; sc += 3) {
pb(sc, walkY + 3, wz1 + 1, 'stone_brick_wall');
pb(sc, walkY + 2, wz1 + 1, 'lantern[hanging=true]');
}
// === INTERIOR: LIBRARY (x45..52, z35..45) ===
try {
shelfWall(52, walkY, 36, 'south', 9, 3);
} catch (e3) {
for (var bz2 = 36; bz2 <= 44; bz2++) { pb(52, walkY, bz2, 'bookshelf'); pb(52, walkY + 1, bz2, 'bookshelf'); pb(52, walkY + 2, bz2, 'bookshelf'); }
}
for (var bx2 = 45; bx2 <= 51; bx2++) {
pb(bx2, walkY, 35, 'bookshelf'); pb(bx2, walkY + 1, 35, 'bookshelf');
}
for (var bx3 = 46; bx3 <= 50; bx3++) { pb(bx3, walkY, 45, 'bookshelf'); pb(bx3, walkY + 1, 45, 'bookshelf'); }
rug(46, walkY, 39, 5, 4, 'green', 'lime');
pb(48, walkY, 40, 'lectern[facing=south]');
chairStair(48, walkY, 41, 'dark_oak_stairs', 'north');
chairStair(46, walkY, 42, 'spruce_stairs', 'east');
chairStair(50, walkY, 42, 'spruce_stairs', 'west');
pb(48, walkY, 42, 'dark_oak_fence'); pb(48, walkY + 1, 42, 'dark_oak_pressure_plate');
pb(48, wingF2Y - 1, 40, 'chain[axis=y]'); pb(48, wingF2Y - 2, 40, 'lantern[hanging=true]');
pb(45, walkY + 2, 36, 'stone_brick_wall'); pb(45, walkY + 1, 36, 'lantern[hanging=true]');
// === INTERIOR: UPPER STUDY / MAP ROOM (whole wing floor 2) ===
rug(40, walkY2w, 39, 7, 5, 'light_blue', 'white');
for (var dx3 = 46; dx3 <= 51; dx3++) { pb(dx3, walkY2w, 35, 'bookshelf'); pb(dx3, walkY2w + 1, 35, 'bookshelf'); }
fill(41, walkY2w, 36, 43, walkY2w, 36, 'dark_oak_fence');
fill(41, walkY2w + 1, 36, 43, walkY2w + 1, 36, 'dark_oak_pressure_plate');
chairStair(42, walkY2w, 37, 'dark_oak_stairs', 'north');
pb(45, walkY2w, 43, 'cartography_table');
pb(46, walkY2w, 43, 'lectern[facing=south]');
chairStair(46, walkY2w, 44, 'dark_oak_stairs', 'north');
pb(50, walkY2w, 43, 'barrel'); pb(51, walkY2w, 43, 'chest[facing=west]');
pb(35, walkY2w, 36, 'bookshelf'); pb(35, walkY2w + 1, 36, 'bookshelf');
pb(35, walkY2w, 37, 'bookshelf');
for (var sc2 = 38; sc2 <= 50; sc2 += 6) {
pb(sc2, walkY2w + 4, 40, 'chain[axis=y]');
pb(sc2, walkY2w + 3, 40, 'lantern[hanging=true]');
}
pb(37, walkY2w, 43, 'flower_pot');
pb(38, walkY2w, 35, 'end_rod[facing=up]');
// === PORCH + EXTERIOR ===
fill(37, floorY, 47, 41, floorY, 49, 'polished_andesite');
fill(37, walkY, 49, 37, walkY + 3, 49, 'stripped_dark_oak_log[axis=y]');
fill(41, walkY, 49, 41, walkY + 3, 49, 'stripped_dark_oak_log[axis=y]');
fill(37, walkY + 4, 47, 41, walkY + 4, 49, 'dark_oak_planks');
for (var ps2 = 0; ps2 < 2; ps2++) {
for (var pxx = 37; pxx <= 41; pxx++) {
roofStair(pxx, walkY + 5 + ps2, 49 - ps2, roofMat(pxx, 0, 49 - ps2), 'south');
}
}
fill(37, walkY + 7, 47, 41, walkY + 7, 47, 'polished_deepslate');
pb(38, walkY + 3, 49, 'oak_fence'); pb(40, walkY + 3, 49, 'oak_fence');
pb(37, walkY + 3, 49, 'lantern[hanging=false]');
pb(41, walkY + 3, 49, 'lantern[hanging=false]');
// path to the door
for (var pz2 = 50; pz2 <= 62; pz2++) {
var wob = Math.round(Math.sin(pz2 * 0.4) * 1.2);
for (var pxi = -1; pxi <= 1; pxi++) {
var pxv = 39 + wob + pxi;
pb(pxv, padY, pz2, ((pxv * 7 + pz2 * 13) % 5 === 0) ? 'cobblestone' : 'gravel');
}
}
// lamp posts along the path
try { lampPost(36, floorY, 52, 4, 'cobblestone_wall'); lampPost(43, floorY, 55, 4, 'cobblestone_wall'); }
catch (e4) {
fill(36, floorY, 52, 36, floorY + 3, 52, 'cobblestone_wall'); pb(36, floorY + 4, 52, 'lantern');
fill(43, floorY, 55, 43, floorY + 3, 55, 'cobblestone_wall'); pb(43, floorY + 4, 55, 'lantern');
}
// low garden wall
for (var gwz = 50; gwz <= 60; gwz++) { pb(33, padY + 1, gwz, 'cobblestone_wall'); pb(48, padY + 1, gwz, 'cobblestone_wall'); }
for (var gwx = 33; gwx <= 48; gwx++) { pb(gwx, padY + 1, 60, 'cobblestone_wall'); }
pb(39, padY + 1, 60, 'air'); pb(40, padY + 1, 60, 'air');
// trees + shrubs (hand-composed clusters on the hill)
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(18, 55, 5, 'oak_log[axis=y]', 'oak_leaves[persistent=true]');
tree(13, 47, 6, 'spruce_log[axis=y]', 'spruce_leaves[persistent=true]');
tree(56, 55, 5, 'oak_log[axis=y]', 'oak_leaves[persistent=true]');
tree(60, 36, 6, 'birch_log[axis=y]', 'birch_leaves[persistent=true]');
tree(15, 28, 5, 'spruce_log[axis=y]', 'spruce_leaves[persistent=true]');
// flower / grass scatter on the lawn
for (var fx2 = 10; fx2 <= 66; fx2 += 1) {
for (var fz2 = 24; fz2 <= 66; fz2 += 1) {
var hsh = (fx2 * 73 + fz2 * 151) % 47;
if (hsh > 4) continue;
if (fx2 >= 30 && fx2 <= 56 && fz2 >= 30 && fz2 <= 50) continue;
var fbl = (hsh === 0) ? 'poppy' : (hsh === 1 ? 'dandelion' : (hsh === 2 ? 'cornflower' : (hsh === 3 ? 'short_grass' : 'oxeye_daisy')));
pb(fx2, padY + 1, fz2, fbl);
}
}
// stone sundial plinth in the garden
fill(45, padY + 1, 53, 46, padY + 2, 54, 'chiseled_stone_bricks');
pb(45, padY + 3, 53, 'polished_diorite_slab[type=bottom]');
pb(46, padY + 3, 54, 'polished_diorite_slab[type=bottom]');
pb(45, padY + 3, 54, 'end_rod[facing=up]');