// === BUILD PLAN ===
// Style: Hanseatic Backsteingotik terrace (Lubeck/Gdansk Speicher row)
// Process: LAYERED + MASKS (build-rules 14) — solid placeholder wool masses, hollow and
// carve with clearMasked(onlyMaterial), texture LAST with replaceMasked.
// Footprint: DELIBERATELY ASYMMETRIC composite (arch-guide 4: no perfect symmetry) =
// A) tall main Speicher X30..46 (17w) Z22..44 (23d), 4 storeys, crest Y45
// B) lower neighbour X48..58 (11w) Z28..44 (17d), 3 storeys, crest Y36 <- STEPPED SETBACK
// C) stair turret X22..29 (8w) Z30..38 (9d), full height, own gable <- bump-out
// + gangway bridge over the 1-block alley at x=47, quay + canal on +Z (rule 15).
//
// GROUND FLOOR (top-down, 1 char = 1 block, Z down = toward canal):
// Z22 ##########NNNN######### N = rear crow gable
// Z30 ####TTTT##..........#### T = stair turret (placeStairwell U-turn)
// Z34 #TTT>>D...............##### D = turret door into store, > = flight
// Z36 ####..........o.......#=#B## o = internal door to neighbour, = alley
// Z44 ######GGGGGG####------dd### G = cargo gate, d = neighbour door
// Z46..Z62 quay + bollards ; Z63+ canal
//
// FRONT ELEVATION (z=44) — crow steps + timber hoist ERKER (Ladeluke):
// ___ the erker projects z44->z47 and carries the beam,
// __|EEE|__ so the overhang is SUPPORTED, not floating (rule 22)
// _| |h| |_ h = hatch
// | |h| |
// | GGGGGG |
//
// MATERIALS PLAN (part -> palette -> WHY):
// plinth : stone_bricks/andesite/mossy — WHY: tide-line stone, reads wet & heavy
// walls : gradientPalette stone_bricks->bricks->granite->red_terracotta, noise .35
// — WHY: value ramp fakes shadow at the base and sun at the crest (volume, not confetti)
// roof : oxidized/weathered/exposed COPPER stairs
// — WHY: green-blue patina is the true Hanseatic roof and is the COMPLEMENT of red
// brick; a red roof on red walls would read monochrome
// timber : dark_oak_log frame + spruce_planks infill on the erker/gangway — warm accent
// ridge : SOLID deepslate_bricks beam placed AFTER every clear — WHY: ridge_gap is the
// classic failure and a top-slab ridge leaves a sky slot
// Rooms: A-F1 weighing hall / A-F2 barrel store / A-F3 cloth store / A-F4 grain loft
// B-F1 chandler's shop / B-F2+B-F3 stores / C = stairwell with landings
// STAIR PLAN: ALL vertical circulation lives in turret C -> placeStairwell(24,32,...) U-turns
// 12->17, 18->23, 24->29. Nothing else is ever placed in x23..29 / z31..38.
// === END PLAN ===
var CK = [];
function ck(m) { CK.push(m); }
ck('PLAN');
// ---------- Y levels ----------
var GY = 10, waterY = 9;
var yF = [11, 17, 23, 29]; // floor slab Y per storey
var yW = [12, 18, 24, 30]; // walk Y per storey
var aTop = 34, aRoof = 35; // main: wall top / roof base -> ridge 43, crest 45
var bTop = 28, bRoof = 29; // neighbour: wall top / roof base -> ridge 34, crest 36
var cTop = 34, cRoof = 35; // turret
var AX1 = 30, AX2 = 46, AZ1 = 22, AZ2 = 44, ACX = 38;
var BX1 = 48, BX2 = 58, BZ1 = 28, BZ2 = 44, BCX = 53;
var CX1 = 22, CX2 = 29, CZ1 = 30, CZ2 = 38;
var PH = 'blue_wool'; // wall placeholder
// ---------- palettes (applied LAST) ----------
var wallPal = gradientPalette(11, aTop, [
{ block: 'stone_bricks', from: 0 },
{ block: 'bricks', from: 0.10 },
{ block: 'granite', from: 0.55 },
{ block: 'red_terracotta', from: 0.88 }
], { noise: 0.35, seed: 17 });
var plinthPal = noisePalette([
{ block: 'stone_bricks', weight: 34 },
{ block: 'andesite', weight: 26 },
{ block: 'mossy_stone_bricks', weight: 22 },
{ block: 'cracked_stone_bricks', weight: 18 }
], { seed: 6, freq: 0.14 });
var roofPal = noisePalette([
{ block: 'oxidized_copper_stairs', weight: 46 },
{ block: 'weathered_copper_stairs', weight: 34 },
{ block: 'exposed_copper_stairs', weight: 20 }
], { seed: 23, freq: 0.15 });
var floorPal = noisePalette([
{ block: 'spruce_planks', weight: 50 },
{ block: 'dark_oak_planks', weight: 30 },
{ block: 'stripped_spruce_wood', weight: 20 }
], { seed: 31, freq: 0.19 });
var quayPal = noisePalette([
{ block: 'stone_bricks', weight: 30 },
{ block: 'cobblestone', weight: 26 },
{ block: 'andesite', weight: 24 },
{ block: 'mossy_cobblestone', weight: 20 }
], { seed: 44, freq: 0.12 });
// ---------- TERRAIN ----------
var hh = hills({ base: GY, amp: 3, scale: 0.05, seed: 11 });
var padFn = flatten(hh, { x0: 14, z0: 14, x1: 68, z1: 62 }, GY, 8);
var landMask = blob(44, 38, 46, { irregularity: 0.38, seed: 21 });
var gmat = patches([
{ block: 'grass_block', w: 66 },
{ block: 'gravel', w: 18 },
{ block: 'coarse_dirt', w: 16 }
], 0.05, 7);
surface(landMask, padFn, gmat, { sub: 'dirt', deep: 'stone', depth: 4 });
ck('TERRAIN');
// ---------- CANAL + STEPPED QUAY ----------
fill(2, 4, 63, 94, 24, 94, 'air');
fill(2, 5, 63, 94, 6, 94, 'gravel');
fill(2, 7, 63, 94, waterY, 94, 'water');
fill(10, 6, 46, 74, GY, 62, quayPal);
fill(10, 6, 62, 74, GY, 62, 'stone_bricks');
// slipway steps down into the water (asymmetric, on the east side)
var sstep;
for (sstep = 0; sstep < 4; sstep++) {
fill(60, GY - sstep, 62 + sstep, 66, GY - sstep, 62 + sstep, 'stone_brick_stairs[facing=south,half=top]');
}
// mooring bollards + iron rings
var bolls = [32, 38, 44, 52, 58, 26];
var bi;
for (bi = 0; bi < bolls.length; bi++) {
pb(bolls[bi], GY + 1, 60, 'stripped_dark_oak_log');
ps(bolls[bi], GY + 2, 60, 'dark_oak_slab[type=bottom]');
ps(bolls[bi], GY + 1, 61, 'iron_trapdoor[facing=north,half=bottom,open=true]');
}
ck('QUAY');
// ---------- LAYER 1: SOLID PLACEHOLDER MASSES ----------
fill(AX1, 11, AZ1, AX2, aTop, AZ2, PH);
fill(BX1, 11, BZ1, BX2, bTop, BZ2, PH);
fill(CX1, 11, CZ1, CX2, cTop, CZ2, PH);
ck('MASS');
// ---------- LAYER 2: HOLLOW BY PART (masks — never touches neighbours) ----------
var si;
for (si = 0; si < 4; si++) {
var top = (si === 3) ? aTop : (yF[si + 1] - 1);
clearMasked(AX1 + 1, yW[si], AZ1 + 1, AX2 - 1, top, AZ2 - 1, onlyMaterial(PH));
}
for (si = 0; si < 3; si++) {
var btop = (si === 2) ? bTop : (yF[si + 1] - 1);
clearMasked(BX1 + 1, yW[si], BZ1 + 1, BX2 - 1, btop, BZ2 - 1, onlyMaterial(PH));
}
for (si = 0; si < 4; si++) {
var ctop = (si === 3) ? cTop : (yF[si + 1] - 1);
clearMasked(CX1 + 1, yW[si], CZ1 + 1, CX2 - 1, ctop, CZ2 - 1, onlyMaterial(PH));
}
ck('HOLLOW');
// ---------- LAYER 3: CARVE OPENINGS (only the wall material is cut) ----------
// main cargo gate (off-centre, asymmetry)
clearMasked(35, 12, AZ2, 40, 15, AZ2, onlyMaterial(PH));
// stacked loading hatches on the crow-gable front, one per upper storey
var hi;
for (hi = 1; hi < 4; hi++) {
clearMasked(37, yW[hi], AZ2, 39, yW[hi] + 1, AZ2, onlyMaterial(PH));
}
// hoist opening in the gable itself (the erker will plug it)
clearMasked(37, 40, AZ2, 39, 42, AZ2, onlyMaterial(PH));
// main long-wall windows — WEST only where the turret is not, EAST all the way (asymmetric)
var wz, wi2;
for (wi2 = 0; wi2 < 4; wi2++) {
var wy = yW[wi2] + 1;
var eastZ = [25, 29, 33, 37, 41];
for (wz = 0; wz < eastZ.length; wz++) {
clearMasked(AX2, wy, eastZ[wz], AX2, wy + 1, eastZ[wz], onlyMaterial(PH));
}
clearMasked(AX1, wy, 25, AX1, wy + 1, 25, onlyMaterial(PH));
clearMasked(AX1, wy, 41, AX1, wy + 1, 41, onlyMaterial(PH));
}
// rear gable-end slit windows
clearMasked(34, 25, AZ1, 34, 26, AZ1, onlyMaterial(PH));
clearMasked(42, 25, AZ1, 42, 26, AZ1, onlyMaterial(PH));
// turret <-> main doorways at every level, plus turret windows
for (wi2 = 0; wi2 < 4; wi2++) {
clearMasked(CX2, yW[wi2], 34, AX1, yW[wi2] + 1, 34, onlyMaterial(PH));
clearMasked(CX1, yW[wi2] + 1, 33, CX1, yW[wi2] + 2, 33, onlyMaterial(PH));
}
// turret ground door to the lane
clearMasked(25, 12, CZ2, 26, 13, CZ2, onlyMaterial(PH));
// neighbour: shop door + windows + internal connection to the main store
clearMasked(52, 12, BZ2, 53, 13, BZ2, onlyMaterial(PH));
for (wi2 = 0; wi2 < 3; wi2++) {
var by2 = yW[wi2] + 1;
clearMasked(BX2, by2, 32, BX2, by2 + 1, 32, onlyMaterial(PH));
clearMasked(BX2, by2, 38, BX2, by2 + 1, 38, onlyMaterial(PH));
clearMasked(50, by2, BZ2, 50, by2 + 1, BZ2, onlyMaterial(PH));
clearMasked(56, by2, BZ2, 56, by2 + 1, BZ2, onlyMaterial(PH));
}
clearMasked(AX2, 12, 36, BX1, 13, 36, onlyMaterial(PH));
// gangway over the alley at storey 2
clearMasked(AX2, 18, 39, BX1, 19, 39, onlyMaterial(PH));
ck('CARVE');
// ---------- LAYER 4: TEXTURE LAST ----------
// plinth band first (3 rows), then everything else that is still placeholder
replaceMasked(CX1 - 1, 11, AZ1 - 1, BX2 + 1, 13, BZ2 + 1, plinthPal, onlyMaterial(PH));
// timber floors + ground slab (they are still placeholder slabs inside the mass)
replaceMasked(AX1 + 1, 11, AZ1 + 1, AX2 - 1, 11, AZ2 - 1, plinthPal, onlyMaterial(PH));
replaceMasked(BX1 + 1, 11, BZ1 + 1, BX2 - 1, 11, BZ2 - 1, plinthPal, onlyMaterial(PH));
var fi;
for (fi = 1; fi < 4; fi++) {
replaceMasked(AX1 + 1, yF[fi], AZ1 + 1, AX2 - 1, yF[fi], AZ2 - 1, floorPal, onlyMaterial(PH));
replaceMasked(CX1 + 1, yF[fi], CZ1 + 1, CX2 - 1, yF[fi], CZ2 - 1, floorPal, onlyMaterial(PH));
}
for (fi = 1; fi < 3; fi++) {
replaceMasked(BX1 + 1, yF[fi], BZ1 + 1, BX2 - 1, yF[fi], BZ2 - 1, floorPal, onlyMaterial(PH));
}
// all remaining placeholder = brickwork
replaceMasked(CX1 - 1, 11, AZ1 - 1, BX2 + 1, aTop + 1, BZ2 + 1, wallPal, onlyMaterial(PH));
ck('TEXTURE');
// ---------- WALL DEPTH: lesenes, blind arcading, cornices (built in final material) ----------
var lz2, lx2;
for (lz2 = 25; lz2 <= 41; lz2 += 4) {
fill(AX2 + 1, 11, lz2, AX2 + 1, aTop - 1, lz2 + 1, wallPal);
ps(AX2 + 1, aTop, lz2, 'brick_stairs[facing=west,half=top]');
ps(AX2 + 1, aTop, lz2 + 1, 'brick_stairs[facing=west,half=top]');
}
for (lz2 = 23; lz2 <= 27; lz2 += 4) {
fill(AX1 - 1, 11, lz2, AX1 - 1, aTop - 1, lz2 + 1, wallPal);
}
for (lz2 = 39; lz2 <= 43; lz2 += 4) {
fill(AX1 - 1, 11, lz2, AX1 - 1, aTop - 1, lz2 + 1, wallPal);
}
for (lz2 = 31; lz2 <= 41; lz2 += 5) {
fill(BX2 + 1, 11, lz2, BX2 + 1, bTop - 1, lz2 + 1, wallPal);
}
// dogtooth string-courses at each floor line (both blocks read as shadow lines)
var bandYs = [16, 22, 28];
var bj2, cz2;
for (bj2 = 0; bj2 < bandYs.length; bj2++) {
for (cz2 = AZ1; cz2 <= AZ2; cz2++) {
if (cz2 % 2 === 1) {
ps(AX1 - 1, bandYs[bj2], cz2, 'brick_slab[type=top]');
ps(AX2 + 1, bandYs[bj2], cz2, 'brick_slab[type=top]');
}
}
for (lx2 = AX1; lx2 <= AX2; lx2++) {
if (lx2 % 2 === 1) {
ps(lx2, bandYs[bj2], AZ2 + 1, 'brick_slab[type=top]');
ps(lx2, bandYs[bj2], AZ1 - 1, 'brick_slab[type=top]');
}
}
}
for (cz2 = BZ1; cz2 <= BZ2; cz2++) {
if (cz2 % 2 === 1) { ps(BX2 + 1, 22, cz2, 'brick_slab[type=top]'); ps(BX2 + 1, 16, cz2, 'brick_slab[type=top]'); }
}
// eave corbels (rule 22 — the overhang must be supported)
for (cz2 = AZ1 + 1; cz2 <= AZ2 - 1; cz2++) {
ps(AX1 - 1, aTop, cz2, 'brick_slab[type=top]');
ps(AX2 + 1, aTop, cz2, 'brick_slab[type=top]');
}
for (cz2 = BZ1 + 1; cz2 <= BZ2 - 1; cz2++) {
ps(BX1 - 1, bTop, cz2, 'brick_slab[type=top]');
ps(BX2 + 1, bTop, cz2, 'brick_slab[type=top]');
}
ck('RELIEF');
// ---------- ROOFS (direct, palette fed per stair so facing survives) ----------
placeGableRoof(AX1, AX2, AZ1 + 1, AZ2 - 1, aRoof, 'oxidized_copper_stairs', 'oxidized_copper_slab', 'bricks');
var rz2, rs;
for (rz2 = AZ1 + 1; rz2 <= AZ2 - 1; rz2++) {
for (rs = 0; rs < 9; rs++) {
roofStair(AX1 - 1 + rs, aRoof + rs, rz2, roofPal(AX1 - 1 + rs, 0, rz2), 'west');
roofStair(AX2 + 1 - rs, aRoof + rs, rz2, roofPal(AX2 + 1 - rs, 0, rz2), 'east');
}
}
placeGableRoof(BX1, BX2, BZ1 + 1, BZ2 - 1, bRoof, 'weathered_copper_stairs', 'weathered_copper_slab', 'bricks');
for (rz2 = BZ1 + 1; rz2 <= BZ2 - 1; rz2++) {
for (rs = 0; rs < 6; rs++) {
roofStair(BX1 - 1 + rs, bRoof + rs, rz2, roofPal(BX1 - 1 + rs, 0, rz2), 'west');
roofStair(BX2 + 1 - rs, bRoof + rs, rz2, roofPal(BX2 + 1 - rs, 0, rz2), 'east');
}
}
placeGableRoof(CX1, CX2, CZ1 + 1, CZ2 - 1, cRoof, 'weathered_copper_stairs', 'weathered_copper_slab', 'bricks');
for (rz2 = CZ1 + 1; rz2 <= CZ2 - 1; rz2++) {
for (rs = 0; rs < 4; rs++) {
roofStair(CX1 - 1 + rs, cRoof + rs, rz2, roofPal(CX1 - 1 + rs, 0, rz2), 'west');
roofStair(CX2 + 1 - rs, cRoof + rs, rz2, roofPal(CX2 + 1 - rs, 0, rz2), 'east');
}
}
ck('ROOF');
// ---------- ATTIC CLEAR (step-by-step so the slopes survive) ----------
var sa;
for (sa = 0; sa < 8; sa++) { fill(AX1 + sa, aRoof + sa, AZ1 + 1, AX2 - sa, aRoof + sa, AZ2 - 1, 'air'); }
for (sa = 0; sa < 5; sa++) { fill(BX1 + sa, bRoof + sa, BZ1 + 1, BX2 - sa, bRoof + sa, BZ2 - 1, 'air'); }
for (sa = 0; sa < 3; sa++) { fill(CX1 + sa, cRoof + sa, CZ1 + 1, CX2 - sa, cRoof + sa, CZ2 - 1, 'air'); }
// SOLID ridge beams — placed AFTER every clear so nothing can re-open a ridge_gap
fill(ACX, aRoof + 8, AZ1, ACX, aRoof + 8, AZ2, 'deepslate_bricks');
fill(BCX, bRoof + 5, BZ1, BCX, bRoof + 5, BZ2, 'deepslate_bricks');
fill(25, cRoof + 3, CZ1, 26, cRoof + 3, CZ2, 'deepslate_bricks');
ck('RIDGE');
// ---------- CROW-STEPPED GABLES ----------
function crow(x1, x2, cxc, zp, crest, baseY) {
var gx, d, st, ty;
for (gx = x1; gx <= x2; gx++) {
d = Math.abs(gx - cxc);
st = Math.floor(d / 2);
ty = crest - 2 * st;
if (ty < baseY) { ty = baseY; }
fill(gx, baseY, zp, gx, ty, zp, wallPal);
ps(gx, ty + 1, zp, 'stone_brick_slab[type=bottom]');
}
}
crow(AX1, AX2, ACX, AZ2, 45, aRoof);
crow(AX1, AX2, ACX, AZ1, 45, aRoof);
crow(BX1, BX2, BCX, BZ2, 36, bRoof);
crow(BX1, BX2, BCX, BZ1, 36, bRoof);
crow(CX1, CX2, 25, CZ2, 38, cRoof);
crow(CX1, CX2, 25, CZ1, 38, cRoof);
// blind pointed niches in the main gable (Backsteingotik), asymmetric heights
var nn = [34, 36, 40, 42];
var nh2 = [39, 42, 42, 39];
var ni2;
for (ni2 = 0; ni2 < nn.length; ni2++) {
fill(nn[ni2], aRoof + 1, AZ2, nn[ni2], nh2[ni2], AZ2, 'red_nether_bricks');
ps(nn[ni2], nh2[ni2] + 1, AZ2, 'brick_stairs[facing=north,half=top]');
}
// re-cut the hoist opening (the crow fill closed it)
fill(37, 40, AZ2, 39, 42, AZ2, 'air');
ck('GABLES');
// ---------- GLAZING + SHUTTERS ----------
var gz2;
for (wi2 = 0; wi2 < 4; wi2++) {
var gy = yW[wi2] + 1;
var ez2 = [25, 29, 33, 37, 41];
for (gz2 = 0; gz2 < ez2.length; gz2++) {
fillMasked(AX2, gy, ez2[gz2], AX2, gy + 1, ez2[gz2], 'glass_pane', onlyAir());
ps(AX2 + 2, gy, ez2[gz2], 'spruce_trapdoor[facing=west,half=bottom,open=true]');
}
fillMasked(AX1, gy, 25, AX1, gy + 1, 25, 'glass_pane', onlyAir());
fillMasked(AX1, gy, 41, AX1, gy + 1, 41, 'glass_pane', onlyAir());
ps(AX1 - 2, gy, 25, 'spruce_trapdoor[facing=east,half=bottom,open=true]');
ps(AX1 - 2, gy, 41, 'spruce_trapdoor[facing=east,half=bottom,open=true]');
fillMasked(CX1, gy + 1, 33, CX1, gy + 2, 33, 'glass_pane', onlyAir());
}
for (wi2 = 0; wi2 < 3; wi2++) {
var by3 = yW[wi2] + 1;
fillMasked(BX2, by3, 32, BX2, by3 + 1, 32, 'glass_pane', onlyAir());
fillMasked(BX2, by3, 38, BX2, by3 + 1, 38, 'glass_pane', onlyAir());
fillMasked(50, by3, BZ2, 50, by3 + 1, BZ2, 'glass_pane', onlyAir());
fillMasked(56, by3, BZ2, 56, by3 + 1, BZ2, 'glass_pane', onlyAir());
}
// hatch shutters, hinged open on the facade
for (hi = 1; hi < 4; hi++) {
ps(36, yW[hi], AZ2, 'dark_oak_trapdoor[facing=east,half=bottom,open=true]');
ps(40, yW[hi], AZ2, 'dark_oak_trapdoor[facing=west,half=bottom,open=true]');
ps(38, yW[hi] - 1, AZ2 + 1, 'spruce_slab[type=top]');
ps(37, yW[hi] - 1, AZ2 + 1, 'spruce_slab[type=top]');
ps(39, yW[hi] - 1, AZ2 + 1, 'spruce_slab[type=top]');
}
// doors
ps(35, 12, AZ2, 'dark_oak_door[facing=south,half=lower,hinge=left]');
ps(35, 13, AZ2, 'dark_oak_door[facing=south,half=upper,hinge=left]');
ps(40, 12, AZ2, 'dark_oak_door[facing=south,half=lower,hinge=right]');
ps(40, 13, AZ2, 'dark_oak_door[facing=south,half=upper,hinge=right]');
ps(52, 12, BZ2, 'spruce_door[facing=south,half=lower,hinge=left]');
ps(52, 13, BZ2, 'spruce_door[facing=south,half=upper,hinge=left]');
ps(25, 12, CZ2, 'spruce_door[facing=south,half=lower,hinge=left]');
ps(25, 13, CZ2, 'spruce_door[facing=south,half=upper,hinge=left]');
// stone gate arch surround
ps(34, 12, AZ2, 'stone_bricks'); ps(34, 13, AZ2, 'stone_bricks'); ps(34, 14, AZ2, 'stone_bricks');
ps(41, 12, AZ2, 'stone_bricks'); ps(41, 13, AZ2, 'stone_bricks'); ps(41, 14, AZ2, 'stone_bricks');
ps(35, 16, AZ2, 'stone_brick_stairs[facing=east,half=bottom]');
ps(40, 16, AZ2, 'stone_brick_stairs[facing=west,half=bottom]');
fill(36, 16, AZ2, 39, 16, AZ2, 'stone_bricks');
ck('OPENINGS');
// ---------- STAIRS: all circulation in the turret (U-turn stairwells) ----------
placeStairwell(24, 32, yW[0], yF[1], 'spruce_stairs', 'spruce_fence', 'spruce_planks', 'south');
placeStairwell(24, 32, yW[1], yF[2], 'spruce_stairs', 'spruce_fence', 'spruce_planks', 'south');
placeStairwell(24, 32, yW[2], yF[3], 'spruce_stairs', 'spruce_fence', 'spruce_planks', 'south');
ck('STAIRS');
// ---------- INTERIORS ----------
function crate2(x, y, z, n) {
var k;
for (k = 0; k < n; k++) { pb(x, y + k, z, 'barrel[facing=up]'); }
}
function bale(x, y, z, col) {
pb(x, y, z, col); pb(x + 1, y, z, col); pb(x, y, z + 1, col);
pb(x, y + 1, z, 'hay_block[axis=y]');
}
function lamp(x, y, z) { ps(x, y, z, 'lantern[hanging=true]'); }
// A-F1 weighing hall
rug(36, yW[0], 38, 5, 4, 'red', 'brown');
ps(38, yW[0], 41, 'anvil[facing=north]');
pb(37, yW[0], 41, 'stripped_spruce_log'); ps(37, yW[0] + 1, 41, 'spruce_slab[type=bottom]');
ps(34, yW[0], 40, 'lectern[facing=east]');
chairStair(35, yW[0], 40, 'spruce_stairs', 'west');
pb(33, yW[0], 40, 'barrel[facing=up]');
crate2(44, yW[0], 41, 2); crate2(45, yW[0], 41, 1); crate2(44, yW[0], 39, 2);
crate2(32, yW[0], 27, 2); crate2(33, yW[0], 27, 1);
pb(45, yW[0], 35, 'chest[facing=west]'); pb(45, yW[0], 34, 'chest[facing=west]');
bale(42, yW[0], 25, 'brown_wool');
ps(44, yW[0], 30, 'cartography_table'); pb(45, yW[0], 30, 'composter');
lamp(38, 16, 36); lamp(43, 16, 40); lamp(33, 16, 32); lamp(40, 16, 26);
// A-F2 barrel store
crate2(32, yW[1], 25, 3); crate2(33, yW[1], 25, 2); crate2(32, yW[1], 26, 2);
crate2(44, yW[1], 25, 3); crate2(45, yW[1], 25, 2);
crate2(44, yW[1], 40, 2); crate2(45, yW[1], 40, 3); crate2(44, yW[1], 41, 1);
crate2(32, yW[1], 41, 2);
bale(36, yW[1], 27, 'brown_wool'); bale(40, yW[1], 30, 'brown_wool');
rug(36, yW[1], 35, 4, 4, 'orange', 'brown');
ps(38, yW[1], 41, 'smithing_table'); pb(37, yW[1], 41, 'barrel[facing=up]');
lamp(38, 22, 33); lamp(43, 22, 38); lamp(33, 22, 29);
// A-F3 cloth store
bale(33, yW[2], 25, 'white_wool'); bale(36, yW[2], 25, 'light_blue_wool');
bale(40, yW[2], 25, 'red_wool'); bale(43, yW[2], 25, 'green_wool');
bale(33, yW[2], 39, 'yellow_wool'); bale(43, yW[2], 39, 'purple_wool');
shelfWall(41, yW[2], 42, 'west', 5, 2);
ps(38, yW[2], 41, 'lectern[facing=south]');
chairStair(38, yW[2], 40, 'dark_oak_stairs', 'south');
pb(36, yW[2], 41, 'chest[facing=south]'); pb(35, yW[2], 41, 'barrel[facing=up]');
rug(36, yW[2], 33, 5, 5, 'blue', 'white');
ps(44, yW[2], 33, 'flower_pot'); ps(33, yW[2], 33, 'potted_fern');
lamp(38, 28, 30); lamp(38, 28, 38); lamp(43, 28, 35);
// A-F4 grain loft + hoist gear
bale(34, yW[3], 25, 'brown_wool'); bale(41, yW[3], 25, 'brown_wool');
bale(34, yW[3], 31, 'brown_wool'); bale(43, yW[3], 33, 'brown_wool');
crate2(44, yW[3], 26, 2); crate2(32, yW[3], 37, 2);
fill(37, aTop - 1, 40, 39, aTop - 1, 40, 'stripped_spruce_log[axis=x]');
ps(37, aTop - 2, 40, 'spruce_fence'); ps(39, aTop - 2, 40, 'spruce_fence');
pb(38, aTop - 2, 40, 'stripped_spruce_log[axis=x]');
pb(38, yW[3], 39, 'barrel[facing=up]');
placeBed(33, yW[3], 42, 'red', 'north');
pb(32, yW[3], 42, 'spruce_fence'); pb(32, yW[3] + 1, 42, 'oak_pressure_plate');
ps(32, yW[3] + 2, 42, 'lantern[hanging=false]');
ps(35, yW[3], 36, 'crafting_table'); pb(34, yW[3], 36, 'chest[facing=south]');
rug(37, yW[3], 33, 4, 3, 'gray', 'brown');
lamp(38, 33, 31); lamp(42, 33, 38);
// B (neighbour) — chandler's shop + stores
rug(50, yW[0], 39, 5, 4, 'green', 'brown');
fill(50, yW[0], 42, 53, yW[0], 42, 'dark_oak_fence');
fill(50, yW[0] + 1, 42, 53, yW[0] + 1, 42, 'dark_oak_pressure_plate');
pb(54, yW[0], 42, 'barrel[facing=up]');
shelfWall(50, yW[0], 30, 'east', 5, 2);
chairStair(52, yW[0], 40, 'dark_oak_stairs', 'north');
ps(55, yW[0], 41, 'lectern[facing=west]');
pb(56, yW[0], 36, 'chest[facing=west]'); crate2(56, yW[0], 34, 2);
ps(51, yW[0], 34, 'cauldron'); pb(52, yW[0], 34, 'composter');
lamp(53, 16, 38); lamp(53, 16, 32);
crate2(50, yW[1], 31, 3); crate2(51, yW[1], 31, 2); crate2(56, yW[1], 31, 2);
crate2(50, yW[1], 41, 2); crate2(56, yW[1], 41, 3);
bale(52, yW[1], 35, 'white_wool');
rug(52, yW[1], 39, 3, 3, 'brown', 'white');
lamp(53, 22, 36);
bale(50, yW[2], 31, 'light_gray_wool'); bale(55, yW[2], 31, 'brown_wool');
crate2(50, yW[2], 41, 2); crate2(56, yW[2], 40, 2);
ps(53, yW[2], 41, 'barrel[facing=up]');
rug(52, yW[2], 35, 3, 3, 'red', 'brown');
lamp(53, 27, 37);
ck('INTERIOR');
// ---------- HOIST ERKER (timber, projects and SUPPORTS the beam) ----------
fill(36, 39, AZ2 + 1, 40, 39, AZ2 + 3, 'spruce_planks');
fill(36, 40, AZ2 + 1, 36, 43, AZ2 + 3, 'dark_oak_log[axis=y]');
fill(40, 40, AZ2 + 1, 40, 43, AZ2 + 3, 'dark_oak_log[axis=y]');
fill(37, 40, AZ2 + 3, 39, 43, AZ2 + 3, 'spruce_planks');
fill(37, 40, AZ2 + 1, 39, 40, AZ2 + 2, 'air');
fill(36, 44, AZ2 + 1, 40, 44, AZ2 + 3, 'dark_oak_log[axis=x]');
// little gable cap on the erker
var es;
for (es = 0; es < 3; es++) {
roofStair(36 + es, 44 + es, AZ2 + 1, 'dark_oak_stairs', 'west');
roofStair(40 - es, 44 + es, AZ2 + 1, 'dark_oak_stairs', 'east');
roofStair(36 + es, 44 + es, AZ2 + 2, 'dark_oak_stairs', 'west');
roofStair(40 - es, 44 + es, AZ2 + 2, 'dark_oak_stairs', 'east');
roofStair(36 + es, 44 + es, AZ2 + 3, 'dark_oak_stairs', 'west');
roofStair(40 - es, 44 + es, AZ2 + 3, 'dark_oak_stairs', 'east');
}
fill(38, 46, AZ2 + 1, 38, 46, AZ2 + 3, 'stripped_dark_oak_log[axis=z]');
// projecting beam + winch + rope + hanging crate
fill(38, 43, AZ2 + 3, 38, 43, AZ2 + 6, 'stripped_spruce_log[axis=z]');
ps(38, 42, AZ2 + 4, 'spruce_stairs[facing=south,half=top]');
ps(37, 43, AZ2 + 5, 'spruce_fence'); ps(39, 43, AZ2 + 5, 'spruce_fence');
var ry2;
for (ry2 = 27; ry2 <= 42; ry2++) { pb(38, ry2, AZ2 + 6, 'iron_bars'); }
pb(38, 26, AZ2 + 6, 'barrel[facing=up]');
ps(38, 25, AZ2 + 6, 'spruce_slab[type=top]');
// braces so the erker is visibly carried
ps(36, 38, AZ2 + 1, 'dark_oak_stairs[facing=south,half=top]');
ps(40, 38, AZ2 + 1, 'dark_oak_stairs[facing=south,half=top]');
ps(38, 38, AZ2 + 2, 'dark_oak_stairs[facing=south,half=top]');
ck('ERKER');
// ---------- GANGWAY over the alley ----------
fill(47, 17, 38, 47, 17, 40, 'spruce_planks');
fill(47, 21, 38, 47, 21, 40, 'spruce_planks');
pb(47, 18, 37, 'dark_oak_log[axis=y]'); pb(47, 19, 37, 'dark_oak_log[axis=y]');
pb(47, 18, 41, 'dark_oak_log[axis=y]'); pb(47, 19, 41, 'dark_oak_log[axis=y]');
ps(47, 20, 37, 'glass_pane'); ps(47, 20, 41, 'glass_pane');
ps(47, 16, 39, 'dark_oak_stairs[facing=north,half=top]');
// ---------- EXTERIOR ----------
var lz3, lx3;
for (lz3 = AZ2 + 1; lz3 <= 62; lz3++) {
for (lx3 = 32; lx3 <= 44; lx3++) {
pb(lx3, GY, lz3, ((lx3 * 7 + lz3 * 5) % 11 === 0) ? 'gravel' : 'cobblestone');
}
}
for (lx3 = 22; lx3 <= 60; lx3++) { pb(lx3, GY, 46, 'cobblestone'); pb(lx3, GY, 47, 'cobblestone'); }
for (lz3 = 30; lz3 <= 46; lz3++) { pb(20, GY, lz3, 'cobblestone'); pb(21, GY, lz3, 'cobblestone'); }
lampPost(33, GY + 1, 49, 4, 'dark_oak_fence');
lampPost(43, GY + 1, 49, 4, 'dark_oak_fence');
lampPost(21, GY + 1, 42, 4, 'dark_oak_fence');
lampPost(56, GY + 1, 50, 4, 'dark_oak_fence');
// quayside crane (timber A-frame) — a real dock prop, not floating
fill(50, GY + 1, 54, 50, GY + 7, 54, 'dark_oak_log[axis=y]');
fill(54, GY + 1, 54, 54, GY + 7, 54, 'dark_oak_log[axis=y]');
fill(50, GY + 8, 54, 54, GY + 8, 54, 'dark_oak_log[axis=x]');
fill(52, GY + 8, 54, 52, GY + 8, 58, 'stripped_spruce_log[axis=z]');
for (ry2 = GY + 3; ry2 <= GY + 7; ry2++) { pb(52, ry2, 58, 'iron_bars'); }
pb(52, GY + 2, 58, 'barrel[facing=up]');
ps(51, GY + 8, 55, 'dark_oak_stairs[facing=south,half=top]');
ps(53, GY + 8, 55, 'dark_oak_stairs[facing=south,half=top]');
// dockside goods, nets, fish barrels
crate2(35, GY + 1, 50, 2); crate2(36, GY + 1, 50, 1); crate2(35, GY + 1, 51, 1);
crate2(42, GY + 1, 52, 2); crate2(43, GY + 1, 52, 1);
bale(46, GY + 1, 50, 'brown_wool');
pb(41, GY + 1, 49, 'chest[facing=south]');
ps(29, GY + 1, 50, 'barrel[facing=up]'); ps(30, GY + 1, 50, 'barrel[facing=up]');
// weathering, moss, greenery
var vg2, gx3, gz3;
for (vg2 = 0; vg2 < 34; vg2++) {
gx3 = 14 + (vg2 * 9) % 56;
gz3 = 47 + (vg2 * 5) % 14;
if (vg2 % 3 === 0) { ps(gx3, GY + 1, gz3, 'moss_carpet'); }
else if (vg2 % 3 === 1) { pb(gx3, GY, gz3, 'mossy_cobblestone'); }
else { ps(gx3, GY + 1, gz3, 'brown_carpet'); }
}
for (vg2 = 46; vg2 <= 62; vg2 += 2) { ps(12, GY, vg2, 'vine[south=true]'); }
for (vg2 = 0; vg2 < 26; vg2++) {
gx3 = 16 + (vg2 * 13) % 48;
gz3 = 14 + (vg2 * 7) % 8;
ps(gx3, GY + 1, gz3, (vg2 % 4 === 0) ? 'oak_leaves[persistent=true]' : 'short_grass');
}
for (vg2 = 0; vg2 < 14; vg2++) {
ps(18 + (vg2 * 4) % 44, GY + 1, 16 + (vg2 * 3) % 6, (vg2 % 2 === 0) ? 'blue_orchid' : 'dandelion');
}
// flower boxes under the neighbour's shop windows (arch-guide 4)
ps(50, 14, BZ2 + 1, 'spruce_trapdoor[facing=north,half=bottom,open=true]');
pb(50, 14, BZ2 + 1, 'flower_pot');
ps(56, 14, BZ2 + 1, 'spruce_trapdoor[facing=north,half=bottom,open=true]');
// moored barge
fill(30, waterY, 65, 36, waterY, 67, 'spruce_slab[type=bottom]');
ps(29, waterY, 66, 'spruce_stairs[facing=east,half=bottom]');
ps(37, waterY, 66, 'spruce_stairs[facing=west,half=bottom]');
pb(33, waterY + 1, 66, 'barrel[facing=up]'); pb(34, waterY + 1, 66, 'barrel[facing=up]');
pb(32, waterY + 1, 65, 'dark_oak_fence'); pb(32, waterY + 2, 65, 'dark_oak_fence');
pb(44, waterY + 1, 66, 'stripped_dark_oak_log'); pb(44, waterY, 66, 'stripped_dark_oak_log');
ck('EXTERIOR');
ck('DONE');