← Back to Gallery

Loading 3D viewer…

Hilltop Astronomical Observatory (indexed)

by Jorge Barbero

Dimensions
80×64×80
Blocks
118,192
Compute Time
10.8s
Generation Time
4m 59s
Edits
1
Model
claude-opus-5
Created
August 31, 2026
observatoryvictoriandomeautoevalindexed
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

INDEXED arm: search_docs({action:"related"}) routed to Clean Dome/Cupola (drum+cap+crown, stacked shrinking cylinders, keep copper oxidation LOW), Victorian Style (cross gables, bay window, wrap porch, gingerbread trim), Round Arch Patterns, Flat Wall Syndrome (pilasters/buttress taper/window recesses/cornices/string courses).

Photos

Exterior
Exteriorexterior
Hall + bay window
Hall + bay windowinterior
Stair to the study
Stair to the studyinterior
Library
Libraryinterior
Telescope floor
Telescope floorinterior
CraftScript Source
// === 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]');

Static Renders

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