← Back to Gallery

Loading 3D viewer…

Northern Thai teak stilt house (indexed)

by Jorge Barbero

Dimensions
64×48×64
Blocks
70,234
Compute Time
13.3s
Generation Time
3m 21s
Edits
1
Model
claude-opus-5
Created
August 31, 2026
autoevalindexedhousesthaistilt
Prompt

User Prompt

a traditional northern Thai teak stilt house on a river bank: the living floor raised on tall round teak posts above shallow water, an open plank veranda at the front reached by a broad exterior wooden staircase from the ground, dark teak plank walls, a steep gabled roof of red-brown clay tiles with crossed carved gable finials (kalae), shuttered windows, and a furnished interior room with mats, a low table and hanging lanterns

Enhanced Prompt

INDEXED arm: prepare_build + search_docs({action:"related"}) which anchored on "Steep Cross-Gable Roof" + "Gable Roof Prelude Helpers", then read shape-techniques/Gable Roofs (placeGableRoof/NS) and shape-techniques/Flat Wall Syndrome Solutions. Independent design from scratch: L cross-gable, veranda wing cantilevered over the water, west entry porch.

Photos

El sitio
El sitioexterior
Escalera y fachada
Escalera y fachadaexterior
Sala
Salainterior
Dormitorio
Dormitoriointerior
CraftScript Source
// === BUILD PLAN ===
// Style: Lanna (northern Thai) teak stilt house — CROSS-GABLE (related-graph anchor)
// Footprint: L / cross plan. Enclosed body 12x12 (x22..33, z22..33) + OPEN roofed veranda wing
//   9x7 (x34..42, z25..31) cantilevered EAST over the river + west entry porch (x20..21, z25..29).
// Height: posts (bed/bank Y~9 -> deck Y18), walls Y19..23, main ridge Y29, wing ridge Y24, kalae Y32.
//
// SITE (top-down, X increases east):
//   x  2..27  west bank, flat pad Y11 (yard, stair foot)
//   x 28..33  bank slope -> shallow water
//   x 33..57  river channel (meander, N-S)
//
// LIVING FLOOR:
//   x:  20 22        33 34      42
//   z22     ############
//   z25 pp  #  shrine   #=======#      p entry porch, = open veranda wing (no walls)
//   z27 pS==D  low tbl  #  jars  #      S = stair head, D = door in west wall
//   z29 pp  #  |partition|=======#
//   z33     ############
//
// WEST ELEVATION:            EAST (river) ELEVATION:
//     /\  kalae                    /\ kalae on the wing gable
//    /##\  brick tile             /##\
//   |WpDpW|  p = pilaster        |  ~  | open veranda under the wing gable
//   | || |   round teak posts    | ||| |
//   ~~~~~~~                      ~~~~~~ water
//
// MATERIALS PLAN
//   ground: patches(grass/podzol/coarse_dirt) + gravel shoreline — WHY: calm blotches, organic
//   posts : noisePalette dark_oak_log / stripped_dark_oak_log — WHY: weathered round teak piles
//   walls : gradientPalette dark_oak(bottom)->stripped_dark_oak_wood->spruce(top), noise 0.25
//           — WHY: fakes shadow/soot low + sun-bleached boards high (palette by VOLUME, not random)
//   relief: stripped_oak_log PILASTERS every 4 blocks (+1) + RECESSED windows (-1) + CORNICE of
//           upside-down stairs — the three anti-flat-wall levers from shape-techniques
//   roof  : placeGableRoof / placeGableRoofNS prelude helpers, brick_stairs + brick_slab +
//           terracotta gable fill — WHY: red-brown clay tile; helpers guarantee ridge + END gables
//   accents: spruce trapdoor SHUTTERS (open, flanking), lanterns on chains, decorated pots, bamboo raft
// Rooms: sala (low table, mats, shrine shelf) | partition | sleeping alcove (bed, chest, loom)
// STAIR PLAN: yard walk Y12 -> deck walk Y19, delta 7 -> staircase(14,27,12,19,"east"), 8 cells,
//   lands flush at (21,19,27) on the entry porch; door at x22,z27 straight ahead. Width 3.
// === END PLAN ===

var padY = 11;
var groundWalk = padY + 1;      // 12
var deckY = 18;
var walkY = deckY + 1;          // 19
var wallTopY = walkY + 4;       // 23
var roofBaseY = wallTopY;       // 23
var mainRidgeY = 29;            // 23 + ceil(14/2) - 1
var wingBaseY = 21;

var BX1 = 22, BX2 = 33, BZ1 = 22, BZ2 = 33;   // enclosed body
var WX1 = 34, WX2 = 42, WZ1 = 25, WZ2 = 31;   // open veranda wing
var PX1 = 20, PX2 = 21, PZ1 = 25, PZ2 = 29;   // entry porch

// ---------- PALETTES ----------
var wallPal = gradientPalette(walkY, wallTopY, [
    {block:'dark_oak_planks', from:0},
    {block:'stripped_dark_oak_wood', from:0.5},
    {block:'spruce_planks', from:0.85}], {noise:0.25, seed:44});
var postPal = noisePalette([{block:'dark_oak_log',weight:55},{block:'stripped_dark_oak_log',weight:30},{block:'stripped_spruce_log',weight:15}], {seed:8, freq:0.18});
var deckPal = noisePalette([{block:'spruce_planks',weight:50},{block:'dark_oak_planks',weight:30},{block:'stripped_spruce_wood',weight:20}], {seed:66, freq:0.22});

// ---------- 1. SITE ----------
var land = blob(30, 32, 34, {irregularity:0.38, seed:61});
var h0   = hills({base:12, amp:3, scale:0.05, seed:19});
var riv  = river({from:[48,-8], to:[42,72], heightFn:h0, halfWidth:7, widthVar:0.4,
                  bends:2, amplitude:5, seed:31, bank:2, depth:4, bounds:land.bounds});
var gh   = flatten(riv.height, {x0:2, z0:12, x1:26, z1:54}, padY, 7);
var soil = patches([{block:'grass_block',weight:55},{block:'podzol',weight:22},{block:'coarse_dirt',weight:15},{block:'rooted_dirt',weight:8}], 0.05, 12);
var siteMat = function (x, z) {
    if (riv.inChannel(x, z)) return 'sand';
    if (gh(x, z) <= riv.waterY + 1) return 'gravel';
    return soil(x, z);
};
surface(land, gh, siteMat, {sub:'dirt', deep:'stone', depth:5});
checkpoint('SITE');

function gAt(x, z) { var v = Math.floor(gh(x, z)); if (v > deckY - 1) v = deckY - 1; return v; }

// ---------- 2. PILES ----------
var pileList = [];
var ax, az;
for (ax = BX1; ax <= WX2; ax += 3) {
    for (az = BZ1; az <= BZ2; az += 3) {
        if (ax > BX2 && (az < WZ1 || az > WZ2)) continue;
        pileList.push([ax, az]);
    }
}
pileList.push([BX2, BZ2]); pileList.push([WX2, WZ1]); pileList.push([WX2, WZ2]);
pileList.push([PX1, PZ1]); pileList.push([PX1, PZ2]);
var i, px, pz;
for (i = 0; i < pileList.length; i++) {
    px = pileList[i][0]; pz = pileList[i][1];
    fill(px, gAt(px, pz), pz, px, deckY - 1, pz, postPal);
}
// sill beams under the deck (nothing floats, structure reads)
for (az = BZ1; az <= BZ2; az += 3) fill(BX1, deckY - 1, az, WX2, deckY - 1, az, 'spruce_log[axis=x]');
for (ax = BX1; ax <= WX2; ax += 3) fill(ax, deckY - 2, BZ1, ax, deckY - 2, BZ2, 'spruce_log[axis=z]');
checkpoint('PILES');

// ---------- 3. DECK ----------
fill(BX1, deckY, BZ1, BX2, deckY, BZ2, deckPal);
fill(WX1, deckY, WZ1, WX2, deckY, WZ2, deckPal);
fill(PX1, deckY, PZ1, PX2, deckY, PZ2, deckPal);
// fascia board round the whole deck edge (relief under the floor line)
for (az = BZ1 - 1; az <= BZ2 + 1; az++) ps(BX1 - 3, deckY, az, 'air');
for (az = BZ1; az <= BZ2; az++) { ps(BX1 - 1, deckY, az, 'spruce_slab[type=top]'); }
for (ax = BX1; ax <= WX2; ax++) { ps(ax, deckY, BZ1 - 1, 'spruce_slab[type=top]'); ps(ax, deckY, BZ2 + 1, 'spruce_slab[type=top]'); }
for (az = WZ1; az <= WZ2; az++) ps(WX2 + 1, deckY, az, 'spruce_slab[type=top]');
checkpoint('DECK');

// ---------- 4. WALLS + ANTI-FLAT RELIEF ----------
makeWalls(BX1, walkY, BZ1, BX2, wallTopY, BZ2, wallPal);
// PILASTERS every 4 blocks, protruding +1 (shape-techniques anti-flat #1)
var pilZ = [25, 29, 33], pilX = [25, 29, 33];
for (i = 0; i < pilZ.length; i++) {
    fill(BX1 - 1, walkY, pilZ[i], BX1 - 1, wallTopY, pilZ[i], 'stripped_oak_log');
}
for (i = 0; i < pilX.length; i++) {
    fill(pilX[i], walkY, BZ1 - 1, pilX[i], wallTopY, BZ1 - 1, 'stripped_oak_log');
    fill(pilX[i], walkY, BZ2 + 1, pilX[i], wallTopY, BZ2 + 1, 'stripped_oak_log');
}
// corner posts
fill(BX1, walkY, BZ1, BX1, wallTopY, BZ1, 'dark_oak_log');
fill(BX2, walkY, BZ1, BX2, wallTopY, BZ1, 'dark_oak_log');
fill(BX1, walkY, BZ2, BX1, wallTopY, BZ2, 'dark_oak_log');
fill(BX2, walkY, BZ2, BX2, wallTopY, BZ2, 'dark_oak_log');
// CORNICE: upside-down stairs at the roofline, all four sides (+1 protrusion)
for (az = BZ1 - 1; az <= BZ2 + 1; az++) {
    ps(BX1 - 1, wallTopY, az, 'spruce_stairs[facing=east,half=top]');
    ps(BX2 + 1, wallTopY, az, 'spruce_stairs[facing=west,half=top]');
}
for (ax = BX1 - 1; ax <= BX2 + 1; ax++) {
    ps(ax, wallTopY, BZ1 - 1, 'spruce_stairs[facing=south,half=top]');
    ps(ax, wallTopY, BZ2 + 1, 'spruce_stairs[facing=north,half=top]');
}
checkpoint('WALLS');

// ---------- 5. RECESSED SHUTTERED WINDOWS + DOOR ----------
// window = opening 1x2, sill stair out, SHUTTER trapdoors open on both flanks
function shuttered(wx, wy, wz, axis, outDx, outDz, shutFace) {
    fill(wx, wy, wz, wx, wy + 1, wz, 'air');
    ps(wx + outDx, wy - 1, wz + outDz, 'spruce_stairs[facing=' + shutFace + ',half=bottom]'); // sill
    if (axis === 'z') {
        ps(wx, wy, wz - 1, 'spruce_trapdoor[facing=north,half=bottom,open=true]');
        ps(wx, wy, wz + 1, 'spruce_trapdoor[facing=south,half=bottom,open=true]');
    } else {
        ps(wx - 1, wy, wz, 'spruce_trapdoor[facing=west,half=bottom,open=true]');
        ps(wx + 1, wy, wz, 'spruce_trapdoor[facing=east,half=bottom,open=true]');
    }
}
shuttered(BX1, walkY + 1, 24, 'z', -1, 0, 'west');
shuttered(BX1, walkY + 1, 31, 'z', -1, 0, 'west');
shuttered(BX2, walkY + 1, 24, 'z', 1, 0, 'east');
shuttered(BX2, walkY + 1, 28, 'z', 1, 0, 'east');
shuttered(24, walkY + 1, BZ1, 'x', 0, -1, 'north');
shuttered(31, walkY + 1, BZ1, 'x', 0, -1, 'north');
shuttered(24, walkY + 1, BZ2, 'x', 0, 1, 'south');
shuttered(31, walkY + 1, BZ2, 'x', 0, 1, 'south');
// door in the west wall, straight off the stair head
fill(BX1, walkY, 27, BX1, walkY + 1, 27, 'air');
ps(BX1, walkY, 27, 'spruce_door[facing=east,half=lower,hinge=left,open=false]');
ps(BX1, walkY + 1, 27, 'spruce_door[facing=east,half=upper,hinge=left,open=false]');
// wide opening from the sala onto the veranda wing (east wall)
fill(BX2, walkY, 27, BX2, walkY + 2, 29, 'air');
pb(BX2, walkY + 3, 27, 'dark_oak_log'); pb(BX2, walkY + 3, 29, 'dark_oak_log');
checkpoint('OPENINGS');

// ---------- 6. ROOFS — prelude gable helpers (no hand-rolled loop) ----------
placeGableRoof(BX1, BX2, BZ1, BZ2, roofBaseY, 'brick_stairs', 'brick_slab', 'terracotta');
placeGableRoofNS(WX1, WX2, WZ1, WZ2, wingBaseY, 'brick_stairs', 'brick_slab', 'terracotta');
// veranda wing posts carry its roof
var wingPosts = [[WX1, WZ1],[WX1, WZ2],[WX2, WZ1],[WX2, WZ2],[38, WZ1],[38, WZ2]];
for (i = 0; i < wingPosts.length; i++) {
    fill(wingPosts[i][0], walkY, wingPosts[i][1], wingPosts[i][0], wingBaseY - 1, wingPosts[i][1], 'dark_oak_log');
}
// close the cross-gable junction so no sky slips between the two roofs
fill(WX1 - 1, wingBaseY, WZ1, WX1 - 1, roofBaseY, WZ2, 'terracotta');
// KALAE crossed finials: both main gable ends + the river-facing wing gable
function kalae(cx, cy, cz, alongZ) {
    var d;
    for (d = 1; d <= 3; d++) {
        if (alongZ) {
            pb(cx - d, cy + d, cz, 'stripped_spruce_log[axis=y]');
            pb(cx + d + 1, cy + d, cz, 'stripped_spruce_log[axis=y]');
        } else {
            pb(cx, cy + d, cz - d, 'stripped_spruce_log[axis=y]');
            pb(cx, cy + d, cz + d + 1, 'stripped_spruce_log[axis=y]');
        }
    }
}
kalae(27, mainRidgeY, BZ1 - 1, true);
kalae(27, mainRidgeY, BZ2 + 1, true);
kalae(WX2 + 1, wingBaseY + 3, 27, false);
checkpoint('ROOF');

// ---------- 7. INTERIOR: sala + partition + sleeping alcove ----------
// ridge/ceiling beams (lantern anchors)
for (az = 24; az <= 32; az += 4) fill(BX1 + 1, wallTopY, az, BX2 - 1, wallTopY, az, 'stripped_spruce_log[axis=x]');
// woven partition with a doorway
fill(24, walkY, 30, 32, walkY + 2, 30, 'bamboo_planks');
fill(27, walkY, 30, 28, walkY + 1, 30, 'air');
// floor mats in the sala
rug(24, walkY, 24, 6, 5, 'red', 'brown');
// low table + cushions
pb(27, walkY, 26, 'dark_oak_fence'); pb(27, walkY + 1, 26, 'dark_oak_pressure_plate');
pb(28, walkY, 26, 'dark_oak_fence'); pb(28, walkY + 1, 26, 'dark_oak_pressure_plate');
pb(26, walkY, 26, 'orange_carpet'); pb(29, walkY, 26, 'orange_carpet');
pb(27, walkY, 25, 'orange_carpet'); pb(28, walkY, 27, 'orange_carpet');
// shrine shelf on the north wall
ps(26, walkY + 2, BZ1 + 1, 'spruce_slab[type=top]');
ps(27, walkY + 2, BZ1 + 1, 'spruce_slab[type=top]');
pb(26, walkY + 3, BZ1 + 1, 'flower_pot');
ps(27, walkY + 3, BZ1 + 1, 'candle[candles=3,lit=true]');
// water jars + basin by the door
ps(23, walkY, 26, 'decorated_pot');
ps(23, walkY, 28, 'water_cauldron[level=3]');
// sleeping alcove behind the partition
placeBed(25, walkY, 32, 'white', 'north');
pb(24, walkY, 32, 'spruce_fence'); pb(24, walkY + 1, 32, 'oak_pressure_plate'); pb(24, walkY + 2, 32, 'lantern');
pb(31, walkY, 32, 'chest[facing=west]');
ps(31, walkY, 31, 'loom[facing=west]');
ps(29, walkY, 32, 'barrel[facing=up]');
// hanging lanterns from the beams
var lan = [[25, 24],[30, 24],[26, 28],[30, 32]];
for (i = 0; i < lan.length; i++) {
    ps(lan[i][0], wallTopY - 1, lan[i][1], 'chain[axis=y]');
    ps(lan[i][0], wallTopY - 2, lan[i][1], 'lantern[hanging=true]');
}
checkpoint('INTERIOR');

// ---------- 8. VERANDA WING + PORCH + STAIR ----------
// railing round the open wing, gap where it meets the house
for (ax = WX1; ax <= WX2; ax++) { pb(ax, walkY, WZ1, 'dark_oak_fence'); pb(ax, walkY, WZ2, 'dark_oak_fence'); }
for (az = WZ1; az <= WZ2; az++) pb(WX2, walkY, az, 'dark_oak_fence');
fill(WX1, walkY, 27, WX1, walkY, 29, 'air');
// wing furniture: stools facing the river, water jars, drying rack
chairStair(40, walkY, 26, 'spruce_stairs', 'south');
chairStair(40, walkY, 30, 'spruce_stairs', 'north');
ps(36, walkY, 26, 'decorated_pot');
ps(36, walkY, 30, 'decorated_pot');
pb(38, walkY, 28, 'spruce_fence'); pb(38, walkY + 1, 28, 'spruce_pressure_plate');
ps(41, wingBaseY - 1, 28, 'chain[axis=y]'); ps(41, wingBaseY - 2, 28, 'lantern[hanging=true]');
ps(35, wingBaseY - 1, 28, 'chain[axis=y]'); ps(35, wingBaseY - 2, 28, 'lantern[hanging=true]');
// entry porch railing + broad stair up from the yard
for (az = PZ1; az <= PZ2; az++) { if (az < 26 || az > 28) pb(PX1, walkY, az, 'dark_oak_fence'); }
pb(PX1, walkY, PZ1, 'dark_oak_fence'); pb(PX2, walkY, PZ1, 'dark_oak_fence');
pb(PX1, walkY, PZ2, 'dark_oak_fence'); pb(PX2, walkY, PZ2, 'dark_oak_fence');
var top = staircase(14, 27, groundWalk, walkY, 'east', {width:3, material:'dark_oak_stairs', rail:true, support:'dark_oak_log'});
checkpoint('VERANDA_STAIR');

// ---------- 9. UNDER-HOUSE + SHORE ----------
var uy = gAt(24, 26) + 1;
ps(24, uy, 25, 'barrel[facing=up]'); ps(25, uy, 25, 'barrel[facing=up]'); ps(24, uy + 1, 25, 'barrel[facing=up]');
fill(23, uy, 31, 24, uy + 1, 32, 'stripped_spruce_log[axis=x]');   // woodpile
ps(26, uy, 32, 'cauldron[level=0]');
// yard path + lamp posts (lampPost(x, y, z, height, postId))
var bx, bz, py;
for (bx = 6; bx <= 13; bx++) {
    for (bz = 26; bz <= 28; bz++) {
        py = Math.floor(gh(bx, bz));
        pb(bx, py, bz, (bz === 27) ? 'gravel' : 'coarse_dirt');
    }
}
lampPost(13, Math.floor(gh(13, 24)) + 1, 24, 4, 'spruce_fence');
lampPost(13, Math.floor(gh(13, 31)) + 1, 31, 4, 'spruce_fence');
// fence along the yard
for (bz = 20; bz <= 36; bz += 2) pb(8, Math.floor(gh(8, bz)) + 1, bz, 'spruce_fence');
// bamboo raft moored under the veranda wing
for (bx = 44; bx <= 49; bx++) for (bz = 27; bz <= 28; bz++) pb(bx, riv.waterY, bz, 'bamboo_mosaic');
pb(49, riv.waterY + 1, 27, 'bamboo_fence');
// reeds, lilies, bamboo clumps, jungle trees
var sx, sz, gy2;
for (sx = 4; sx <= 58; sx++) {
    for (sz = 8; sz <= 56; sz++) {
        gy2 = Math.floor(gh(sx, sz));
        if (!riv.inChannel(sx, sz) && gy2 === riv.waterY && (sx * 5 + sz * 3) % 9 === 0) {
            fill(sx, gy2 + 1, sz, sx, gy2 + 1 + ((sx + sz) % 3), sz, 'sugar_cane');
        }
        if (riv.inChannel(sx, sz) && (sx * 7 + sz * 11) % 29 === 0) pb(sx, riv.waterY + 1, sz, 'lily_pad');
    }
}
var clumps = [[18, 20],[16, 23],[19, 35],[17, 38],[30, 16],[34, 44],[10, 40],[12, 17]];
for (i = 0; i < clumps.length; i++) {
    sx = clumps[i][0]; sz = clumps[i][1]; gy2 = Math.floor(gh(sx, sz));
    fill(sx, gy2 + 1, sz, sx, gy2 + 5 + (i % 3), sz, 'bamboo[age=1,leaves=large,stage=0]');
}
placeTree(9, Math.floor(gh(9, 20)) + 1, 20, 'jungle');
placeTree(11, Math.floor(gh(11, 45)) + 1, 45, 'jungle');
placeTree(22, Math.floor(gh(22, 48)) + 1, 48, 'oak');
checkpoint('SHORE');

// ---------- 10. FIX PASS: close the roof sky-holes and the hole in the deck ----------
var fs;
for (fs = 0; fs <= 5; fs++) {
    fill(BX1 + fs, roofBaseY + fs, BZ1, BX2 - fs, roofBaseY + fs, BZ1, 'terracotta');
    fill(BX1 + fs, roofBaseY + fs, BZ2, BX2 - fs, roofBaseY + fs, BZ2, 'terracotta');
}
pb(27, mainRidgeY, BZ1, 'terracotta'); pb(28, mainRidgeY, BZ1, 'terracotta');
pb(27, mainRidgeY, BZ2, 'terracotta'); pb(28, mainRidgeY, BZ2, 'terracotta');
// close the cross-gable junction plane right up to the main roof
fill(WX1 - 1, wingBaseY + 1, WZ1, WX1 - 1, roofBaseY + 3, WZ2, 'terracotta');
// re-lay the living floor and the veranda deck (a hole had opened through them)
fill(BX1, deckY, BZ1, BX2, deckY, BZ2, deckPal);
fill(WX1, deckY, WZ1, WX2, deckY, WZ2, deckPal);
checkpoint('FIX');

Static Renders

Northern Thai teak stilt house (indexed) isometric viewisometric
Northern Thai teak stilt house (indexed) front viewfront
Northern Thai teak stilt house (indexed) side viewside
Northern Thai teak stilt house (indexed) back viewback
Northern Thai teak stilt house (indexed) top viewtop