// === BUILD PLAN ===
// Style: colossal organic creature (axolotl) in a limestone cavern, half-beached at a pool edge
// Footprint: creature ~56 long (X 16..72) x ~16 wide, head at the west, tail curling south into the water
// Height: cavern floor pad y=8, water surface y=10, creature spine y=12..16, dripstone columns to y=30
//
// TOP VIEW:
// ...^^^^ dripstone / limestone wall ^^^^.......
// .... gills ___body___ ......
// .. (head)==( A X O L O T L )==\ ......
// ..~~~~~~~~~~~~~~~~~~~~~~~~~~ tail ) ~~~~~
// ..~~~~~~~~~~~ POOL ~~~~~~~~~~~~~~~~~~~~~~~
// Legend: ~ water, ^ rock, A body
//
// MATERIALS PLAN:
// rock : terrain() + patches: calcite / diorite / tuff / dripstone - WHY: cool grey limestone reads "cave"
// pool : water over gravel+sand bed, prismarine glints - WHY: contrast with the warm pink body
// skin : noise pink_concrete(55) + pink_terracotta(30) + pink_wool(15) - WHY: value ramp, not one flat pink
// belly : white_concrete / white_terracotta on the lowest 2 courses - WHY: countershading = volume
// gills : magenta_wool branches + pink_wool feather tips - WHY: fluffy silhouette read
// glow : glow_lichen, sea_lantern under water, moss patches - WHY: "glowing algae" from the prompt
// Creature parts: head (broad flat ellipsoid) - gills x6 - body - 4 stubby legs w/ 4 toes - curled paddle tail
// === END PLAN ===
var padY = 8, waterY = 10;
// ---------- 1. CAVERN FLOOR (terrain superpowers) ----------
terrain({ cx:44, cz:32, radius:46, baseY:padY, amp:4, scale:0.05, seed:41,
surface:[{block:'calcite',weight:30},{block:'diorite',weight:20},{block:'tuff',weight:25},{block:'gravel',weight:15},{block:'moss_block',weight:10}],
sub:'tuff', deep:'deepslate', depth:4,
pads:[{cx:40, cz:30, r:26, y:padY, falloff:9}] });
// ---------- 2. POOL (irregular blob, carved then filled) ----------
var poolMask = blob(50, 60, 26, {irregularity:0.45, seed:13});
var wx, wz, wy;
for (wx = 10; wx <= 90; wx++){
for (wz = 30; wz <= 78; wz++){
if (poolMask(wx, wz)){
for (wy = padY + 4; wy >= padY - 4; wy--) pb(wx, wy, wz, 'air');
pb(wx, padY - 5, wz, (((wx + wz) % 7) === 0) ? 'prismarine' : 'gravel');
for (wy = padY - 4; wy <= waterY; wy++) pb(wx, wy, wz, 'water');
if (((wx * 3 + wz * 5) % 23) === 0) pb(wx, padY - 4, wz, 'sea_lantern');
}
}
}
// ---------- 3. SKIN PALETTES ----------
function skin(x, y, z){
var n = noise2d('perlin', x * 1.4 + z * 0.6, z * 1.4 + y * 0.8, {freq:0.22, seed:8});
if (n > 0.68) return 'pink_wool';
if (n > 0.34) return 'pink_terracotta';
return 'pink_concrete';
}
function bellySkin(x, y, z){
var n = noise2d('perlin', x, z + y, {freq:0.25, seed:3});
return (n > 0.5) ? 'white_concrete' : 'white_terracotta';
}
// ---------- 4. BODY: ellipsoid cross-sections sampled along a spine ----------
// spine: [x, y, z, halfWidth, halfHeight]
var spine = [
[17, 12, 34, 4.0, 1.8], // snout tip
[20, 12, 34, 6.0, 2.4],
[24, 12, 34, 7.5, 3.0], // head, widest
[28, 12, 34, 7.5, 3.2],
[31, 12, 34, 6.0, 3.2], // jaw / neck
[34, 12, 34, 5.2, 3.4],
[39, 12, 34, 5.8, 3.8], // trunk
[44, 12, 34, 5.6, 3.8],
[49, 12, 35, 4.8, 3.6],
[54, 12, 36, 3.8, 3.8], // tail base, starts getting tall
[59, 12, 39, 3.0, 4.4],
[63, 12, 44, 2.4, 4.6], // paddle tail, flattened & tall
[65, 12, 50, 2.0, 4.4],
[65, 12, 56, 1.6, 3.6],
[63, 12, 61, 1.2, 2.6], // tail tip curling back
[60, 12, 64, 0.9, 1.8]
];
function ellipseAt(cx, cy, cz, hw, hh){
var dx, dy, dz, v;
var r = Math.ceil(hw) + 1;
for (dx = -r; dx <= r; dx++)
for (dz = -r; dz <= r; dz++)
for (dy = -Math.ceil(hh) - 1; dy <= Math.ceil(hh) + 1; dy++){
v = (dx*dx)/(hw*hw) + (dz*dz)/(hw*hw) + (dy*dy)/(hh*hh);
if (v <= 1.0){
var yy = cy + dy;
pb(cx + dx, yy, cz + dz, (dy <= -hh * 0.45) ? bellySkin(cx+dx, yy, cz+dz) : skin(cx+dx, yy, cz+dz));
}
}
}
var si, t, steps, p0, p1, ix, iy, iz, ihw, ihh;
for (si = 0; si < spine.length - 1; si++){
p0 = spine[si]; p1 = spine[si+1];
steps = 6;
for (t = 0; t < steps; t++){
var f = t / steps;
ix = Math.round(p0[0] + (p1[0]-p0[0]) * f);
iy = Math.round(p0[1] + (p1[1]-p0[1]) * f);
iz = Math.round(p0[2] + (p1[2]-p0[2]) * f);
ihw = p0[3] + (p1[3]-p0[3]) * f;
ihh = p0[4] + (p1[4]-p0[4]) * f;
ellipseAt(ix, iy, iz, ihw, ihh);
}
}
// ---------- 5. HEAD DETAIL: flat crown, smiling mouth, eyes ----------
// flatten the top of the head a little (axolotls are flat-headed)
var hx, hz;
for (hx = 18; hx <= 30; hx++)
for (hz = 27; hz <= 41; hz++){
if ((hx-24)*(hx-24)/49 + (hz-34)*(hz-34)/49 <= 1.0) pb(hx, 16, hz, 'air');
}
// wide smiling mouth: a dark seam that curves up at the corners
var mz, mx, my;
for (mz = 28; mz <= 40; mz++){
mx = 17 + Math.round(Math.abs(mz - 34) * 0.55);
my = 11 + ((Math.abs(mz - 34) > 4) ? 1 : 0);
pb(mx, my, mz, 'purple_terracotta');
pb(mx + 1, my, mz, 'purple_terracotta');
}
// eyes: small black dots set wide on the flat head
pb(21, 14, 30, 'black_concrete'); pb(21, 14, 38, 'black_concrete');
pb(21, 15, 30, 'pink_terracotta'); pb(21, 15, 38, 'pink_terracotta');
// nostrils
pb(17, 13, 33, 'purple_terracotta'); pb(17, 13, 35, 'purple_terracotta');
// ---------- 6. GILLS: three feathery branches per side ----------
function gill(bx, bz, dirZ, lift, len){
var i, gx, gy, gz;
for (i = 0; i <= len; i++){
gx = bx - Math.round(i * 0.55);
gy = 13 + Math.round(i * lift);
gz = bz + dirZ * i;
pb(gx, gy, gz, 'magenta_wool');
pb(gx, gy + 1, gz, 'magenta_wool');
if (i > len - 4){
// feathery tips
pb(gx, gy + 2, gz, 'pink_wool');
pb(gx - 1, gy + 1, gz + dirZ, 'pink_wool');
pb(gx + 1, gy + 1, gz + dirZ, 'magenta_wool');
pb(gx, gy, gz + dirZ, 'pink_wool');
}
}
// stalk root blends into the neck
pb(bx + 1, 13, bz, 'magenta_wool');
}
gill(31, 40, 1, 0.45, 7);
gill(33, 40, 1, 0.30, 8);
gill(35, 40, 1, 0.15, 7);
gill(31, 28, -1, 0.45, 7);
gill(33, 28, -1, 0.30, 8);
gill(35, 28, -1, 0.15, 7);
// ---------- 7. LEGS with four toes ----------
function leg(lx, lz, dirZ){
var i, j;
for (i = 0; i < 4; i++){
// upper leg, angled outwards and down
pb(lx, 11 - i, lz + dirZ * i, 'pink_concrete');
pb(lx + 1, 11 - i, lz + dirZ * i, 'pink_terracotta');
}
// foot pad
for (i = -1; i <= 1; i++)
for (j = 0; j <= 1; j++)
pb(lx + i, 8, lz + dirZ * (3 + j), 'pink_terracotta');
// four toes
for (i = -1; i <= 2; i++) pb(lx + i, 8, lz + dirZ * 5, 'pink_concrete');
}
leg(35, 39, 1);
leg(35, 29, -1);
leg(48, 40, 1);
leg(48, 30, -1);
// ---------- 8. TAIL FIN CREST ----------
var ti2, tp, cx3, cz3, cy3;
for (ti2 = 9; ti2 < spine.length; ti2++){
tp = spine[ti2];
cx3 = tp[0]; cz3 = tp[2];
for (cy3 = 0; cy3 < 3; cy3++){
pb(cx3, 12 + Math.ceil(tp[4]) + cy3, cz3, (cy3 === 2) ? 'pink_wool' : 'pink_concrete');
pb(cx3, 12 - Math.ceil(tp[4]) - cy3, cz3, (cy3 === 2) ? 'pink_wool' : 'pink_concrete');
}
}
// ---------- 9. CAVERN WALLS, DRIPSTONE, GLOWING ALGAE ----------
// back wall of limestone to the north
var bx2, by2, bz2, h2;
for (bx2 = 8; bx2 <= 88; bx2++){
h2 = 12 + Math.round(noise2d('perlin', bx2, 0, {freq:0.08, seed:5}) * 14);
for (bz2 = 8; bz2 <= 16; bz2++){
for (by2 = padY - 2; by2 <= h2 - (bz2 - 8); by2++){
pb(bx2, by2, bz2, (((bx2 + by2 + bz2) % 5) === 0) ? 'dripstone_block' : ((((bx2 * 2 + by2) % 3) === 0) ? 'calcite' : 'tuff'));
}
}
}
// stalagmites / stalactite columns around the scene
function column(cx, cz, top){
var y, r;
for (y = padY; y <= top; y++){
r = Math.max(0, Math.round(3 - (y - padY) * 0.18));
var ax, az;
for (ax = -r; ax <= r; ax++)
for (az = -r; az <= r; az++)
if (ax*ax + az*az <= r*r + 1) pb(cx + ax, y, cz + az, (((y + ax + az) % 4) === 0) ? 'calcite' : 'dripstone_block');
}
ps(cx, top + 1, cz, 'pointed_dripstone[thickness=tip,vertical_direction=up]');
}
column(14, 24, 24); column(80, 26, 22); column(78, 60, 19); column(20, 66, 17); column(88, 40, 20);
// glowing algae patches on wet rock + moss
var ax2, az2, nv2;
for (ax2 = 10; ax2 <= 90; ax2++)
for (az2 = 10; az2 <= 78; az2++){
nv2 = noise2d('perlin', ax2, az2, {freq:0.13, seed:27});
if (nv2 > 0.86 && !poolMask(ax2, az2)) pb(ax2, padY + 1, az2, 'moss_carpet');
if (nv2 < 0.08 && !poolMask(ax2, az2)) pb(ax2, padY + 1, az2, 'glow_lichen[down=true]');
}
// lily-pad style algae mats floating at the pool edge
var lm;
for (lm = 0; lm < 26; lm++){
var lx2 = 34 + ((lm * 13) % 44), lz2 = 46 + ((lm * 7) % 26);
if (poolMask(lx2, lz2)) pb(lx2, waterY + 1, lz2, 'lily_pad');
}