← Back to Gallery

Loading 3D viewer…

Hilltop Astronomical Observatory (guided)

by Jorge Barbero

Dimensions
80×56×80
Blocks
82,459
Compute Time
9.3s
Generation Time
7m 23s
Model
claude-opus-5
Created
August 31, 2026
observatoryvictoriandomeautoevalguided
Prompt

User Prompt

a 19th-century astronomical observatory on a grassy hill: a cylindrical rendered-stone drum topped by a hemispherical copper dome with an open observing slit and a brass telescope inside, tall arched windows, an attached two-storey stone wing with a slate roof housing a library and entrance hall, and a stair leading up from the hall to the telescope floor

Enhanced Prompt

GUIDED arm: prepare_build + search_docs(build-rules Essential, shape-techniques Dome Layer Tables + L-Shape staircase, interior-design Room-by-Room, worldedit-api Terrain/Palettes/Furniture). Composite plan (round drum + rectangular wing + porch), gradientPalette on the drum for patina-by-height, noisePalette slate stair roof with solid ridge beam, staircase() helper for both flights, terrain()/flatten() pad.

Photos

Exterior
Exteriorexterior
Entrance hall
Entrance hallinterior
Stair to the dome
Stair to the domeinterior
Telescope floor
Telescope floorinterior
Library
Libraryinterior
CraftScript Source
// === 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]');

Static Renders

Hilltop Astronomical Observatory (guided) isometric viewisometric
Hilltop Astronomical Observatory (guided) front viewfront
Hilltop Astronomical Observatory (guided) side viewside
Hilltop Astronomical Observatory (guided) back viewback
Hilltop Astronomical Observatory (guided) top viewtop