// === BUILD PLAN ===
// Subject: COLOSSAL PANGOLIN (organic). Retrieval: search_docs action="related" ->
// anchored on organic-builds "Sculpting Curves at Different Scales" (+ Statues & Sculptures,
// Human Figure Proportions). Method taken from it:
// large curves (r>=9) -> makeSphere/makeCylinder BASE SHAPE, then DETAIL BY HAND
// small curves (r=2-4) -> stairs + slabs at the edges
// So: sphere-chain body, hand-laid STAIR SCALE PLATES, slab toes/claws.
//
// SIDE SILHOUETTE (X horizontal, snout left; Y vertical):
// .........#####........
// ......###########..... arched armoured back
// ...#################......
// ..###################.####.... tail = body length, dragging away to +Z
// ...##...##.......##...##...... 4 short stout legs
// ======================== ground pad Y8, feet Y9
//
// TOP SILHOUETTE (X right, Z down):
// o##########........
// .###########.......
// o############......
// ......########.....
// .........#######...
// ............#####..
// ...............###. tail sweeps to +Z
//
// MATERIALS (what / where / why):
// scales : dark_oak_planks + brown_terracotta + moss_block + packed_mud
// WHY: dark olive keratin. Kept DARK so it reads against a LIGHT ground —
// value contrast is what makes the silhouette legible (organic pitfall list).
// plates : dark_oak_stairs laid by hand in rows, facing TOWARD the tail (roofStair edge=west
// -> facing=east) WHY: that is literally "overlapping scales", relief not paint
// belly : white/light_gray terracotta on the lower third — pale soft underside
// ground : red_sand + orange_terracotta (LIGHT) so the dark animal pops
// mounds : tall thin termite spires, terracotta, 10-18 high
// === END PLAN ===
var padY = 8, groundY = 9;
var SCALES = noisePalette([
{ block: 'dark_oak_planks', weight: 30 },
{ block: 'brown_terracotta', weight: 24 },
{ block: 'packed_mud', weight: 18 },
{ block: 'moss_block', weight: 16 },
{ block: 'stripped_dark_oak_log[axis=x]', weight: 12 }
], { seed: 71, freq: 0.13 });
var BELLY = noisePalette([
{ block: 'white_terracotta', weight: 42 },
{ block: 'light_gray_terracotta', weight: 33 },
{ block: 'terracotta', weight: 25 }
], { seed: 73, freq: 0.17 });
var LIMB = noisePalette([
{ block: 'brown_terracotta', weight: 50 },
{ block: 'packed_mud', weight: 28 },
{ block: 'dark_oak_planks', weight: 22 }
], { seed: 77, freq: 0.19 });
var SPIRE = noisePalette([
{ block: 'terracotta', weight: 34 },
{ block: 'orange_terracotta', weight: 26 },
{ block: 'red_sand', weight: 22 },
{ block: 'smooth_red_sandstone', weight: 18 }
], { seed: 79, freq: 0.11 });
// ---------- 1. GROUND: light red-earth savanna, flat pad under the animal ----------
var land = blob(66, 58, 60, { irregularity: 0.32, seed: 33 });
var hf = hills({ base: padY, amp: 3, scale: 0.028, seed: 14 });
var pad = flatten(hf, { x0: 8, z0: 34, x1: 122, z1: 84 }, padY, 12);
var gm = patches(['red_sand', 'orange_terracotta', 'red_sand', 'smooth_red_sandstone'], 0.045, 9);
surface(land, pad, gm, { sub: 'red_sand', deep: 'smooth_red_sandstone', depth: 5 });
// ---------- 2. BASE SHAPE: sphere chain along the spine (large curves) ----------
var SP = [
[17, 15, 55, 2.2],
[23, 16, 55, 4.0],
[31, 18, 55, 6.2],
[40, 20, 55, 8.8],
[46, 21, 55, 9.8],
[53, 21, 55, 10.0],
[60, 20, 55, 9.4],
[67, 19, 56, 8.2],
[75, 18, 59, 7.0],
[85, 16, 65, 5.6],
[96, 14, 70, 4.2],
[106, 12, 72, 3.0],
[116, 11, 69, 1.8]
];
var path = [];
var i, j;
for (i = 0; i < SP.length - 1; i++) {
var A = SP[i], B = SP[i + 1];
var dx = B[0] - A[0], dy = B[1] - A[1], dz = B[2] - A[2];
var L = Math.sqrt(dx * dx + dy * dy + dz * dz);
var n = Math.ceil(L / 1.6);
for (j = 0; j < n; j++) {
var t = j / n;
path.push([A[0] + dx * t, A[1] + dy * t, A[2] + dz * t, A[3] + (B[3] - A[3]) * t]);
}
}
path.push(SP[SP.length - 1]);
for (i = 0; i < path.length; i++) {
var p = path[i];
makeSphere(Math.round(p[0]), Math.round(p[1]), Math.round(p[2]), SCALES, Math.round(p[3]), false);
}
// trim anything that dropped below the ground line
fill(0, 0, 0, 129, groundY - 1, 109, 'air');
surface(land, pad, gm, { sub: 'red_sand', deep: 'smooth_red_sandstone', depth: 5 });
// ---------- 3. DETAIL BY HAND (a): pale belly on the lower third ----------
for (i = 0; i < path.length; i++) {
var q = path[i];
var r = q[3];
if (r < 2.5) continue;
var cxq = q[0], cyq = q[1], czq = q[2];
for (var bx = Math.round(cxq - r); bx <= Math.round(cxq + r); bx++) {
for (var by = Math.round(cyq - r); by <= Math.round(cyq - r * 0.38); by++) {
if (by < groundY) continue;
for (var bz = Math.round(czq - r); bz <= Math.round(czq + r); bz++) {
var ddx = bx - cxq, ddy = by - cyq, ddz = bz - czq;
var dd = Math.sqrt(ddx * ddx + ddy * ddy + ddz * ddz);
if (dd <= r && dd >= r - 1.6) pb(bx, by, bz, BELLY);
}
}
}
}
// ---------- 4. DETAIL BY HAND (b): OVERLAPPING STAIR SCALE PLATES ----------
// rows every 4 stations; each row is an arc of stairs over the upper surface,
// full face toward the TAIL (edge "west" -> facing "east") = the overlap read.
var plateMat = noisePalette([
{ block: 'dark_oak_stairs', weight: 55 },
{ block: 'spruce_stairs', weight: 28 },
{ block: 'mangrove_stairs', weight: 17 }
], { seed: 83, freq: 0.2 });
for (i = 2; i < path.length; i += 4) {
var sp = path[i];
var rr = sp[3] + 0.6;
if (rr < 3) continue;
for (var ang = -115; ang <= 115; ang += 9) {
var th = ang * Math.PI / 180;
var py = Math.round(sp[1] + rr * Math.cos(th));
var pzz = Math.round(sp[2] + rr * Math.sin(th));
if (py < groundY) continue;
roofStair(Math.round(sp[0]), py, pzz, plateMat(Math.round(sp[0]), py, pzz), 'west');
}
}
// dorsal keel ridge
for (i = 0; i < path.length; i++) {
var kp = path[i];
if (kp[3] < 2.2) continue;
pb(Math.round(kp[0]), Math.round(kp[1] + kp[3]), Math.round(kp[2]), 'dark_oak_wood');
}
// ---------- 5. HEAD: narrow tapering snout (small curves -> slabs/stairs) ----------
makeCylinder(14, 14, 55, SCALES, 2, 1, false);
makeSphere(19, 15, 55, SCALES, 3, false);
ps(12, 14, 55, 'dark_oak_slab[type=bottom]');
ps(13, 15, 55, 'polished_blackstone_slab[type=bottom]');
pb(14, 14, 54, 'polished_blackstone'); pb(14, 14, 56, 'polished_blackstone');
pb(20, 17, 52, 'black_concrete'); pb(20, 17, 58, 'black_concrete'); // eyes
pb(21, 18, 52, 'dark_oak_wood'); pb(21, 18, 58, 'dark_oak_wood'); // brow
pb(24, 19, 51, 'brown_terracotta'); pb(24, 19, 59, 'brown_terracotta'); // ears
// throat pouch, pale
makeSphere(22, 13, 55, BELLY, 2, false);
// ---------- 6. LEGS: short + stout, clawed forelimbs ----------
function leg(lx, lz, topY, rr, claws) {
var x, y, z;
for (x = Math.round(lx - rr); x <= Math.round(lx + rr); x++) {
for (z = Math.round(lz - rr); z <= Math.round(lz + rr); z++) {
var d = Math.sqrt((x - lx) * (x - lx) + (z - lz) * (z - lz));
if (d > rr) continue;
for (y = groundY; y <= topY; y++) pb(x, y, z, LIMB);
}
}
for (x = Math.round(lx - rr - 1); x <= Math.round(lx + rr + 1); x++) {
for (z = Math.round(lz - rr - 1); z <= Math.round(lz + rr + 1); z++) {
if (Math.sqrt((x - lx) * (x - lx) + (z - lz) * (z - lz)) <= rr + 1) pb(x, groundY, z, LIMB);
}
}
if (claws) {
var zs = [lz - 2, lz, lz + 2];
for (var c = 0; c < 3; c++) {
pb(Math.round(lx - rr - 1), groundY, Math.round(zs[c]), 'polished_blackstone');
pb(Math.round(lx - rr - 2), groundY, Math.round(zs[c]), 'blackstone');
ps(Math.round(lx - rr - 3), groundY, Math.round(zs[c]), 'polished_blackstone_slab[type=bottom]');
}
}
}
leg(37, 48, 14, 3.4, true);
leg(40, 62, 14, 3.4, true);
leg(62, 48, 14, 3.6, false);
leg(60, 62, 14, 3.6, false);
// ---------- 7. SCENE: tall termite spires, acacias, scrub, scratched earth ----------
function spire(mx, mz, r, hh) {
makeCone(mx, groundY, mz, SPIRE, r, hh, false);
makeCone(mx + 2, groundY, mz - 1, SPIRE, Math.max(1, r - 2), Math.round(hh * 0.6), false);
makeCone(mx - 2, groundY, mz + 2, SPIRE, Math.max(1, r - 3), Math.round(hh * 0.45), false);
pb(mx, groundY + hh, mz, 'orange_terracotta');
}
spire(26, 26, 5, 17);
spire(96, 24, 4, 13);
spire(16, 78, 4, 12);
spire(112, 92, 5, 15);
spire(70, 96, 3, 10);
spire(48, 18, 3, 11);
function acacia(tx, tz, hh) {
var y;
for (y = groundY; y < groundY + hh; y++) pb(tx, y, tz, 'acacia_log[axis=y]');
drawLine(tx, groundY + hh - 2, tz, tx - 4, groundY + hh + 1, tz + 2, 'acacia_log', 1);
drawLine(tx, groundY + hh - 2, tz, tx + 4, groundY + hh + 1, tz - 3, 'acacia_log', 1);
var lf = noisePalette([
{ block: 'acacia_leaves[persistent=true]', weight: 65 },
{ block: 'oak_leaves[persistent=true]', weight: 20 },
{ block: 'azalea_leaves[persistent=true]', weight: 15 }
], { seed: 87 });
makeCylinder(tx, groundY + hh + 1, tz, lf, 8, 2, false);
makeCylinder(tx + 2, groundY + hh + 3, tz - 1, lf, 4, 1, false);
}
acacia(100, 50, 11);
acacia(14, 40, 9);
acacia(80, 94, 10);
// scattered boulders (big blotches, not confetti)
function boulder(bx, bz, r) {
makeSphere(bx, groundY + r - 2, bz, noisePalette([
{ block: 'smooth_red_sandstone', weight: 45 },
{ block: 'terracotta', weight: 30 },
{ block: 'cobblestone', weight: 25 }
], { seed: 91 }), r, false);
}
boulder(36, 88, 3); boulder(90, 34, 4); boulder(118, 60, 3); boulder(10, 62, 3);
var sx, sz;
for (sx = 6; sx <= 124; sx += 3) {
for (sz = 6; sz <= 104; sz += 3) {
var nv = noise2d(sx * 0.08, sz * 0.08);
if (nv > 0.3) {
if ((sx * 2 + sz) % 7 === 0) pb(sx, groundY, sz, 'dead_bush');
else if ((sx * 2 + sz) % 7 === 3) pb(sx, groundY, sz, 'short_grass');
}
}
}