// === BUILD PLAN ===
// Style: Norwegian stave church (rustic dark tarred timber)
// Footprint: composite cross — nave 13x17 (x-6..6, z-8..8) + chancel 9x6 (z8..13)
// + porch 7x6 (z-13..-8) + svalgang deck ring (x-9..9) + lantern tower over nave
// Height: floorY3 / walls to Y11 / nave gable base Y12 -> ridge Y18 / tower Y12-20,
// tower gable base Y21 -> ridge Y24 / mast to Y27
//
// GROUND FLOOR (top-down, 1 char = 1 block, Z increases downward):
// ....#####PPP#####.... P porch (entrance z=-13)
// ..oo#############oo.. o svalgang posts (x=+-9)
// ..o # gallery over # o.. G gallery over the north bay (Y8, stair at x=-4)
// ..o # B B | B B # o.. B benches, | red carpet aisle x=0
// ..o # B B | B B # o..
// ..oo##### A #####oo.. A chancel arch (z=8)
// .......## D ##....... D raised chancel dais + altar
//
// FRONT ELEVATION (north):
// /^\ dragon-head finial + mast
// /TTT\ shingled lantern tower (Y21-24)
// /=========\ nave gable, dark_oak shingles (Y12-18)
// /=============\
// |staves+window| clerestory round windows Y9
// __| |__ svalgang lean-to (Y8->Y6), posts + rail
// |o o o o o o o o o o|
// =====rocky knoll=====
//
// MATERIALS PLAN:
// base : gradientPalette cobble->mossy->andesite Y4..Y6 — WHY: wet stone sill grounds the timber
// walls : noisePalette dark_oak_planks55/spruce30/dark_oak_log15 — WHY: tarred stave board variation
// staves : dark_oak_log[axis=y] pilasters PROTRUDING at x=+-7 every 3 — WHY: real facade relief
// roofs : dark_oak_stairs (nave, big dark mass) vs spruce_stairs (porch/chancel/tower/svalgang)
// — WHY: tier CONTRAST reads the stacked silhouette
// accents: brown_stained_glass round windows, lanterns, red carpet, banners
// Rooms: Nave (pews, aisle, chandelier, wall lanterns), Chancel (dais, altar, lectern, banners),
// Gallery Y8 (benches, lantern, rail), Porch (bench, lanterns)
// STAIR PLAN: nave walk Y4 -> gallery walk Y9 (D=5) -> staircase(-4,-2,4,9,"north"), 6 cells z-2..-7
// === END PLAN ===
var padY = 2;
var floorY = 3;
var walkY = floorY + 1; // 4
var wallTopY = 11;
var naveRoofY = 12;
var towerBaseY = 12;
var towerTopY = 20;
var wallMat = noisePalette([
{ block: 'dark_oak_planks', weight: 55 },
{ block: 'spruce_planks', weight: 30 },
{ block: 'dark_oak_log', weight: 15 }
], { seed: 7, freq: 0.16 });
var deckMat = noisePalette([
{ block: 'spruce_planks', weight: 60 },
{ block: 'dark_oak_planks', weight: 25 },
{ block: 'stripped_spruce_log', weight: 15 }
], { seed: 13, freq: 0.2 });
var stoneMat = gradientPalette(floorY, floorY + 3, [
{ block: 'mossy_cobblestone', from: 0 },
{ block: 'cobblestone', from: 0.45 },
{ block: 'andesite', from: 0.8 }
], { noise: 0.25, seed: 3 });
function ringWalls(x1, z1, x2, z2, y1, y2, 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 ===
var ground = null;
try {
ground = terrain({
cx: 0, cz: 0, radius: 34, baseY: -2, amp: 5, scale: 0.05, seed: 29, irregularity: 0.38,
surface: [
{ block: 'grass_block', w: 5 },
{ block: 'coarse_dirt', w: 2 },
{ block: 'stone', w: 2 },
{ block: 'moss_block', w: 1 }
],
sub: 'dirt', deep: 'stone', depth: 4,
pads: [{ cx: 0, cz: 0, r: 19, y: padY, falloff: 10 }]
});
} catch (terrErr) {
fill(-20, padY - 3, -20, 20, padY, 20, 'stone');
fill(-20, padY, -20, 20, padY, 20, 'grass_block');
}
// clear the building envelope so no ground intrudes
fill(-12, floorY, -18, 12, 30, 18, 'air');
// === STRUCTURE ===
// deck / svalgang platform + church floor slab
fill(-9, floorY, -8, 9, floorY, 8, deckMat);
fill(-5, floorY, -14, 5, floorY, 14, deckMat);
fill(-5, floorY, -7, 5, floorY, 7, 'dark_oak_planks');
// nave walls
ringWalls(-6, -8, 6, 8, floorY + 1, wallTopY, wallMat);
// stone sill band
ringWalls(-6, -8, 6, 8, floorY + 1, floorY + 3, stoneMat);
// chancel
ringWalls(-4, 8, 4, 13, floorY + 1, 9, wallMat);
ringWalls(-4, 8, 4, 13, floorY + 1, floorY + 3, stoneMat);
fill(-3, floorY, 9, 3, floorY, 12, 'dark_oak_planks');
// porch
ringWalls(-3, -13, 3, -8, floorY + 1, 8, wallMat);
ringWalls(-3, -13, 3, -8, floorY + 1, floorY + 3, stoneMat);
fill(-2, floorY, -12, 2, floorY, -9, 'dark_oak_planks');
// openings: outer door, porch->nave, nave->chancel arch
fill(-1, walkY, -13, 1, walkY + 2, -13, 'air');
fill(-1, walkY, -8, 1, walkY + 2, -8, 'air');
fill(-2, walkY, 8, 2, walkY + 3, 8, 'air');
ps(0, walkY, -13, 'dark_oak_door[facing=north,half=lower,hinge=left]');
ps(0, walkY + 1, -13, 'dark_oak_door[facing=north,half=upper,hinge=left]');
// protruding stave pilasters + corner posts (facade depth)
var pz;
for (pz = -8; pz <= 8; pz += 3) {
fill(-7, floorY + 1, pz, -7, wallTopY, pz, 'dark_oak_log[axis=y]');
fill(7, floorY + 1, pz, 7, wallTopY, pz, 'dark_oak_log[axis=y]');
}
fill(-6, floorY + 1, -8, -6, wallTopY, -8, 'dark_oak_log[axis=y]');
fill(6, floorY + 1, -8, 6, wallTopY, -8, 'dark_oak_log[axis=y]');
fill(-6, floorY + 1, 8, -6, wallTopY, 8, 'dark_oak_log[axis=y]');
fill(6, floorY + 1, 8, 6, wallTopY, 8, 'dark_oak_log[axis=y]');
// cornice ring (upside-down stairs) at wall top
var cx2, cz2;
for (cx2 = -6; cx2 <= 6; cx2++) {
roofStair(cx2, wallTopY, -9, 'dark_oak_stairs', 'north', 'top');
roofStair(cx2, wallTopY, 9, 'dark_oak_stairs', 'south', 'top');
}
for (cz2 = -8; cz2 <= 8; cz2++) {
roofStair(-7, wallTopY, cz2, 'dark_oak_stairs', 'west', 'top');
roofStair(7, wallTopY, cz2, 'dark_oak_stairs', 'east', 'top');
}
// === ROOF ===
placeGableRoof(-6, 6, -8, 8, naveRoofY, 'dark_oak_stairs', 'dark_oak_slab', wallMat);
placeGableRoof(-4, 4, 8, 13, 10, 'spruce_stairs', 'spruce_slab', wallMat);
placeGableRoof(-3, 3, -13, -8, 9, 'spruce_stairs', 'spruce_slab', wallMat);
// lantern tower over the nave (built AFTER the nave roof so it overwrites it)
ringWalls(-3, -3, 3, 3, towerBaseY, towerTopY, wallMat);
fill(-2, towerBaseY, -2, 2, towerTopY, 2, 'air');
// belfry louvers on all four faces
var lv;
for (lv = -1; lv <= 1; lv++) {
fill(lv, towerTopY - 4, -3, lv, towerTopY - 1, -3, 'dark_oak_fence');
fill(lv, towerTopY - 4, 3, lv, towerTopY - 1, 3, 'dark_oak_fence');
fill(-3, towerTopY - 4, lv, -3, towerTopY - 1, lv, 'dark_oak_fence');
fill(3, towerTopY - 4, lv, 3, towerTopY - 1, lv, 'dark_oak_fence');
}
placeGableRoof(-3, 3, -3, 3, towerTopY + 1, 'spruce_stairs', 'spruce_slab', wallMat);
// mast + weather finial
fill(0, towerTopY + 5, 0, 0, towerTopY + 7, 0, 'dark_oak_fence');
pb(0, towerTopY + 8, 0, 'lantern');
// dragon-head finials at the four ridge ends
function finial(fx, fy, fz, face) {
pb(fx, fy, fz, 'dark_oak_fence');
ps(fx, fy + 1, fz, 'dark_oak_stairs[facing=' + face + ',half=top]');
ps(fx, fy + 1, fz + (face === 'north' ? -1 : (face === 'south' ? 1 : 0)), 'dark_oak_trapdoor[facing=' + face + ',half=top,open=false]');
}
finial(0, 19, -9, 'north');
finial(0, 19, 9, 'south');
finial(0, 15, 14, 'south');
finial(0, 13, -14, 'north');
// === SVALGANG (arcaded covered walkway) ===
var sz;
for (sz = -8; sz <= 8; sz++) {
// lean-to shingles west & east
roofStair(-7, 8, sz, 'spruce_stairs', 'west');
roofStair(-8, 7, sz, 'spruce_stairs', 'west');
roofStair(-9, 6, sz, 'spruce_stairs', 'west');
roofStair(7, 8, sz, 'spruce_stairs', 'east');
roofStair(8, 7, sz, 'spruce_stairs', 'east');
roofStair(9, 6, sz, 'spruce_stairs', 'east');
if (sz % 2 === 0) {
fill(-9, walkY, sz, -9, 5, sz, 'dark_oak_log[axis=y]');
fill(9, walkY, sz, 9, 5, sz, 'dark_oak_log[axis=y]');
} else {
pb(-9, walkY + 1, sz, 'dark_oak_fence');
pb(9, walkY + 1, sz, 'dark_oak_fence');
}
}
// re-place the pilasters that the lean-to overwrote at Y8
for (pz = -8; pz <= 8; pz += 3) {
fill(-7, floorY + 1, pz, -7, wallTopY, pz, 'dark_oak_log[axis=y]');
fill(7, floorY + 1, pz, 7, wallTopY, pz, 'dark_oak_log[axis=y]');
}
// === WINDOWS === small round clerestory windows above the svalgang roof
var wz;
for (wz = -6; wz <= 6; wz += 3) {
ps(-6, 9, wz, 'brown_stained_glass');
ps(6, 9, wz, 'brown_stained_glass');
ps(-6, 10, wz, 'dark_oak_trapdoor[facing=west,half=top,open=false]');
ps(6, 10, wz, 'dark_oak_trapdoor[facing=east,half=top,open=false]');
}
ps(-3, 7, 13, 'brown_stained_glass');
ps(3, 7, 13, 'brown_stained_glass');
ps(0, 8, 13, 'brown_stained_glass');
// === INTERIOR: GALLERY + STAIR ===
fill(-5, 8, -7, 5, 8, -5, 'spruce_planks');
var gx;
for (gx = -5; gx <= 5; gx++) {
pb(gx, 9, -4, 'dark_oak_fence');
}
staircase(-4, -2, walkY, 9, 'north', { width: 1, material: 'dark_oak_stairs', rail: true, support: 'dark_oak_planks' });
var gb;
for (gb = -2; gb <= 2; gb++) {
chairStair(gb, 9, -6, 'spruce_stairs', 'south');
}
pb(4, 9, -6, 'dark_oak_fence');
pb(4, 10, -6, 'lantern');
// === INTERIOR: NAVE ===
var rz, bx;
for (rz = -7; rz <= 7; rz++) {
pb(0, walkY, rz, 'red_carpet');
}
for (rz = -5; rz <= 5; rz += 2) {
for (bx = 2; bx <= 3; bx++) {
chairStair(-bx, walkY, rz, 'spruce_stairs', 'south');
chairStair(bx, walkY, rz, 'spruce_stairs', 'south');
}
}
// wall lanterns on fence brackets
var lz;
for (lz = -5; lz <= 5; lz += 4) {
pb(-5, walkY + 3, lz, 'dark_oak_fence');
pb(-5, walkY + 4, lz, 'lantern');
pb(5, walkY + 3, lz, 'dark_oak_fence');
pb(5, walkY + 4, lz, 'lantern');
}
// chandelier hanging from the tower ridge into the nave
var chY;
for (chY = towerBaseY; chY <= towerTopY + 3; chY++) {
pb(0, chY, 0, 'chain[axis=y]');
}
ps(0, wallTopY, 0, 'lantern[hanging=true]');
// === INTERIOR: CHANCEL ===
fill(-3, walkY, 10, 3, walkY, 12, 'polished_andesite');
var stx;
for (stx = -2; stx <= 2; stx++) {
climbStair(stx, walkY, 9, 'dark_oak_stairs', 'south');
}
fill(-1, walkY + 1, 12, 1, walkY + 1, 12, 'chiseled_stone_bricks');
pb(0, walkY + 2, 12, 'lantern');
ps(-2, walkY + 1, 11, 'lectern[facing=east]');
ps(-4, walkY + 4, 11, 'red_wall_banner[facing=east]');
ps(4, walkY + 4, 11, 'red_wall_banner[facing=west]');
pb(-3, walkY + 1, 10, 'dark_oak_fence');
pb(-3, walkY + 2, 10, 'lantern');
pb(3, walkY + 1, 10, 'dark_oak_fence');
pb(3, walkY + 2, 10, 'lantern');
// === INTERIOR: PORCH ===
chairStair(-2, walkY, -11, 'spruce_stairs', 'east');
chairStair(2, walkY, -11, 'spruce_stairs', 'west');
pb(-2, walkY + 3, -9, 'dark_oak_fence');
pb(-2, walkY + 4, -9, 'lantern');
pb(2, walkY + 3, -9, 'dark_oak_fence');
pb(2, walkY + 4, -9, 'lantern');
// === DETAIL: LANDSCAPING ===
// path from the porch down the knoll
var pathZ, gy, pxx;
for (pathZ = -15; pathZ >= -26; pathZ--) {
gy = padY;
if (ground) { gy = Math.round(ground(0, pathZ)); }
for (pxx = -1; pxx <= 1; pxx++) {
pb(pxx, gy, pathZ, (pathZ % 3 === 0) ? 'cobblestone' : 'gravel');
}
}
// churchyard: stone grave markers + low wall posts
var graves = [[-13, -4], [-14, 2], [-13, 7], [13, -3], [14, 3], [12, 8]];
var gi, gxx, gzz, ggy;
for (gi = 0; gi < graves.length; gi++) {
gxx = graves[gi][0]; gzz = graves[gi][1];
ggy = padY;
if (ground) { ggy = Math.round(ground(gxx, gzz)); }
pb(gxx, ggy + 1, gzz, 'cobblestone_wall');
ps(gxx, ggy + 2, gzz, 'stone_brick_slab[type=bottom]');
pb(gxx + 1, ggy + 1, gzz, 'moss_block');
}
// trees + shrubs on the knoll
var trees = [[-19, -12], [17, -14], [-21, 9], [18, 12], [-16, 17]];
var ti, txx, tzz, tyy;
for (ti = 0; ti < trees.length; ti++) {
txx = trees[ti][0]; tzz = trees[ti][1];
tyy = padY;
if (ground) { tyy = Math.round(ground(txx, tzz)); }
try {
placeTree(txx, tyy + 1, tzz, 'spruce');
} catch (treeErr) {
fill(txx, tyy + 1, tzz, txx, tyy + 6, tzz, 'spruce_log[axis=y]');
makeSphere(txx, tyy + 6, tzz, 'spruce_leaves[persistent=true]', 3, true);
}
}
// outdoor lamps flanking the path
try {
lampPost(-3, padY + 1, -15, 'dark_oak_fence');
lampPost(3, padY + 1, -15, 'dark_oak_fence');
} catch (lampErr) {
fill(-3, padY + 1, -15, -3, padY + 3, -15, 'dark_oak_fence');
pb(-3, padY + 4, -15, 'lantern');
fill(3, padY + 1, -15, 3, padY + 3, -15, 'dark_oak_fence');
pb(3, padY + 4, -15, 'lantern');
}
// scattered flowers / grass on the pad edge
var fi2, fx2, fz2, fy2;
for (fi2 = 0; fi2 < 60; fi2++) {
fx2 = -24 + Math.floor(noise2d('perlin', fi2 * 7.3, 11.1) * 48);
fz2 = -24 + Math.floor(noise2d('perlin', 3.7, fi2 * 5.9) * 48);
if (Math.abs(fx2) < 11 && Math.abs(fz2) < 16) { continue; }
fy2 = padY;
if (ground) { fy2 = Math.round(ground(fx2, fz2)); }
pb(fx2, fy2 + 1, fz2, (fi2 % 4 === 0) ? 'poppy' : ((fi2 % 4 === 1) ? 'oxeye_daisy' : 'short_grass'));
}