// === BUILD PLAN ===
// Style: Japanese gassho-zukuri minka + attached namako-kabe kura (storehouse)
// Footprint: COMPOSITE L — main block 27x19 (x14..40, z12..30, ridge along X)
// + kura wing 9x11 (x42..50, z16..26) with its own 45deg gable, one storey lower
// Height: walls Y14..18 | loft floor Y19 | eaves Y15 (z10 / z32, 2 proud of the walls)
// | RIDGE Y38 = rise 23 over half-span 11 => 2:1 => ~63deg gassho pitch
// | kura ridge Y23 -> meets the tall main gable plane (x41), which is drawn LAST so the
// junction is sealed by a solid wall (rule 21: raise the low side to the tall side)
//
// SECTION (Z, ridge along X): GROUND FLOOR (top-down, x ->, z v):
// /\ Y38 solid beam #############################
// / \ # STAIR | IRORI | BEDS |#===KURA===#
// /LOFT\ walk Y20 # well | hearth | cha D barrels #
// /=======\ Y19 # DOMA | tatami | shelf |# chests #
// | IRORI | walk Y14 #####D####################### hay/pots #
// Y15 __/ \__ Y15 ^ main door (south, under the low eave)
// Y12 snow pad
//
// MATERIALS PLAN:
// thatch : gradientPalette packed_mud(low) -> rooted_dirt -> hay_block(high)
// WHY: damp/dark at the eave, pale straw at the ridge = fakes shadow + describes volume
// stairs : bamboo_mosaic / bamboo / spruce per column, facing preserved via roofStair()
// snow : snow[layers=2..4] on every exposed tread + drifts on the north side
// walls : shikkui plaster white_terracotta/calcite/smooth_quartz + dark_oak post-and-beam,
// posts every 3 with knee braces proud of the wall (relief, not a flat box)
// kura : namako-kabe = checkerboard white_terracotta / polished_blackstone (the storehouse look)
// plinth : mossy_cobblestone -> cobblestone -> andesite gradient
// Rooms: DOMA+kitchen (furnace, smoker, cauldron, barrels, woodpile) | IRORI (sunken campfire,
// pot on a chain, zabuton, chabudai, tokonoma) | EAST ROOM (2 futons, chests, shelfWall,
// lectern) | KURA (barrels, chests, hay, pots, lantern) | LOFT (silkworm trays, hay, loom)
// STAIR PLAN: placeStairwell(16,15,walk14,upperFloor19,...) U-turn 5x5 with rails + landing
// === END PLAN ===
var padY = 12;
var floorY = padY + 1; // 13
var walkY = floorY + 1; // 14
var wallTopY = 18;
var loftFloorY = 19;
var loftWalkY = 20;
var mx1 = 14, mx2 = 40, mz1 = 12, mz2 = 30; // main block walls
var rx1 = mx1 - 1, rx2 = mx2 + 1; // roof x span (gable planes)
var ez1 = 10, ez2 = 32, czc = 21; // eave z / ridge z
var eaveY = 15, ridgeY = 38;
var kx1 = 42, kx2 = 50, kz1 = 16, kz2 = 26; // kura wing walls
function roofBottomZ(z) {
var s = Math.min(z - ez1, ez2 - z);
if (s < 0) return 0;
return eaveY + 2 * s;
}
function triLo(y) { return ez1 + (Math.floor((y - eaveY) / 2) + 1); }
function triHi(y) { return ez2 - (Math.floor((y - eaveY) / 2) + 1); }
var shikkui = noisePalette([{block:'white_terracotta',weight:50},{block:'calcite',weight:22},{block:'smooth_quartz',weight:18},{block:'diorite',weight:10}], {seed:41, freq:0.16});
var thatchG = gradientPalette(eaveY, ridgeY, [{block:'packed_mud',from:0},{block:'rooted_dirt',from:0.28},{block:'hay_block',from:0.52}], {noise:0.28, seed:14});
var rockMix = noisePalette([{block:'cobblestone',weight:35},{block:'mossy_cobblestone',weight:25},{block:'andesite',weight:22},{block:'stone',weight:18}], {seed:6, freq:0.19});
var floorMix = noisePalette([{block:'spruce_planks',weight:55},{block:'dark_oak_planks',weight:28},{block:'stripped_spruce_log',weight:17}], {seed:12, freq:0.2});
var snowMix = noisePalette([{block:'snow_block',weight:60},{block:'powder_snow',weight:8},{block:'grass_block',weight:20},{block:'podzol',weight:12}], {seed:23, freq:0.09});
function rsid(a, bq) {
var n = (a * 17 + bq * 11) % 10;
if (n < 5) return 'bamboo_mosaic_stairs';
if (n < 8) return 'bamboo_stairs';
return 'spruce_stairs';
}
var x, y, z, i, s;
// ================= TERRAIN =================
var land = blob(30, 24, 33, {irregularity:0.45, seed:17});
var hf = hills({base: padY, amp: 4, scale: 0.05, seed: 33});
var pad = flatten(hf, {x0:6, z0:4, x1:56, z1:46}, padY, 12);
surface(land, pad, function (gx, gz) { return snowMix(gx, 0, gz); }, {sub:'dirt', deep:'stone', depth:5});
// stone-lined water channel along the NORTH edge, half frozen
fill(8, padY - 1, 7, 52, padY - 1, 8, 'stone');
fill(8, padY, 7, 52, padY, 8, 'water');
for (x = 8; x <= 52; x++) { if ((x * 5 + 3) % 7 < 3) { pb(x, padY, 7, 'ice'); pb(x, padY, 8, 'ice'); } }
fill(8, padY, 6, 52, padY, 6, rockMix);
fill(8, padY, 9, 52, padY, 9, rockMix);
for (x = 9; x <= 51; x += 4) { ps(x, padY + 1, 6, 'cobblestone_slab[type=bottom]'); ps(x + 2, padY + 1, 9, 'mossy_cobblestone_slab[type=bottom]'); }
// ================= PLINTH + FLOORS =================
fill(mx1 - 1, floorY - 1, mz1 - 1, mx2 + 1, floorY - 1, mz2 + 1, rockMix);
fill(mx1 - 1, floorY, mz1 - 1, mx2 + 1, floorY, mz2 + 1, gradientPalette(floorY - 1, floorY, [{block:'mossy_cobblestone',from:0},{block:'cobblestone',from:0.45},{block:'andesite',from:0.85}], {noise:0.3, seed:8}));
fill(kx1 - 1, floorY - 1, kz1 - 1, kx2 + 1, floorY, kz2 + 1, rockMix);
// doma (beaten earth) at the west end, boards elsewhere
fill(mx1 + 1, floorY, mz1 + 1, 21, floorY, mz2 - 1, noisePalette([{block:'packed_mud',weight:55},{block:'coarse_dirt',weight:28},{block:'dirt_path',weight:17}], {seed:19, freq:0.2}));
fill(22, floorY, mz1 + 1, mx2 - 1, floorY, mz2 - 1, floorMix);
fill(kx1 + 1, floorY, kz1 + 1, kx2 - 1, floorY, kz2 - 1, noisePalette([{block:'spruce_planks',weight:60},{block:'stripped_oak_log',weight:40}], {seed:21, freq:0.25}));
// ================= MAIN WALLS =================
fill(mx1, walkY, mz1, mx2, wallTopY, mz1, shikkui);
fill(mx1, walkY, mz2, mx2, wallTopY, mz2, shikkui);
fill(mx1, walkY, mz1, mx1, wallTopY, mz2, shikkui);
fill(mx2, walkY, mz1, mx2, wallTopY, mz2, shikkui);
// post-and-beam frame with braces PROUD of the wall
function postAt(px, pz, ox, oz) {
for (y = floorY; y <= wallTopY; y++) ps(px, y, pz, 'dark_oak_log[axis=y]');
if (ox !== 0) ps(px + ox, wallTopY - 1, pz, 'dark_oak_fence');
if (oz !== 0) ps(px, wallTopY - 1, pz + oz, 'dark_oak_fence');
}
for (x = mx1; x <= mx2; x += 3) { postAt(x, mz1, 0, -1); postAt(x, mz2, 0, 1); }
for (z = mz1; z <= mz2; z += 3) { postAt(mx1, z, -1, 0); postAt(mx2, z, 1, 0); }
for (x = mx1; x <= mx2; x++) { ps(x, wallTopY, mz1, 'dark_oak_log[axis=x]'); ps(x, wallTopY, mz2, 'dark_oak_log[axis=x]'); ps(x, 15, mz1, 'dark_oak_log[axis=x]'); ps(x, 15, mz2, 'dark_oak_log[axis=x]'); pb(x, walkY, mz1, rockMix); pb(x, walkY, mz2, rockMix); }
for (z = mz1; z <= mz2; z++) { ps(mx1, wallTopY, z, 'dark_oak_log[axis=z]'); ps(mx2, wallTopY, z, 'dark_oak_log[axis=z]'); ps(mx1, 15, z, 'dark_oak_log[axis=z]'); ps(mx2, 15, z, 'dark_oak_log[axis=z]'); pb(mx1, walkY, z, rockMix); pb(mx2, walkY, z, rockMix); }
// shoji bands on the two long walls
function shojiRun(pz, xa, xb) {
for (x = xa; x <= xb; x++) {
if (x % 3 === (mx1 % 3)) continue; // keep the posts
ps(x, 16, pz, 'white_stained_glass_pane');
ps(x, 17, pz, 'white_stained_glass_pane');
}
}
shojiRun(mz1, 24, 32); shojiRun(mz1, 34, 38);
shojiRun(mz2, 16, 22); shojiRun(mz2, 26, 38);
// main door, south side, under the low eave
fill(22, walkY, mz1, 22, walkY + 1, mz1, 'air');
ps(22, walkY, mz1, 'dark_oak_door[facing=north,half=lower,hinge=left]');
ps(22, walkY + 1, mz1, 'dark_oak_door[facing=north,half=upper,hinge=left]');
pb(22, floorY, 11, 'stone_bricks'); // entry step
ps(21, floorY, 11, 'stone_brick_slab[type=bottom]');
ps(23, floorY, 11, 'stone_brick_slab[type=bottom]');
// ================= KURA WING (built BEFORE the main gable so the junction seals) =================
for (y = walkY; y <= wallTopY; y++) {
for (x = kx1; x <= kx2; x++) {
pb(x, y, kz1, (y < 17 && (x + y) % 2 === 0) ? 'polished_blackstone' : 'white_terracotta');
pb(x, y, kz2, (y < 17 && (x + y) % 2 === 0) ? 'polished_blackstone' : 'white_terracotta');
}
for (z = kz1; z <= kz2; z++) {
pb(kx1, y, z, (y < 17 && (z + y) % 2 === 0) ? 'polished_blackstone' : 'white_terracotta');
pb(kx2, y, z, (y < 17 && (z + y) % 2 === 0) ? 'polished_blackstone' : 'white_terracotta');
}
}
for (x = kx1; x <= kx2; x++) { ps(x, wallTopY, kz1, 'dark_oak_log[axis=x]'); ps(x, wallTopY, kz2, 'dark_oak_log[axis=x]'); }
for (z = kz1; z <= kz2; z++) { ps(kx1, wallTopY, z, 'dark_oak_log[axis=z]'); ps(kx2, wallTopY, z, 'dark_oak_log[axis=z]'); }
fill(kx1 + 1, loftFloorY, kz1 + 1, kx2 - 1, loftFloorY, kz2 - 1, 'spruce_planks');
placeGableRoof(kx1, kx2, kz1, kz2, loftFloorY, 'deepslate_tile_stairs', 'deepslate_tile_slab', 'white_terracotta');
for (x = kx1 - 1; x <= kx2 + 1; x++) { ps(x, 24, kz1 - 1, 'snow[layers=2]'); ps(x, 24, kz2 + 1, 'snow[layers=2]'); ps(x, 23, kz1, 'snow[layers=1]'); ps(x, 23, kz2, 'snow[layers=1]'); }
// kura windows + door
for (y = 16; y <= 17; y++) { ps(kx2, y, 21, 'iron_bars'); ps(46, y, kz1, 'iron_bars'); ps(46, y, kz2, 'iron_bars'); }
fill(kx1, walkY, 21, kx1, walkY + 1, 21, 'air');
// ================= MAIN ROOF: 2:1 gassho pitch =================
for (x = rx1; x <= rx2; x++) {
for (s = 0; s <= 10; s++) {
var zn = ez1 + s, zs = ez2 - s, y0 = eaveY + 2 * s;
pb(x, y0, zn, thatchG); roofStair(x, y0 + 1, zn, rsid(x, zn), 'north');
pb(x, y0, zs, thatchG); roofStair(x, y0 + 1, zs, rsid(x, zs), 'south');
if (s >= 1) { pb(x, y0 - 1, zn, 'spruce_planks'); pb(x, y0 - 1, zs, 'spruce_planks'); }
if (((x * 3 + zn * 7) % 10) < 6) ps(x, y0 + 2, zn, 'snow[layers=3]');
if (((x * 3 + zs * 7) % 10) < 6) ps(x, y0 + 2, zs, 'snow[layers=2]');
}
pb(x, ridgeY - 2, czc, 'spruce_planks');
pb(x, ridgeY - 1, czc, thatchG);
ps(x, ridgeY, czc, 'stripped_spruce_log[axis=x]'); // SOLID ridge beam, never a top-slab
if (x % 2 === 0) ps(x, ridgeY + 1, czc, 'snow[layers=2]');
}
// barge boards along both gable edges
for (s = 0; s <= 10; s++) {
ps(rx1, eaveY + 2 * s + 2, ez1 + s, 'dark_oak_slab[type=bottom]');
ps(rx1, eaveY + 2 * s + 2, ez2 - s, 'dark_oak_slab[type=bottom]');
ps(rx2, eaveY + 2 * s + 2, ez1 + s, 'dark_oak_slab[type=bottom]');
ps(rx2, eaveY + 2 * s + 2, ez2 - s, 'dark_oak_slab[type=bottom]');
}
// ================= GABLE TRIANGLES (drawn LAST -> seals the kura junction at x41) =================
var gxs = [rx1, rx2];
for (i = 0; i < 2; i++) {
var gx = gxs[i];
for (z = ez1; z <= ez2; z++) {
var yTop = roofBottomZ(z) - 1;
if (yTop >= floorY) fill(gx, floorY, z, gx, yTop, z, shikkui);
}
var pzs = [12, 15, 18, 21, 24, 27, 30];
for (var pi = 0; pi < pzs.length; pi++) {
for (y = floorY; y <= roofBottomZ(pzs[pi]) - 1; y++) ps(gx, y, pzs[pi], 'dark_oak_log[axis=y]');
}
var beamYs = [19, 24, 29, 33];
for (var bi = 0; bi < beamYs.length; bi++) {
for (z = triLo(beamYs[bi]); z <= triHi(beamYs[bi]); z++) ps(gx, beamYs[bi], z, 'dark_oak_log[axis=z]');
}
var winYs = [20, 21, 25, 26, 30, 31];
for (var wi = 0; wi < winYs.length; wi++) {
var wy = winYs[wi];
for (z = triLo(wy); z <= triHi(wy); z++) {
if (z === 12 || z === 15 || z === 18 || z === 21 || z === 24 || z === 27 || z === 30) continue;
ps(gx, wy, z, 'white_stained_glass_pane');
}
}
}
// ================= LOFT FLOOR + CLEARING (rule 20: clear with INTERIOR bounds) =================
fill(mx1 + 1, loftFloorY, mz1, mx2 - 1, loftFloorY, mz2, floorMix);
fill(mx1 + 1, walkY, mz1 + 1, mx2 - 1, wallTopY, mz2 - 1, 'air');
for (z = mz1; z <= mz2; z++) {
var topFree = roofBottomZ(z) - 2;
if (topFree >= loftWalkY) fill(mx1 + 1, loftWalkY, z, mx2 - 1, topFree, z, 'air');
}
fill(kx1 + 1, walkY, kz1 + 1, kx2 - 1, wallTopY, kz2 - 1, 'air');
// passage main house -> kura (rule 14: 1 wide x 2 tall, nothing within 2 blocks)
fill(mx2, walkY, 21, kx1, walkY + 1, 21, 'air');
fill(mx2, floorY, 21, kx1, floorY, 21, 'spruce_planks');
ps(mx2, walkY, 21, 'dark_oak_door[facing=east,half=lower,hinge=left]');
ps(mx2, walkY + 1, 21, 'dark_oak_door[facing=east,half=upper,hinge=left]');
// exposed joists + roof trusses
for (x = 17; x <= 38; x += 4) for (z = mz1 + 1; z <= mz2 - 1; z++) ps(x, wallTopY, z, 'dark_oak_log[axis=z]');
for (x = 16; x <= 38; x += 5) {
for (z = 17; z <= 25; z++) ps(x, 27, z, 'dark_oak_log[axis=z]');
for (y = 28; y <= 34; y++) ps(x, y, czc, 'dark_oak_log[axis=y]');
for (z = 18; z <= 24; z++) ps(x, 31, z, 'dark_oak_log[axis=z]');
}
// ================= STAIR TO THE LOFT (U-turn stairwell) =================
placeStairwell(16, 15, walkY, loftFloorY, 'dark_oak_stairs', 'dark_oak_fence', 'spruce_planks', 'east');
// ================= GROUND FLOOR INTERIOR =================
fill(23, walkY, mz1 + 1, mx2 - 1, walkY, mz2 - 1, noisePalette([{block:'green_carpet',weight:70},{block:'lime_carpet',weight:30}], {seed:2, freq:0.25}));
// -- DOMA / kitchen (west end, x15..21)
ps(15, walkY, 15, 'furnace[facing=east,lit=true]');
ps(15, walkY, 16, 'smoker[facing=east,lit=true]');
pb(15, walkY, 17, 'stripped_spruce_log');
ps(15, walkY + 1, 17, 'spruce_stairs[facing=east,half=top]');
ps(15, walkY, 18, 'water_cauldron[level=3]');
pb(15, walkY, 19, 'barrel');
pb(16, walkY, 21, 'crafting_table'); pb(17, walkY, 21, 'cartography_table');
ps(15, walkY, 22, 'composter'); pb(16, walkY, 23, 'chest');
fill(17, walkY, 26, 19, walkY + 1, 27, 'stripped_spruce_log[axis=x]'); // woodpile
ps(20, walkY, 28, 'cauldron[level=0]');
pb(19, wallTopY - 1, 24, 'chain[axis=y]'); ps(19, wallTopY - 2, 24, 'lantern[hanging=true]');
pb(17, wallTopY - 1, 17, 'chain[axis=y]'); ps(17, wallTopY - 2, 17, 'lantern[hanging=true]');
// -- IRORI hearth room (x24..31)
fill(26, floorY, 20, 28, floorY, 22, 'polished_andesite');
fill(26, walkY, 20, 28, walkY, 22, 'air');
ps(27, floorY, 21, 'campfire[lit=true]');
for (y = 15; y <= wallTopY - 1; y++) ps(27, y, 21, 'chain[axis=y]');
ps(26, walkY, 21, 'brown_carpet'); ps(28, walkY, 21, 'brown_carpet');
ps(27, walkY, 20, 'brown_carpet'); ps(27, walkY, 22, 'brown_carpet');
ps(30, walkY, 21, 'spruce_slab[type=bottom]'); ps(31, walkY, 21, 'spruce_slab[type=bottom]');
ps(30, walkY, 20, 'red_carpet'); ps(31, walkY, 22, 'red_carpet');
// tokonoma alcove on the north wall
ps(29, walkY, mz2 - 1, 'spruce_slab[type=top]');
ps(29, walkY + 1, mz2 - 1, 'flower_pot');
ps(28, walkY + 2, mz2 - 1, 'white_wall_banner[facing=south]');
ps(30, walkY, mz2 - 1, 'potted_bamboo');
pb(25, wallTopY - 1, 25, 'chain[axis=y]'); ps(25, wallTopY - 2, 25, 'lantern[hanging=true]');
pb(31, wallTopY - 1, 17, 'chain[axis=y]'); ps(31, wallTopY - 2, 17, 'lantern[hanging=true]');
// fusuma screen between the hearth room and the east room (partial, path stays clear)
for (z = 24; z <= 29; z++) for (y = walkY; y <= walkY + 2; y++) ps(33, y, z, 'white_stained_glass_pane');
for (y = walkY; y <= walkY + 2; y++) ps(33, y, 23, 'dark_oak_log[axis=y]');
// -- EAST ROOM: sleeping + storage (x34..39)
placeBed(35, walkY, 27, 'white', 'north');
placeBed(38, walkY, 27, 'white', 'north');
pb(35, walkY, 14, 'chest'); pb(36, walkY, 14, 'chest');
shelfWall(38, walkY, 15, 'south', 5, 3);
ps(36, walkY, 20, 'lectern[facing=north]');
ps(34, walkY, 18, 'barrel[facing=up]');
rug(35, walkY, 21, 4, 3, 'red', 'orange');
ps(37, walkY, 24, 'potted_fern');
pb(36, wallTopY - 1, 22, 'chain[axis=y]'); ps(36, wallTopY - 2, 22, 'lantern[hanging=true]');
// -- KURA interior
pb(44, walkY, 18, 'barrel'); pb(45, walkY, 18, 'barrel'); pb(46, walkY, 18, 'chest');
pb(44, walkY, 24, 'chest'); pb(45, walkY, 24, 'barrel');
fill(47, walkY, 20, 48, walkY + 1, 22, 'hay_block[axis=y]');
ps(48, walkY, 18, 'decorated_pot');
ps(43, walkY, 22, 'decorated_pot');
pb(46, wallTopY - 1, 21, 'chain[axis=y]'); ps(46, wallTopY - 2, 21, 'lantern[hanging=true]');
rug(44, walkY, 20, 3, 3, 'brown', 'gray');
// ================= LOFT: silkworm floor =================
for (x = 18; x <= 37; x += 2) {
ps(x, loftWalkY, 17, 'spruce_trapdoor[facing=south,half=bottom,open=false]');
ps(x, loftWalkY + 1, 17, 'spruce_trapdoor[facing=south,half=bottom,open=false]');
ps(x, loftWalkY, 25, 'spruce_trapdoor[facing=north,half=bottom,open=false]');
ps(x, loftWalkY + 1, 25, 'spruce_trapdoor[facing=north,half=bottom,open=false]');
}
for (x = 19; x <= 36; x += 3) { pb(x, loftWalkY, 18, 'hay_block[axis=y]'); pb(x, loftWalkY, 24, 'hay_block[axis=y]'); }
pb(24, loftWalkY, 21, 'barrel'); pb(25, loftWalkY, 21, 'chest');
ps(26, loftWalkY, 21, 'loom[facing=south]');
ps(27, loftWalkY, 21, 'crafting_table');
pb(33, loftWalkY, 20, 'barrel'); pb(34, loftWalkY, 22, 'chest');
rug(29, loftWalkY, 19, 4, 4, 'brown', 'red');
for (x = 20; x <= 37; x += 5) { pb(x, 26, czc, 'chain[axis=y]'); ps(x, 25, czc, 'lantern[hanging=true]'); }
// ================= EXTERIOR =================
// raised stone-edged vegetable beds, south side
for (i = 0; i < 3; i++) {
var bx = 20 + i * 7;
fill(bx, padY + 1, 38, bx + 4, padY + 1, 44, 'farmland[moisture=7]');
for (x = bx - 1; x <= bx + 5; x++) { ps(x, padY + 1, 37, 'cobblestone_wall'); ps(x, padY + 1, 45, 'cobblestone_wall'); }
for (z = 37; z <= 45; z++) { ps(bx - 1, padY + 1, z, 'cobblestone_wall'); ps(bx + 5, padY + 1, z, 'cobblestone_wall'); }
for (x = bx; x <= bx + 4; x++) for (z = 38; z <= 44; z++) {
var cm = (x + z + i) % 4;
if (cm === 0) ps(x, padY + 2, z, 'carrots[age=7]');
else if (cm === 1) ps(x, padY + 2, z, 'beetroots[age=3]');
else if (cm === 2) ps(x, padY + 2, z, 'wheat[age=7]');
else ps(x, padY + 2, z, 'snow[layers=2]');
}
}
fill(24, padY + 1, 41, 24, padY + 1, 41, 'water');
fill(31, padY + 1, 41, 31, padY + 1, 41, 'water');
// approach path from the channel bridge to the front door
fill(20, padY, 11, 24, padY, 11, rockMix);
fill(21, padY, 34, 23, padY, 36, rockMix);
for (z = 33; z >= 12; z--) { pb(22, padY, z, rockMix); if ((z % 5) === 0) pb(21, padY, z, rockMix); }
// stone-wall plot boundary with a gate
for (x = 10; x <= 54; x++) { ps(x, padY + 1, 47, 'mossy_cobblestone_wall'); }
for (z = 11; z <= 47; z++) { ps(54, padY + 1, z, 'mossy_cobblestone_wall'); ps(10, padY + 1, z, 'mossy_cobblestone_wall'); }
fill(21, padY + 1, 47, 23, padY + 1, 47, 'air');
ps(20, padY + 1, 47, 'dark_oak_fence_gate[facing=north]');
ps(24, padY + 1, 47, 'dark_oak_fence_gate[facing=north]');
// outdoor lighting that never floats
lampPost(18, padY + 1, 35, 4, 'cobblestone_wall');
lampPost(28, padY + 1, 35, 4, 'cobblestone_wall');
lampPost(45, padY + 1, 31, 4, 'cobblestone_wall');
lampPost(12, padY + 1, 20, 4, 'cobblestone_wall');
// snow-laden trees + drying racks + drifts
makeSphere(47, padY + 8, 38, noisePalette([{block:'spruce_leaves[persistent=true]',weight:65},{block:'snow_block',weight:35}], {seed:2, freq:0.3}), 5, true);
fill(47, padY + 1, 38, 47, padY + 7, 38, 'spruce_log[axis=y]');
makeSphere(14, padY + 7, 40, noisePalette([{block:'spruce_leaves[persistent=true]',weight:65},{block:'snow_block',weight:35}], {seed:4, freq:0.3}), 4, true);
fill(14, padY + 1, 40, 14, padY + 6, 40, 'spruce_log[axis=y]');
makeSphere(51, padY + 6, 14, noisePalette([{block:'oak_leaves[persistent=true]',weight:55},{block:'snow_block',weight:45}], {seed:5, freq:0.3}), 3, true);
fill(51, padY + 1, 14, 51, padY + 5, 14, 'oak_log[axis=y]');
fill(14, padY + 1, 34, 30, padY + 1, 34, 'spruce_fence');
for (x = 14; x <= 30; x += 2) ps(x, padY + 2, 34, 'hay_block[axis=x]');
for (x = 11; x <= 53; x++) for (z = 10; z <= 46; z += 3) { if ((x * 7 + z * 3) % 11 < 3) ps(x, padY + 1, z, 'snow[layers=2]'); }
// ===== FIX PASS: settled snow on the kura roof, guarded loft opening, readable stair =====
var qx, qz;
for (qz = kz1 - 1; qz <= kz2 + 1; qz++) { ps(kx1 + 3, 24, qz, 'snow[layers=3]'); ps(kx1 + 5, 24, qz, 'snow[layers=3]'); }
// guard rail around the stairwell opening in the loft floor (5x5 well at x16..20, z15..19)
for (qx = 15; qx <= 21; qx++) { ps(qx, loftWalkY, 14, 'dark_oak_fence'); ps(qx, loftWalkY, 20, 'dark_oak_fence'); }
for (qz = 15; qz <= 19; qz++) { ps(15, loftWalkY, qz, 'dark_oak_fence'); ps(21, loftWalkY, qz, 'dark_oak_fence'); }
fill(17, loftWalkY, 17, 19, loftWalkY, 19, 'air');
fill(17, loftWalkY + 1, 17, 19, loftWalkY + 1, 19, 'air');
// lantern over the stair head so the route reads from the hearth room
pb(18, wallTopY - 1, 20, 'chain[axis=y]'); ps(18, wallTopY - 2, 20, 'lantern[hanging=true]');
pb(16, loftWalkY + 3, 21, 'chain[axis=y]'); ps(16, loftWalkY + 2, 21, 'lantern[hanging=true]');
// runner carpet from the front door to the stair approach, so the path is obvious
for (qz = 13; qz <= 20; qz++) ps(22, walkY, qz, 'red_carpet');
for (qx = 17; qx <= 22; qx++) ps(qx, walkY, 20, 'red_carpet');