Skip to content
Kiln1.3Get Kiln

Rebuilt modular cabin with an open living and dining area, bedroom, supplies, open kitchen, porch and side work exit.

Cabin in the Woods: PSX Horror pack
Rebuilt modular cabin with an open living and dining area, bedroom, supplies, open kitchen, porch and side work exit.

Drag to orbit after opening. The model starts stationary.

For your engine. The download is a standard glTF 2.0 binary (GLB) with PBR metallic-roughness materials. glTF stores materials, not lighting or tone mapping, so your engine decides how they read. This 3D view tone-maps with Review Neutral, the Khronos PBR Neutral construction with a smaller glare offset (0.015 instead of 0.04), at exposure 0.9. Its Tone mapping control also shows ACES and Linear, for comparison.

Triangles
29,384
Meshes
75
Materials
6
Dimensions (m)
12.47 × 4.77 × 13.92

Runtime assets

Models, textures and animations prepared for use in a scene or application.

313,176 bytes (0.31 MB)

Download runtime assets

Full Kiln assets (remixable)

Models plus Kiln source, editing metadata, materials and included revisions, so you can reopen and continue editing.

566,314 bytes (0.57 MB)

Download full kiln assets (remixable)

Runtime includes the GLB and metadata sidecar. The editable ZIP contains this selected revision and its complete material closure. Parent revision identifiers are retained; earlier authoring history is deliberately not distributed in this initial pack.

Import this ZIP into Kiln’s Library, or run node kiln.mjs import asset.zip in an authoring workspace. The full model, exact source, editing metadata, preview and material resources are included so you can reopen and remix it.

Use an importing Kiln build that supports the included material schemas. Use Kiln 1.2.3 or later.

Collection / asset / revision
project / a_e6f6a8a0c4eb465584fe448b8b17f103 / r_c27b7f2836c14fd898a0d82f83b741a3
Source SHA-256
9d5988dbb3c664bba03827aac86e60beaa0583e0ddbfea6ec132d69c2bbe2b8c
Open living cabin (12 x 10 m): exact saved source
const meta={name:'Nightman cabin layout v2',role:'building'};
const MATERIALS={"tx01":{"schemaVersion":3,"model":"pbrMetallicRoughness","name":"Weathered cabin timber","baseColor":16777215,"roughness":1,"metalness":0,"emissiveIntensity":1,"alphaMode":"opaque","alphaCutoff":0.5,"doubleSided":false,"textures":{"baseColor":{"kind":"resource","resourceId":"kiln.library.87c9fe1286e32442ed5e29c42b5c05cf88ac5b509260b95ce755bcbd0e3cb8ea.base-color","sampler":{"minFilter":"nearest-mipmap-linear","magFilter":"nearest","wrapS":"repeat","wrapT":"repeat"}}}},"tx02":{"schemaVersion":3,"model":"pbrMetallicRoughness","name":"Warm interior boards","baseColor":16777215,"roughness":1,"metalness":0,"emissiveIntensity":1,"alphaMode":"opaque","alphaCutoff":0.5,"doubleSided":false,"textures":{"baseColor":{"kind":"resource","resourceId":"kiln.library.d86eb2087a7bd4edbe734e603bc6b8180220e751bc0e5244d80c696b566dfc26.base-color","sampler":{"minFilter":"nearest-mipmap-linear","magFilter":"nearest","wrapS":"repeat","wrapT":"repeat"}}}},"tx04":{"schemaVersion":3,"model":"pbrMetallicRoughness","name":"Cut endgrain","baseColor":16777215,"roughness":1,"metalness":0,"emissiveIntensity":1,"alphaMode":"opaque","alphaCutoff":0.5,"doubleSided":false,"textures":{"baseColor":{"kind":"resource","resourceId":"kiln.library.2dadd9f8f02157fcab7add4c237598d8358b2c65babbd07830c653791bad128d.base-color","sampler":{"minFilter":"nearest-mipmap-linear","magFilter":"nearest","wrapS":"repeat","wrapT":"repeat"}}}},"tx06":{"schemaVersion":3,"model":"pbrMetallicRoughness","name":"Dark wooden shingles","baseColor":16777215,"roughness":1,"metalness":0,"emissiveIntensity":1,"alphaMode":"opaque","alphaCutoff":0.5,"doubleSided":false,"textures":{"baseColor":{"kind":"resource","resourceId":"kiln.library.f20b5106a73407a176c1f38ddda6062c1a78c33e306535631e2a187620d9f26f.base-color","sampler":{"minFilter":"nearest-mipmap-linear","magFilter":"nearest","wrapS":"repeat","wrapT":"repeat"}}}},"tx08":{"schemaVersion":3,"model":"pbrMetallicRoughness","name":"Worn iron","baseColor":16777215,"roughness":0.85,"metalness":0.25,"emissiveIntensity":1,"alphaMode":"opaque","alphaCutoff":0.5,"doubleSided":false,"textures":{"baseColor":{"kind":"resource","resourceId":"kiln.library.1870a95ffec8e00bc9daac56a32bc537547e002305e373c4ff7a97f098119fbe.base-color","sampler":{"minFilter":"nearest-mipmap-linear","magFilter":"nearest","wrapS":"repeat","wrapT":"repeat"}}}},"tx07":{"schemaVersion":3,"model":"pbrMetallicRoughness","name":"Worn hearth masonry","baseColor":16777215,"roughness":1,"metalness":0,"emissiveIntensity":1,"alphaMode":"opaque","alphaCutoff":0.5,"doubleSided":false,"textures":{"baseColor":{"kind":"resource","resourceId":"kiln.library.75cd799a82ee1e2adcc33546078e15674a0904084bed28da638083976009b535.base-color","sampler":{"minFilter":"nearest-mipmap-linear","magFilter":"nearest","wrapS":"repeat","wrapT":"repeat"}}}}};
const CONTRACT={"version":"nightman.cabin-structure-v2.proposed-interface","approvedPlanSha256":"sha256:c7c37cb382c0923e71485164d7e37d033ed731ad3b9e96f22ab6a5d2bdb4991c","frame":"[X,Y,Z]=[v-5,Y,u-6], +X front","nominalFootprint":{"minX":-5,"maxX":5,"minZ":-6,"maxZ":6,"floorTopY":0,"wallThickness":0.2,"wallHeight":2.8},"porch":{"plan":{"u":0,"v":10,"w":8,"d":2},"worldBounds":{"minX":5,"maxX":7,"minZ":-6,"maxZ":2},"floorTopY":0},"rooms":[{"id":"living","name":"Open living / dining","u":0,"v":0,"w":8,"d":10,"note":"No living-room partition. Direct views across hearth, table, TV and entry."},{"id":"bedroom","name":"Bedroom","u":8,"v":0,"w":4,"d":4,"clear":"3.7 × 3.7 m"},{"id":"supply","name":"Tools / supplies","u":8,"v":4,"w":4,"d":3,"clear":"3.7 × 2.8 m"},{"id":"kitchen","name":"Open kitchen nook","u":8,"v":7,"w":4,"d":3,"note":"Open edge to living area; no door or full partition."}],"clearRooms":{"bedroom":{"u":[8.1,11.8],"v":[0.2,3.9],"size":[3.7,3.7]},"supply":{"u":[8.1,11.8],"v":[4.1,6.9],"size":[3.7,2.8]},"living":"No central partition; 8m nominal side width"},"doors":[{"name":"front_door_mount","translation":[4.9,0,0.04999999999999982],"rotation":[0,0,0,1],"scale":[1,1,1],"id":"D1","doorKey":"door","doorOpenAngleDegrees":-95,"hingeVariant":"as-authored-left/start-edge; no mirroring","swingSide":"inward","planOpeningStart":[5.5,10],"clearOpening":{"width":1.1,"height":2.2},"roughOpening":{"width":1.24,"height":2.32},"assetFrontSide":"outward/approach-facing","assetKey":"door","key":"D1","openAngleDegrees":-95},{"name":"bedroom_door_mount","translation":[-2,0,2],"rotation":[0,0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"D2","doorKey":"interiorDoor","doorOpenAngleDegrees":-95,"hingeVariant":"as-authored-left/start-edge; no mirroring","swingSide":"inward","planOpeningStart":[8,2.5],"clearOpening":{"width":1,"height":2.2},"roughOpening":{"width":1.12,"height":2.3},"assetFrontSide":"outward/approach-facing","assetKey":"interiorDoor","key":"D2","openAngleDegrees":-95},{"name":"utility_door_mount","translation":[0.8499999999999996,0,2],"rotation":[0,0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"D3","doorKey":"interiorDoor","doorOpenAngleDegrees":-95,"hingeVariant":"as-authored-left/start-edge; no mirroring","swingSide":"inward","planOpeningStart":[8,5.35],"clearOpening":{"width":1,"height":2.2},"roughOpening":{"width":1.12,"height":2.3},"assetFrontSide":"outward/approach-facing","assetKey":"interiorDoor","key":"D3","openAngleDegrees":-95},{"name":"workyard_door_mount","translation":[0.6499999999999995,0,5.9],"rotation":[0,0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"D4","doorKey":"door","doorOpenAngleDegrees":-95,"hingeVariant":"as-authored-left/start-edge; no mirroring","swingSide":"outward into yard","planOpeningStart":[12,5.1],"clearOpening":{"width":1.1,"height":2.2},"roughOpening":{"width":1.24,"height":2.32},"assetFrontSide":"supply-room-facing; decorative brace faces yard","assetKey":"door","key":"D4","openAngleDegrees":-95}],"windows":[{"name":"window_w1_mount","translation":[-4.9,0.95,-3.1999999999999997],"rotation":[0,1,0,6.123233995736766e-17],"scale":[1,1,1],"id":"W1","room":"living","planOpeningStart":[2.2,0],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"window_w2_mount","translation":[-4.9,0.95,3.9000000000000004],"rotation":[0,1,0,6.123233995736766e-17],"scale":[1,1,1],"id":"W2","room":"bedroom","planOpeningStart":[9.3,0],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"window_w3_mount","translation":[-2.8,0.95,5.9],"rotation":[0,-0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"W3","room":"bedroom","planOpeningStart":[12,1.6],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"window_w4_mount","translation":[-2.6,0.95,-5.9],"rotation":[0,0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"W4","room":"living","planOpeningStart":[0,1.8],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"window_w5_mount","translation":[3.0999999999999996,0.95,-5.9],"rotation":[0,0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"W5","room":"living","planOpeningStart":[0,7.5],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"window_w6_mount","translation":[4.9,0.95,-3.1999999999999997],"rotation":[0,0,0,1],"scale":[1,1,1],"id":"W6","room":"living","planOpeningStart":[2.2,10],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"window_w7_mount","translation":[4.9,0.95,3.9000000000000004],"rotation":[0,0,0,1],"scale":[1,1,1],"id":"W7","room":"kitchen","planOpeningStart":[9.3,10],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]}],"sockets":[{"name":"front_door_mount","translation":[4.9,0,0.04999999999999982],"rotation":[0,0,0,1],"scale":[1,1,1],"id":"D1","doorKey":"door","doorOpenAngleDegrees":-95,"hingeVariant":"as-authored-left/start-edge; no mirroring","swingSide":"inward","planOpeningStart":[5.5,10],"clearOpening":{"width":1.1,"height":2.2},"roughOpening":{"width":1.24,"height":2.32},"assetFrontSide":"outward/approach-facing","assetKey":"door","key":"D1","openAngleDegrees":-95},{"name":"bedroom_door_mount","translation":[-2,0,2],"rotation":[0,0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"D2","doorKey":"interiorDoor","doorOpenAngleDegrees":-95,"hingeVariant":"as-authored-left/start-edge; no mirroring","swingSide":"inward","planOpeningStart":[8,2.5],"clearOpening":{"width":1,"height":2.2},"roughOpening":{"width":1.12,"height":2.3},"assetFrontSide":"outward/approach-facing","assetKey":"interiorDoor","key":"D2","openAngleDegrees":-95},{"name":"utility_door_mount","translation":[0.8499999999999996,0,2],"rotation":[0,0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"D3","doorKey":"interiorDoor","doorOpenAngleDegrees":-95,"hingeVariant":"as-authored-left/start-edge; no mirroring","swingSide":"inward","planOpeningStart":[8,5.35],"clearOpening":{"width":1,"height":2.2},"roughOpening":{"width":1.12,"height":2.3},"assetFrontSide":"outward/approach-facing","assetKey":"interiorDoor","key":"D3","openAngleDegrees":-95},{"name":"workyard_door_mount","translation":[0.6499999999999995,0,5.9],"rotation":[0,0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"D4","doorKey":"door","doorOpenAngleDegrees":-95,"hingeVariant":"as-authored-left/start-edge; no mirroring","swingSide":"outward into yard","planOpeningStart":[12,5.1],"clearOpening":{"width":1.1,"height":2.2},"roughOpening":{"width":1.24,"height":2.32},"assetFrontSide":"supply-room-facing; decorative brace faces yard","assetKey":"door","key":"D4","openAngleDegrees":-95},{"name":"window_w1_mount","translation":[-4.9,0.95,-3.1999999999999997],"rotation":[0,1,0,6.123233995736766e-17],"scale":[1,1,1],"id":"W1","room":"living","planOpeningStart":[2.2,0],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"window_w2_mount","translation":[-4.9,0.95,3.9000000000000004],"rotation":[0,1,0,6.123233995736766e-17],"scale":[1,1,1],"id":"W2","room":"bedroom","planOpeningStart":[9.3,0],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"window_w3_mount","translation":[-2.8,0.95,5.9],"rotation":[0,-0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"W3","room":"bedroom","planOpeningStart":[12,1.6],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"window_w4_mount","translation":[-2.6,0.95,-5.9],"rotation":[0,0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"W4","room":"living","planOpeningStart":[0,1.8],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"window_w5_mount","translation":[3.0999999999999996,0.95,-5.9],"rotation":[0,0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"W5","room":"living","planOpeningStart":[0,7.5],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"window_w6_mount","translation":[4.9,0.95,-3.1999999999999997],"rotation":[0,0,0,1],"scale":[1,1,1],"id":"W6","room":"living","planOpeningStart":[2.2,10],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"window_w7_mount","translation":[4.9,0.95,3.9000000000000004],"rotation":[0,0,0,1],"scale":[1,1,1],"id":"W7","room":"kitchen","planOpeningStart":[9.3,10],"clearOpening":{"width":1.2,"height":1.1,"sill":0.95},"roughOpening":{"width":1.36,"yMin":0.87,"yMax":2.13},"boardNodes":["Board_1","Board_2","Board_3"]},{"name":"hearth_mount","translation":[-0.18,0,-5.37],"rotation":[0,-0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"H1","attachment":"asset-root","planFootprint":{"u":0.25,"v":4.15,"w":0.84,"d":1.34}},{"name":"wall_m1_mount","translation":[-0.17999999999999972,1.55,-5.8],"rotation":[0,-0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"M1","attachmentMarker":"wall_mount","placementMode":"align exported marker to socket","planPoint":[0.14,4.82]},{"name":"wall_m2_mount","translation":[-4.8,1.55,0.7000000000000002],"rotation":[0,0,0,1],"scale":[1,1,1],"id":"M2","attachmentMarker":"wall_mount","placementMode":"align exported marker to socket","planPoint":[6.7,0.14]},{"name":"wall_p1_mount","translation":[-1.7000000000000002,1.55,-5.8],"rotation":[0,-0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"P1","attachmentMarker":"wall_mount","placementMode":"align exported marker to socket","planPoint":[0.14,3.3]},{"name":"wall_p2_mount","translation":[-3.4,1.55,2.1],"rotation":[0,-0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"P2","attachmentMarker":"wall_mount","placementMode":"align exported marker to socket","planPoint":[8.14,1.6]},{"name":"wall_a1_mount","translation":[4.8,1.55,0.9000000000000004],"rotation":[0,1,0,6.123233995736766e-17],"scale":[1,1,1],"id":"A1","attachmentMarker":"wall_mount","placementMode":"align exported marker to socket","planPoint":[6.9,9.85]},{"name":"wall_a2_mount","translation":[-0.9,1.55,3.8499999999999996],"rotation":[0,0,0,1],"scale":[1,1,1],"id":"A2","attachmentMarker":"wall_mount","placementMode":"align exported marker to socket","planPoint":[9.85,4.12]},{"name":"deer_mount","translation":[-0.18,1.55,-5.23],"rotation":[0,-0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"M1-chimney-face","attachmentMarker":"wall_mount","placementMode":"align exported marker to actual hearth chimney front; preferred above-hearth target","planPoint":[0.14,4.82],"physicalAdjustment":"Chimney front at source localX=.14, rather than embedding plaque/head in hearth flue."},{"name":"picture_mount","translation":[-1.7000000000000002,1.55,-5.8],"rotation":[0,-0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"P1","attachmentMarker":"wall_mount","placementMode":"align marker","warning":"Actual picture width must be checked against W4 ending at planv3.0; plan marker is retained."}],"wallDressings":[{"name":"wall_m1_mount","translation":[-0.17999999999999972,1.55,-5.8],"rotation":[0,-0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"M1","attachmentMarker":"wall_mount","placementMode":"align exported marker to socket","planPoint":[0.14,4.82]},{"name":"wall_m2_mount","translation":[-4.8,1.55,0.7000000000000002],"rotation":[0,0,0,1],"scale":[1,1,1],"id":"M2","attachmentMarker":"wall_mount","placementMode":"align exported marker to socket","planPoint":[6.7,0.14]},{"name":"wall_p1_mount","translation":[-1.7000000000000002,1.55,-5.8],"rotation":[0,-0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"P1","attachmentMarker":"wall_mount","placementMode":"align exported marker to socket","planPoint":[0.14,3.3]},{"name":"wall_p2_mount","translation":[-3.4,1.55,2.1],"rotation":[0,-0.7071067811865475,0,0.7071067811865476],"scale":[1,1,1],"id":"P2","attachmentMarker":"wall_mount","placementMode":"align exported marker to socket","planPoint":[8.14,1.6]},{"name":"wall_a1_mount","translation":[4.8,1.55,0.9000000000000004],"rotation":[0,1,0,6.123233995736766e-17],"scale":[1,1,1],"id":"A1","attachmentMarker":"wall_mount","placementMode":"align exported marker to socket","planPoint":[6.9,9.85]},{"name":"wall_a2_mount","translation":[-0.9,1.55,3.8499999999999996],"rotation":[0,0,0,1],"scale":[1,1,1],"id":"A2","attachmentMarker":"wall_mount","placementMode":"align exported marker to socket","planPoint":[9.85,4.12]}],"approvedPlanItems":[{"id":"H1","name":"Stone hearth","u":0.25,"v":4.15,"w":0.84,"d":1.34,"kind":"authored","room":"living","note":"Existing authored footprint, rotated to face into the room. Reserve1.1m in front for feeding and tool clearance; ash/poker dress this area."},{"id":"B1","name":"Hearth bench","u":2.25,"v":4.25,"w":0.42,"d":1.1,"kind":"authored","room":"living","note":"Faces the hearth; benches remain movable dressing and do not choke the route."},{"id":"B2","name":"TV bench","u":1.8,"v":7.4,"w":1.1,"d":0.42,"kind":"authored","room":"living","note":"Second instance of the bench; faces the TV corner."},{"id":"T1","name":"CRT + supporting table","u":0.5,"v":8.9,"w":1.1,"d":0.65,"kind":"authored","room":"living","note":"TV .50×.44m sits on the authored table .78m high. Clock/picture can dress this corner. Keep W5 andW6 approach clear."},{"id":"T2","name":"Dining table","u":4.6,"v":7.1,"w":1.4,"d":0.8,"kind":"planned","room":"living","note":"Target from the asset bible, larger than the current1.1×.65m table. Radio, mugs, food tins and books sit here; no table in the central door route."},{"id":"C1","name":"Dining chair","u":4.7,"v":6.35,"w":0.45,"d":0.5,"kind":"planned","room":"living","note":"Four chairs around the proposed table; final collision and pullback space still need scene review."},{"id":"C2","name":"Dining chair","u":5.4,"v":6.35,"w":0.45,"d":0.5,"kind":"planned","room":"living"},{"id":"C3","name":"Dining chair","u":4.7,"v":8.15,"w":0.45,"d":0.5,"kind":"planned","room":"living"},{"id":"C4","name":"Dining chair","u":5.4,"v":8.15,"w":0.45,"d":0.5,"kind":"planned","room":"living"},{"id":"S1","name":"Single bed","u":9.25,"v":2.85,"w":1.9,"d":1,"kind":"authored","room":"bedroom","note":"Current saved bed footprint rotated across the room. Keeps both window approaches and the door swing clear. Bedding/pillow part of the family; a second bed needs a later co-op layout review."},{"id":"S2","name":"Bedroom cabinet","u":8.25,"v":0.4,"w":0.8,"d":0.45,"kind":"planned","room":"bedroom","note":"Clothes/books and a wall note, clear of the rear window approach."},{"id":"K1","name":"Kitchen worktop","u":11.15,"v":7.6,"w":0.6,"d":2,"kind":"planned","room":"kitchen","note":"Kettle, mugs, bowls, tins and bottles on the side-wall worktop. Keeps the front window boardable. No plumbing/stove mechanic has been committed."},{"id":"K2","name":"Kitchen cupboard","u":8.35,"v":9.2,"w":0.8,"d":0.45,"kind":"planned","room":"kitchen","note":"Food and small props; wall shelf above. Positioned beside the window approach."},{"id":"R1","name":"Indoor firewood rack","u":10.65,"v":6.4,"w":0.915,"d":0.37,"kind":"authored","room":"supply","note":"Close to the exterior work door. Carry wood inside, deposit/withdraw, then bring firewood to the hearth."},{"id":"R2","name":"Plank reserve","u":8.35,"v":6.45,"w":1.5,"d":0.35,"kind":"planned","room":"supply","note":"Separate visible storage for processed boards; clear of both door swings."},{"id":"R3","name":"Supply chest","u":8.45,"v":4.35,"w":0.8,"d":0.45,"kind":"planned","room":"supply","note":"Shells, flashlight batteries and first-aid candidates; contents/loot rules remain open."},{"id":"R4","name":"Tall supply cabinet","u":11.3,"v":4.25,"w":0.45,"d":0.8,"kind":"planned","room":"supply","note":"Loose tool and consumable storage, with wall tool rack beside it."},{"id":"O1","name":"Chopping block","u":14.5,"v":5.2,"w":0.6,"d":0.6,"kind":"authored","room":"yard","note":"Outside, exposed to the woods.2×2m work pad; original supported log and axe contact remain at their authored height."},{"id":"O2","name":"Sawing station","u":13.35,"v":8,"w":1.5,"d":1.01,"kind":"authored","room":"yard","note":"Separate2.8×2.6m pad for operator and saw motion. Use this station for boards."},{"id":"O3","name":"Incoming log pile","u":16,"v":8.5,"w":1.3,"d":0.6,"kind":"planned","room":"yard","note":"Temporary outdoor stock next to the processing route; not a replacement for indoor storage."}],"limits":["These are derived source targets; final interface will be read from actual export.","Plan door/window coordinates denote start edges, not centers.","Structural interior walls are .2m; current interior door frame depth .12m leaves .04m wall reveal on each side, without narrowing its1.0m clear opening.","D4 uses yaw+90 and native -95degrees to preserve plan start-edge hinge and open into yard; its decorative front faces supply."]};
// Original beveled timber section: grain follows each member's long Z axis.
function timberGeo(length,width,height,repeat=1,warp=0,chip=0){
 const bevel=Math.min(width,height)*.16,profile=[[-width/2+bevel,-height/2],[width/2-bevel,-height/2],[width/2,-height/2+bevel],[width/2,height/2-bevel],[width/2-bevel,height/2],[-width/2+bevel,height/2],[-width/2,height/2-bevel],[-width/2,-height/2+bevel]];
 const positions=[],uv=[],indices=[],groups=[];let count=0;
 function face(points,coords,material){const base=count;for(let i=0;i<points.length;i++){positions.push(...points[i]);uv.push(...coords[i]);count++;}for(let j=1;j<points.length-1;j++)indices.push(base,base+j,base+j+1);groups.push({start:indices.length-(points.length-2)*3,count:(points.length-2)*3,materialIndex:material});}
 const z0=-length/2,z1=length/2;const start=i=>z0+((i===0||i===1)?chip:0),finish=i=>z1-((i===4||i===5)?chip*1.3:0);
 for(let i=0;i<8;i++){const a=profile[i],b=profile[(i+1)%8],v=Math.hypot(b[0]-a[0],b[1]-a[1])/repeat;face([[...a,start(i)],[...b,start((i+1)%8)],[b[0]+warp,b[1],finish((i+1)%8)],[a[0]+warp,a[1],finish(i)]],[[0,0],[0,v],[length/repeat,v],[length/repeat,0]],0);}
 face(profile.map((p,i)=>[...p,start(i)]).reverse(),profile.map(p=>[(p[0]+width/2)/.5,(p[1]+height/2)/.5]).reverse(),1);
 face(profile.map((p,i)=>[p[0]+warp,p[1],finish(i)]),profile.map(p=>[(p[0]+width/2)/.5,(p[1]+height/2)/.5]),1);
 const g=new THREE.BufferGeometry();g.setAttribute('position',new THREE.Float32BufferAttribute(positions,3));g.setAttribute('uv',new THREE.Float32BufferAttribute(uv,2));g.setIndex(indices);g.computeVertexNormals();g.addGroup(0,48,0);g.addGroup(48,36,1);return g;
}
function timber(parent,name,L,w,h,wood,end,pos,rotation=[0,0,0],repeat=1,warp=0){const g=timberGeo(L,w,h,repeat,warp,name.includes("Plank")||name.includes("Board")?.025:0);const u=g.getAttribute("uv");let seed=17;for(let k=0;k<name.length;k++)seed=(Math.imul(seed,31)+name.charCodeAt(k))>>>0;seed=Math.imul(seed^(seed>>>16),0x7feb352d)>>>0;seed=Math.imul(seed^(seed>>>15),0x846ca68b)>>>0;seed=(seed^(seed>>>16))>>>0;const phaseU=(seed&255)/256,phaseV=((seed>>>8)&255)/256;for(let j=0;j<Math.min(u.count,32);j++)u.setXY(j,u.getX(j)+phaseU,u.getY(j)+phaseV);const mesh=new THREE.Mesh(g,[wood,end]);mesh.name=name;mesh.position.set(...pos);mesh.rotation.set(...rotation.map(v=>v*Math.PI/180));parent.add(mesh);return mesh;}
function socket(parent,name,xyz){const s=new THREE.Object3D();s.name=name;s.position.set(...xyz);parent.add(s);return s;}

async function surfaces(){const out={};for(const key of Object.keys(MATERIALS))out[key]=await compilePortableMaterialSpecV3(MATERIALS[key]);return out;}
function box(parent,name,size,material,pos){return createPart(name,boxGeo(...size),material,{parent,position:pos});}
function group(parent,name,pos=[0,0,0]){const g=new THREE.Group();g.name=name;g.position.set(...pos);parent.add(g);return g;}
function timberBetween(parent,name,a,b,width,height,wood,end){const p=new THREE.Vector3(...a),q=new THREE.Vector3(...b),d=q.clone().sub(p),m=timber(parent,name,d.length(),width,height,wood,end,p.clone().add(q).multiplyScalar(.5).toArray());m.quaternion.setFromUnitVectors(new THREE.Vector3(0,0,1),d.normalize());return m;}
function polygonPrism(profile,L){const n=profile.length,positions=[],uv=[],idx=[];let count=0;function face(points,coords){const b=count;points.forEach((p,i)=>{positions.push(...p);uv.push(...coords[i]);count++;});for(let j=1;j<points.length-1;j++)idx.push(b,b+j,b+j+1);}
for(let i=0;i<n;i++){const a=profile[i],b=profile[(i+1)%n];face([[...a,-L/2],[...b,-L/2],[...b,L/2],[...a,L/2]],[[0,0],[0,.15],[L,.15],[L,0]]);}const side=idx.length;
face(profile.map(p=>[...p,-L/2]).reverse(),profile.map(p=>[p[0]*2+.5,p[1]*2+.5]).reverse());face(profile.map(p=>[...p,L/2]),profile.map(p=>[p[0]*2+.5,p[1]*2+.5]));const g=new THREE.BufferGeometry();g.setAttribute('position',new THREE.Float32BufferAttribute(positions,3));g.setAttribute('uv',new THREE.Float32BufferAttribute(uv,2));g.setIndex(idx);g.computeVertexNormals();g.addGroup(0,side,0);g.addGroup(side,idx.length-side,1);return g;}
function log(parent,name,L,r,m,pos,rot=[0,0,0]){const shape=[[0,-r],[r*.8,-r*.5],[r*.95,r*.15],[r*.55,r*.65],[-r*.25,r*.75],[-r*.75,r*.25],[-r*.7,-r*.4]];const mesh=new THREE.Mesh(polygonPrism(shape,L),[m.tx03,m.tx04]);mesh.name=name;mesh.position.set(...pos);mesh.rotation.set(...rot.map(x=>x*Math.PI/180));parent.add(mesh);return mesh;}
function pin(parent,name,pos,m){return createPart(name,cylinderGeo(.014,.014,.014,6),m.tx08,{parent,position:pos,rotation:[0,0,-90]});}
function consolidate(parent,name){parent.updateMatrixWorld(true);const inverse=parent.matrixWorld.clone().invert(),byMaterial=new Map(),old=[];parent.traverse(o=>{if(o.isMesh&&o.parent===parent){old.push(o);const mats=Array.isArray(o.material)?o.material:[o.material];const g=o.geometry,index=g.getIndex(),p=g.getAttribute('position'),u=g.getAttribute('uv'),n=g.getAttribute('normal'),matrix=inverse.clone().multiply(o.matrixWorld),normalMatrix=new THREE.Matrix3().getNormalMatrix(matrix);for(const gr of g.groups.length?g.groups:[{start:0,count:index?index.count:p.count,materialIndex:0}]){const mat=Array.isArray(o.material)?mats[gr.materialIndex||0]:o.material;let entry=byMaterial.get(mat);if(!entry){entry={p:[],u:[],n:[]};byMaterial.set(mat,entry);}for(let k=gr.start;k<gr.start+gr.count;k++){const i=index?index.getX(k):k;entry.p.push(...new THREE.Vector3(p.getX(i),p.getY(i),p.getZ(i)).applyMatrix4(matrix).toArray());entry.n.push(...new THREE.Vector3(n.getX(i),n.getY(i),n.getZ(i)).applyMatrix3(normalMatrix).normalize().toArray());entry.u.push(u?u.getX(i):0,u?u.getY(i):0);}}}});for(const o of old){parent.remove(o);const marker=socket(parent,o.name,o.position.toArray());marker.userData.originalStaticMember=true;}let j=0;for(const [material,e]of byMaterial){const g=new THREE.BufferGeometry();g.setAttribute('position',new THREE.Float32BufferAttribute(e.p,3));g.setAttribute('normal',new THREE.Float32BufferAttribute(e.n,3));g.setAttribute('uv',new THREE.Float32BufferAttribute(e.u,2));const mesh=new THREE.Mesh(g,material);mesh.name=name+'_Surface_'+j++;parent.add(mesh);}}

function metricBox(parent,name,size,material,pos,repeat=2){const g=boxGeo(...size).clone(),p=g.getAttribute('position'),n=g.getAttribute('normal'),uv=g.getAttribute('uv');for(let i=0;i<p.count;i++){const x=p.getX(i),y=p.getY(i),z=p.getZ(i);if(Math.abs(n.getX(i))>.5)uv.setXY(i,(z+size[2]/2)/repeat,(y+size[1]/2)/repeat);else if(Math.abs(n.getY(i))>.5)uv.setXY(i,(x+size[0]/2)/repeat,(z+size[2]/2)/repeat);else uv.setXY(i,(x+size[0]/2)/repeat,(y+size[1]/2)/repeat);}return createPart(name,g,material,{parent,position:pos});}

function wallV2(parent,name,L,openings,m,pos,yaw,exterior=true){const root=group(parent,name,pos);root.rotation.y=yaw*Math.PI/180;const ys=[0,2.8];for(let y=.2;y<2.799;y+=.2)ys.push(Number(y.toFixed(6)));for(const o of openings)ys.push(o.y0,o.y1);const rows=[...new Set(ys)].sort((a,b)=>a-b);let seq=0;
for(let i=0;i<rows.length-1;i++){const low=rows[i],high=rows[i+1],mid=(low+high)/2,cut=openings.filter(o=>mid>=o.y0&&mid<o.y1).sort((a,b)=>a.z0-b.z0);let z=-L/2;const spans=[];for(const o of cut){if(o.z0>z)spans.push([z,o.z0]);z=Math.max(z,o.z1);}if(z<L/2)spans.push([z,L/2]);for(const [a,b]of spans){const length=b-a;if(length<.012)continue;const center=(a+b)/2;timber(root,name+'_CladOuter_'+seq,length,.095,high-low-.003,exterior?m.tx01:m.tx02,m.tx04,[.0525,mid,center],[0,0,0],2);timber(root,name+'_CladInner_'+seq,length,.095,high-low-.003,m.tx02,m.tx04,[-.0525,mid,center],[0,0,0],2);metricBox(root,name+'_Core_'+seq,[.012,high-low,length],exterior?m.tx01:m.tx02,[0,mid,center],2);seq++;}}
consolidate(root,name);root.userData.nightmanWall={length:L,height:2.8,thickness:.2,openings,exterior};return root;}
function deck(parent,name,widthZ,depthX,m,pos=[0,0,0]){const root=group(parent,name,pos),count=Math.round(widthZ/.2),pitch=widthZ/count;metricBox(root,name+'_ContinuousSubfloor',[depthX,.05,widthZ],m.tx02,[0,-.145,0],2);for(let row=0;row<count;row++){const cuts=[-depthX/2,depthX/2];for(let x=-depthX/2+((row%2)?1:2);x<depthX/2-.001;x+=2)cuts.push(x);cuts.sort((a,b)=>a-b);for(let segment=0;segment<cuts.length-1;segment++){const lo=cuts[segment],hi=cuts[segment+1];timber(root,name+'_Slat_'+row+'_'+segment,hi-lo-.003,pitch-.004,.13,m.tx02,m.tx04,[(lo+hi)/2,-.065,-widthZ/2+(row+.5)*pitch],[0,90,0],2);}}consolidate(root,name);root.userData.nightmanFloor={nominalSize:[depthX,.17,widthZ],topY:pos[1],bottomY:pos[1]-.17,continuousSubfloor:true};return root;}
function opening(contract,width,height){return {id:contract.id,z0:contract.center-width/2,z1:contract.center+width/2,y0:contract.y0??0,y1:contract.y1??height};}
function roofCell(parent,name,x0,x1,z0,z1,m){const y=z=>4.6-Math.abs(z)*1.78/6.32,profile=[[-z0,y(z0)-.10],[-z1,y(z1)-.10],[-z1,y(z1)],[-z0,y(z0)]];let area=0;for(let i=0;i<4;i++)area+=profile[i][0]*profile[(i+1)%4][1]-profile[(i+1)%4][0]*profile[i][1];if(area<0)profile.reverse();const g=polygonPrism(profile,x1-x0),p=g.getAttribute('position'),u=g.getAttribute('uv');for(let i=0;i<p.count;i++)u.setXY(i,(p.getZ(i)+(x0+x1)/2)/2,p.getX(i)/2);g.clearGroups();for(let i=0;i<4;i++){const a=profile[i],b=profile[(i+1)%4],normalY=-(b[0]-a[0]);g.addGroup(i*6,6,normalY>0?0:normalY<0?1:2);}g.addGroup(24,12,2);const mesh=new THREE.Mesh(g,[m.tx06,m.tx02,m.tx01]);mesh.name=name;mesh.rotation.y=Math.PI/2;mesh.position.x=(x0+x1)/2;parent.add(mesh);return mesh;}
function makeRoof(root,m){const roof=group(root,'Roof'),west=group(roof,'Roof_West'),east=group(roof,'Roof_East'),xs=[-5.32,-.555,.195,5.32],zs=[-6.32,-5.79,-5.17,0];for(let i=0;i<xs.length-1;i++)for(let j=0;j<zs.length-1;j++){if(i===1&&j===1)continue;roofCell(west,'Roof_West_Cell_'+i+'_'+j,xs[i],xs[i+1],zs[j],zs[j+1],m);}roofCell(east,'Roof_East_Panel',-5.32,5.32,0,6.32,m);socket(roof,'chimney_roof_opening',[-.18,4.6-5.48*1.78/6.32,-5.48]);
for(const x of [-4.9,4.9]){const g=polygonPrism([[-6,2.8],[6,2.8],[0,4.5]],.2),p=g.getAttribute('position'),u=g.getAttribute('uv');for(let i=0;i<p.count;i++)u.setXY(i,p.getX(i)/2,p.getY(i)/2);g.clearGroups();g.addGroup(0,18,0);g.addGroup(18,3,x>0?2:1);g.addGroup(21,3,x>0?1:2);const mesh=new THREE.Mesh(g,[m.tx01,m.tx01,m.tx02]);mesh.name=x>0?'Gable_Front':'Gable_Rear';mesh.rotation.y=Math.PI/2;mesh.position.x=x;roof.add(mesh);for(const side of [-1,1])timberBetween(roof,'Gable_Trim_'+x+'_'+side,[x,2.84,side*6.18],[x,4.52,0],.10,.14,m.tx01,m.tx04);}
consolidate(west,'Roof_West');consolidate(east,'Roof_East');return roof;}
function makeChimney(root,m){const chimney=group(root,'Chimney',[-.18,0,-5.48]);for(const x of [-.2775,.2775])metricBox(chimney,'FlueSideX_'+x,[.075,1.82,.5],m.tx07,[x,3.39,0],1);for(const z of [-.2125,.2125])metricBox(chimney,'FlueSideZ_'+z,[.48,1.82,.075],m.tx07,[0,3.39,z],1);for(const x of [-.3375,.3375])metricBox(chimney,'CapRimX_'+x,[.10,.12,.65],m.tx07,[x,4.34,0],1);for(const z of [-.275,.275])metricBox(chimney,'CapRimZ_'+z,[.575,.12,.10],m.tx07,[0,4.34,z],1);socket(chimney,'chimney_smoke_socket',[0,4.41,0]);const slope=1.78/6.32,roofY=z=>4.6+z*slope;for(const x of [-.435,.075]){const strip=metricBox(chimney,'FlashingX_'+x,[.16,.035,.80],m.tx08,[x,roofY(-5.48)+.025,0],1);strip.rotation.x=-Math.atan(slope);}for(const z of [-.31,.31]){const strip=metricBox(chimney,'FlashingZ_'+z,[.96,.035,.16],m.tx08,[0,roofY(-5.48+z)+.025,z],1);strip.rotation.x=-Math.atan(slope);}consolidate(chimney,'Chimney');return chimney;}
function makePorch(root,m){deck(root,'Porch',8,2,m,[6,0,-2]);const canopy=group(root,'PorchCanopy'),y=x=>2.84-(x-4.8)*.17,profile=[[4.8,y(4.8)-.10],[7.15,y(7.15)-.10],[7.15,y(7.15)],[4.8,y(4.8)]];const g=polygonPrism(profile,8.30),p=g.getAttribute('position'),uv=g.getAttribute('uv');for(let i=0;i<p.count;i++)uv.setXY(i,p.getX(i)/2,(p.getZ(i)-2)/2);g.clearGroups();g.addGroup(0,6,1);g.addGroup(6,6,2);g.addGroup(12,6,0);g.addGroup(18,18,2);const panel=new THREE.Mesh(g,[m.tx06,m.tx02,m.tx01]);panel.name='Porch_Roof_Panel';panel.position.z=-2;canopy.add(panel);const beamY=y(6.92)-.14;for(const z of [-5.83,-2,1.83]){timber(root,'Porch_Post_'+z,beamY-.09,.14,.14,m.tx01,m.tx04,[6.92,(beamY-.09)/2,z],[90,0,0],2);metricBox(root,'Porch_Post_Shoe_'+z,[.17,.045,.17],m.tx08,[6.92,.023,z],1);timberBetween(canopy,'Porch_Rafter_'+z,[4.86,2.76,z],[6.92,y(6.92)-.11,z],.11,.15,m.tx01,m.tx04);for(const sign of [-1,1]){if(z===-5.83&&sign<0||z===1.83&&sign>0)continue;timberBetween(root,'Porch_Brace_'+z+'_'+sign,[6.92,beamY-.53,z],[6.92,beamY-.02,z+sign*.45],.075,.09,m.tx01,m.tx04);}}timber(root,'Porch_Front_Header',7.85,.18,.18,m.tx01,m.tx04,[6.92,beamY,-2],[0,0,0],2);consolidate(canopy,'PorchCanopy');return canopy;}
async function build(){const m=await surfaces(),root=createRoot('CabinShellV2');deck(root,'Floor',12,10,m);deck(root,'WorkyardLanding',1.6,1.6,m,[.65,0,6.8]);
const front=[opening({id:'D1',center:.05},1.24,2.32),opening({id:'W6',center:-3.2,y0:.87,y1:2.13},1.36),opening({id:'W7',center:3.9,y0:.87,y1:2.13},1.36)],rear=[opening({id:'W1',center:3.2,y0:.87,y1:2.13},1.36),opening({id:'W2',center:-3.9,y0:.87,y1:2.13},1.36)],left=[opening({id:'W4',center:-2.6,y0:.87,y1:2.13},1.36),opening({id:'W5',center:3.1,y0:.87,y1:2.13},1.36)],right=[opening({id:'W3',center:2.8,y0:.87,y1:2.13},1.36),opening({id:'D4',center:-.65},1.24,2.32)];
wallV2(root,'FrontWall',12,front,m,[4.9,0,0],0);wallV2(root,'RearWall',12,rear,m,[-4.9,0,0],180);wallV2(root,'LeftWall',9.6,left,m,[0,0,-5.9],90);wallV2(root,'RightWall',9.6,right,m,[0,0,5.9],-90);wallV2(root,'RoomPartition',6.8,[opening({id:'D2',center:-.6},1.12,2.3),opening({id:'D3',center:2.25},1.12,2.3)],m,[-1.4,0,2],90,false);wallV2(root,'BedroomSupplyDivider',3.8,[],m,[-1,0,3.9],0,false);wallV2(root,'SupplyKitchenDivider',3.8,[],m,[2,0,3.9],0,false);
const ceiling1=deck(root,'BedroomCeiling',3.8,3.8,m,[-3,2.97,3.9]),ceiling2=deck(root,'SupplyCeiling',3.8,3,m,[.5,2.97,3.9]);ceiling1.userData.nightmanFloor.role='ceiling';ceiling2.userData.nightmanFloor.role='ceiling';
const roof=makeRoof(root,m);for(const x of [-4.65,-2.325,0,2.325,4.65]){for(const sign of [-1,1])timberBetween(roof,'Roof_Rafter_'+x+'_'+sign,[x,2.68,sign*5.82],[x,4.25,0],.12,.17,m.tx01,m.tx04);timber(roof,'Roof_Tie_'+x,10.6,.16,.20,m.tx02,m.tx04,[x,2.9,0],[0,0,0],2);}timber(roof,'Ridge_Beam',10.22,.18,.22,m.tx01,m.tx04,[0,4.4,0],[0,90,0],2);
makeChimney(root,m);makePorch(root,m);const trim=group(root,'WallTrim');for(const x of [-4.88,4.88])for(const z of [-5.88,5.88])timber(trim,'Corner_Post_'+x+'_'+z,2.8,.13,.13,m.tx01,m.tx04,[x,1.4,z],[90,0,0],2);for(const x of [-4.9,4.9])timber(trim,'TopPlate_'+x,11.75,.19,.16,m.tx01,m.tx04,[x,2.83,0],[0,0,0],2);for(const z of [-5.9,5.9])timber(trim,'SideTopPlate_'+z,9.55,.19,.16,m.tx01,m.tx04,[0,2.83,z],[0,90,0],2);consolidate(trim,'WallTrim');
for(const s of CONTRACT.sockets){const n=socket(root,s.name,s.translation);n.quaternion.set(...s.rotation);n.userData.nightmanSocket=s;}
root.userData.nightmanLayout={version:2,outerWidthZ:12,outerDepthX:10,wallHeight:2.8,floorY:0,wallThickness:.2,planMapping:CONTRACT.frame,approvedPlanSha256:CONTRACT.approvedPlanSha256,rooms:CONTRACT.rooms,doorSocketNames:CONTRACT.doors.map(s=>s.name),windowSocketNames:CONTRACT.windows.map(s=>s.name),inspectionHide:['Roof','PorchCanopy','BedroomCeiling','SupplyCeiling'],closedBedroom:true,closedSupply:true,openLiving:true,openKitchen:true,subfloorContinuous:true};return root;}

Asset content follows the supplied CC0-1.0 licence record. Kiln and scene software retain their own licences.