Skip to content
Kiln1.3Get Kiln

Original fitted PSX cabin furnishing with procedural pixel textures.

Cabin in the Woods: PSX Horror pack
Original fitted PSX cabin furnishing with procedural pixel textures.

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
888
Meshes
20
Materials
2
Dimensions (m)
0.60 × 0.57 × 1.30

Full Kiln assets (remixable)

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

81,249 bytes (0.08 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_831c8568d1c64d32ba3bdec26e01c5e7 / r_02259d548f9145428b2d01acfa6250f1
Source SHA-256
e3eec398f2918f9cbdafa8b496a4e698abfb26e1fff93621a15972de1f960919
Incoming outdoor log pile: exact saved source
const meta={name:"Incoming outdoor log pile",description:'Original PSX cabin-v2 furnishing, assembled carpentry with exact original cabin pixel materials. Local +X faces forward, +Y up, +Z width; no scene scale stretch.'};
const ITEM="incomingLogPile",SPECS={"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"}}}},"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"}}}},"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"}}}}};
async function build(){
 const root=createRoot('CabinV2_'+ITEM),mat={};for(const[key,spec]of Object.entries(SPECS))mat[key]=await compilePortableMaterialSpecV3(spec);const wood=mat.tx02??mat.tx01,iron=mat.tx08,doors=[];const paper=await compilePortableMaterialSpecV3({schemaVersion:3,model:'pbrMetallicRoughness',name:'Original worn book pages',roughness:1,textures:{baseColor:{kind:'procedural',spec:{schemaVersion:3,width:16,height:16,usage:'albedo',background:[189,185,157,255],operations:[{op:'paint',shape:{kind:'rectangle',x:0,y:4,width:16,height:1},rgba:[157,154,135,255]},{op:'paint',shape:{kind:'rectangle',x:0,y:8,width:16,height:1},rgba:[158,155,135,255]},{op:'paint',shape:{kind:'rectangle',x:0,y:12,width:16,height:1},rgba:[157,154,135,255]}]},sampler:{minFilter:'nearest',magFilter:'nearest',wrapS:'repeat',wrapT:'repeat'}}}}),bookCover=new THREE.MeshStandardMaterial({color:0x516054,roughness:.95,metalness:0});
 function anchor(name,p,parent=root){const n=new THREE.Object3D();n.name=name;n.position.fromArray(p);n.userData.furnishingAnchor={name,version:1};parent.add(n);return n;}
 function grain(g,axis='Z',phase=0){const p=g.getAttribute('position'),n=g.getAttribute('normal'),uv=g.getAttribute('uv');const get=(a,i)=>a==='X'?p.getX(i):a==='Y'?p.getY(i):p.getZ(i);for(let i=0;i<p.count;i++){const normal=[Math.abs(n.getX(i)),Math.abs(n.getY(i)),Math.abs(n.getZ(i))],dominant=['X','Y','Z'][normal.indexOf(Math.max(...normal))],cross=['X','Y','Z'].find(a=>a!==axis&&a!==dominant)??(axis==='Y'?'Z':'Y');const faceAxis=dominant===axis?(['X','Y','Z'].find(a=>a!==dominant&&a!==cross)):axis;uv.setXY(i,get(faceAxis,i)*.5+.5+phase,get(cross,i)*.5+.5);}return g;}
 function box(name,size,pos,m=wood,axis='Z',parent=root,phase=0){return createPart(name,grain(boxGeo(...size).clone(),axis,phase),m,{parent,position:pos});}
 function geom(p,uv,ix){let g=new THREE.BufferGeometry();g.setAttribute('position',new THREE.Float32BufferAttribute(p,3));g.setAttribute('uv',new THREE.Float32BufferAttribute(uv,2));g.setIndex(ix);g=g.toNonIndexed();g.computeVertexNormals();return g;}
 function taper(name,base,top,height,bottomR,topR,parent=root){const p=[],uv=[],ix=[];for(const[centre,y,r]of[[base,0,bottomR],[top,height,topR]])for(const[x,z]of[[-1,-1],[1,-1],[1,1],[-1,1]]){p.push(centre[0]+x*r,y,centre[1]+z*r);uv.push(x*.5+.5,y);}for(let i=0;i<4;i++){const j=(i+1)%4;ix.push(i,i+4,j,j,i+4,j+4);}ix.push(0,1,2,0,2,3,4,6,5,4,7,6);return createPart(name,grain(geom(p,uv,ix),'Y'),wood,{parent});}
 function beam(name,a,b,width=.035,depth=width,m=wood,parent=root){const A=new THREE.Vector3(...a),B=new THREE.Vector3(...b),direction=B.clone().sub(A),g=grain(boxGeo(width,direction.length(),depth).clone(),'Y'),n=createPart(name,g,m,{parent,position:A.clone().add(B).multiplyScalar(.5).toArray()});n.quaternion.setFromUnitVectors(new THREE.Vector3(0,1,0),direction.normalize());return n;}
 function screw(name,pos,parent=root){return createPart(name,cylinderGeo(.007,.007,.005,8),iron,{parent,position:pos,rotation:[0,0,-90]});}
 function door(name,hingeZ,height,bottom){const left=hingeZ<0,sign=left?1:-1,pivot=createPivot(name,[.194,bottom,hingeZ],root),w=.343;for(const[y,h]of[[.025,.05],[height-.025,.05]])box(name+'Horizontal_'+y,[.027,h,w],[.004,y,sign*w/2],wood,'Z',pivot);for(const[z,suffix]of[[sign*.018,'HingeStile'],[sign*(w-.018),'LatchStile']])box(name+suffix,[.027,height-.06,.036],[.004,height/2,z],wood,'Y',pivot);box(name+'RecessedPanel',[.018,height-.10,w-.084],[-.006,height/2,sign*w/2],wood,'Y',pivot,.17);screw(name+'UpperHinge',[.014,height-.10,sign*.008],pivot);screw(name+'LowerHinge',[.014,.10,sign*.008],pivot);box(name+'Pull',[.010,.037,.019],[.026,height*.53,sign*(w-.07)],iron,'Y',pivot);doors.push({name:pivot.name,angle:left?103:-103});return pivot;}
 function book(name,pos,height=.18,width=.07,parent=root){createPart(name+'Pages',boxGeo(.12,height,width),paper,{parent,position:pos});box(name+'Spine',[.015,height+.004,width+.007],[pos[0]+.065,pos[1],pos[2]],bookCover,'Y',parent,.45);box(name+'TopCover',[.14,.008,width+.012],[pos[0],pos[1]+height/2,pos[2]],bookCover,'Z',parent,.3);}
 if(ITEM==='diningTable'){
  const W=1.4,D=.8,H=.78,gap=.003,bw=(W-4*gap)/5;for(let i=0;i<5;i++)box('TopPlank_'+i,[D,.04,bw],[0,H-.02,(i-2)*(bw+gap)],wood,'Z',root,i*.113);
  for(const[x,z,suffix]of[[-.31,-.61,'RearLeft'],[.31,-.61,'FrontLeft'],[-.31,.61,'RearRight'],[.31,.61,'FrontRight']])taper('Leg_'+suffix,[x,z],[x,z],.746,.022,.032);
  for(const z of[-.61,.61])box('EndApron_'+z,[.65,.09,.043],[0,.694,z],wood,'X');for(const x of[-.31,.31])box('LongApron_'+x,[.043,.09,1.25],[x,.694,0]);for(const z of[-.61,.61])beam('EndStretcher_'+z,[-.31,.23,z],[.31,.23,z],.037,.04);beam('LongStretcher',[0,.23,-.61],[0,.23,.61],.042,.042);for(const z of[-.59,.59])for(const x of[-.30,.30])box('JoinPeg_'+x+'_'+z,[.010,.023,.023],[x,.69,z],mat.tx03??wood,'Y');anchor('tabletop_support',[0,H,0]);root.userData.furnishing={kind:ITEM,targetFootprint:[D,W],supportY:H,frontClearance:.6};
 }else if(ITEM==='diningChair'){
  const seatY=.46;for(const side of[-1,1]){taper('FrontLeg_'+side,[.223,side*.199],[.205,side*.196],.437,.024,.026);taper('RearLeg_'+side,[-.218,side*.196],[-.195,side*.196],.437,.023,.025);beam('BackPost_'+side,[-.195,.415,side*.196],[-.225,.905,side*.196],.045,.045);beam('SideStretcher_'+side,[-.208,.17,side*.196],[.215,.17,side*.196],.029,.032);}beam('FrontStretcher',[.216,.215,-.196],[.216,.215,.196],.032,.032);beam('RearStretcher',[-.207,.19,-.196],[-.207,.19,.196],.029,.029);
  const gap=.003,sw=(.45-2*gap)/3;for(let i=0;i<3;i++)box('SeatSlat_'+i,[.45,.033,sw],[.025,seatY-.0165,(i-1)*(sw+gap)],wood,'X',root,i*.17);box('SeatFrontRail',[.045,.066,.402],[.21,.408,0],wood,'Z');box('SeatRearRail',[.045,.066,.402],[-.19,.408,0],wood,'Z');box('BackCrest',[.042,.075,.40],[-.222,.8925,0],wood,'Z');box('BackLowerRail',[.040,.045,.36],[-.202,.605,0],wood,'Z');for(const z of[-.125,0,.125])beam('BackSlat_'+z,[-.201,.605,z],[-.223,.879,z],.026,.072);anchor('seat_support',[.025,.46,0]);root.userData.furnishing={kind:ITEM,targetFootprint:[.5,.45],seatY:.46,face:'+X',rearPullback:.65};
 }else if(['bedroomCabinet','kitchenCupboard','tallCabinet'].includes(ITEM)){
  const H=ITEM==='bedroomCabinet'?1:ITEM==='kitchenCupboard'?1.25:1.82,doorTop=ITEM==='bedroomCabinet'?.71:ITEM==='kitchenCupboard'?.79:1.05;
  for(const z of[-.355,.355])for(const x of[-.18,.18])taper('Foot_'+x+'_'+z,[x,z],[x,z],.10,.028,.035);box('Plinth',[.45,.055,.8],[0,.0925,0]);box('CaseBack',[.024,H-.13,.744],[-.213,(H+.11)/2,0],wood,'Y');for(const z of[-.385,.385])box('CaseSide_'+z,[.40,H-.13,.030],[-.015,(H+.11)/2,z],wood,'Y');box('Cornice',[.45,.035,.8],[0,H-.0175,0]);box('CaseFloor',[.409,.027,.744],[-.008,.131,0]);box('CentreStile',[.037,doorTop-.11,.025],[.186,(doorTop+.11)/2,0],wood,'Y');
  door('DoorLeft',-.355,doorTop-.13,.13);door('DoorRight',.355,doorTop-.13,.13);for(const y of[.39,doorTop])box('Shelf_'+y,[.389,.024,.737],[-.02,y-.012,0]);
  if(ITEM==='bedroomCabinet'){for(const z of[-.185,.185]){box('DrawerFront_'+z,[.028,.152,.352],[.190,.825,z]);box('DrawerPull_'+z,[.014,.015,.079],[.216,.825,z],iron);box('DrawerSide_'+z,[.31,.12,.018],[-.010,.823,z-.165],wood,'X');}for(let i=0;i<4;i++)book('ClothingBook_'+i,[-.055,.49,-.25+i*.083],.18,.065);}
  else if(ITEM==='kitchenCupboard'){for(const y of[1.045])box('UpperShelf',[.389,.024,.737],[-.02,y-.012,0]);box('UpperDivider',[.37,.22,.020],[-.02,.915,0],wood,'Y');for(let i=0;i<3;i++)book('PantryLedger_'+i,[-.055,1.135,-.28+i*.088],.15,.067);for(const z of[.15,.25])createPart('PantryTin_'+z,cylinderGeo(.033,.033,.125,10),iron,{parent:root,position:[-.015,.865,z]});}
  else{box('UpperDivider',[.37,.70,.024],[-.02,1.40,0],wood,'Y');box('UpperShelf',[.389,.024,.737],[-.02,1.445,0]);for(let i=0;i<3;i++)book('ToolManual_'+i,[-.05,1.58,-.28+i*.080],.22,.065);for(const z of[.10,.25]){beam('HangerArm_'+z,[-.11,1.70,z],[.08,1.70,z],.015,.015,iron);beam('HangerHook_'+z,[.08,1.70,z],[.08,1.64,z],.015,.015,iron);}}
  anchor('front_use',[.225,.6,0]);root.userData.furnishing={kind:ITEM,targetFootprint:[.45,.8],frontClearance:.7,doorNodes:doors,openRole:'Decorative native cabinet inspection; no loot mechanic assumed'};
 }else if(ITEM==='kitchenWorktop'){
  for(const x of[-.24,.24])for(const z of[-.90,.90])taper('WorktopLeg_'+x+'_'+z,[x,z],[x,z],.85,.031,.042);for(let i=0;i<5;i++)box('WorktopPlank_'+i,[.6,.045,.3976],[0,.8575,(i-2)*.4006],wood,'Z',root,i*.097);for(const x of[-.24,.24])box('Apron_'+x,[.045,.10,1.83],[x,.77,0]);for(const z of[-.90,.90])box('EndApron_'+z,[.49,.10,.045],[0,.77,z],wood,'X');for(let i=0;i<5;i++)box('LowerShelfPlank_'+i,[.47,.028,.361],[0,.23,(i-2)*.368],wood,'Z',root,.13*i);for(const z of[-.90,0,.90])beam('ShelfSupport_'+z,[-.24,.20,z],[.24,.20,z],.035,.040);box('ShelfDivider',[.44,.44,.027],[0,.46,.30],wood,'Y');anchor('worktop_support',[0,.88,0]);root.userData.furnishing={kind:ITEM,targetFootprint:[.6,2],supportY:.88,face:'+X'};
 }else if(ITEM==='supplyChest'){
  for(const z of[-.34,.34])box('SledFoot_'+z,[.42,.055,.055],[0,.0275,z],wood,'X');box('ChestFloor',[.405,.033,.744],[0,.0735,0]);for(const x of[-.209,.209])for(let i=0;i<4;i++)box('ChestLongSlat_'+x+'_'+i,[.026,.112,.78],[x,.134+i*.108,0]);for(const z of[-.387,.387])box('ChestEnd_'+z,[.43,.447,.026],[0,.2945,z],wood,'Y');for(const z of[-.30,.30])for(const x of[-.216,.216])box('IronStrap_'+x+'_'+z,[.009,.439,.03],[x,.292,z],iron,'Y');
  const lid=createPivot('ChestLid',[-.207,.545,0],root);for(let i=0;i<4;i++)box('LidPlank_'+i,[.433,.035,.197],[.207,.0175,(i-1.5)*.200],wood,'X',lid,i*.17);box('LidFrontLip',[.020,.055,.79],[.419,.0075,0],wood,'Z',lid);box('LatchPlate',[.01,.084,.050],[.220,.501,0],iron,'Y');box('Hasp',[.010,.042,.025],[.220,.559,0],iron,'Y');for(const z of[-.29,.29])box('LidStrap_'+z,[.433,.007,.026],[.207,.037,z],iron,'X',lid);anchor('lid_hinge',[-.207,.545,0]);root.userData.furnishing={kind:ITEM,targetFootprint:[.45,.8],lidNode:lid.name,lidAngle:85,frontClearance:.55};
 }else if(ITEM==='plankReserve'){
  for(const z of[-.65,.65])box('CradleFoot_'+z,[.35,.055,.075],[0,.0275,z],mat.tx01??wood,'X');for(const x of[-.151,.151])for(const z of[-.65,.65])box('RetainingPost_'+x+'_'+z,[.035,.53,.045],[x,.315,z],mat.tx01??wood,'Y');for(let i=0;i<9;i++){const board=box('ReserveBoard_'+i,[.26,.038,1.5],[((i%3)-1)*.012,.080+i*.050,0],mat.tx03??wood,'Z',root,i*.073);for(const z of[-.7501,.7501])box('BoardEnd_'+i+'_'+z,[.2601,.0381,.0006],[((i%3)-1)*.012,.080+i*.050,z],mat.tx04??wood,'X');}root.userData.furnishing={kind:ITEM,targetFootprint:[.35,1.5],stackParts:Array.from({length:9},(_,i)=>'Mesh_ReserveBoard_'+i),stockVisibility:'Scene may hide board groups; no inventory policy in asset'};
 }else if(ITEM==='incomingLogPile'){
  for(const z of[-.47,.47])box('GroundSleeper_'+z,[.6,.05,.10],[0,.025,z],mat.tx01??wood,'X');function logGrain(g,phase){const p=g.getAttribute('position'),n=g.getAttribute('normal'),uv=g.getAttribute('uv');for(let i=0;i<p.count;i++){if(Math.abs(n.getY(i))>.5)uv.setXY(i,p.getX(i)*.5+.5,p.getZ(i)*.5+.5);else uv.setXY(i,p.getY(i)*.5+.5+phase,uv.getX(i)*2*Math.PI*.096*.5+.13+phase*.17);}return g;}let index=0;const r=.096,dy=r*Math.sqrt(3);for(let row=0;row<3;row++)for(let col=0;col<3-row;col++){const x=(col-(2-row)/2)*2*r,y=.05+r+row*dy,len=1.3-row*.013-col*.009;createPart('IncomingLog_'+index,logGrain(cylinderGeo(r,r,len,12).clone(),index*.073),mat.tx01??wood,{parent:root,position:[x,y,0],rotation:[90,0,0]});for(const z of[-len/2-.0002,len/2+.0002])createPart('LogEnd_'+index+'_'+z,cylinderGeo(r*.996,r*.996,.0006,12),mat.tx04??wood,{parent:root,position:[x,y,z],rotation:[90,0,0]});index++;}root.userData.furnishing={kind:ITEM,targetFootprint:[.6,1.3],logs:6,contact:'Hex-packed vertex contacts; source sleepers derive from bottom radius, not random placement'};
 }else throw Error('Unknown furnishing '+ITEM);
 root.userData.furnishing={...root.userData.furnishing,version:1,frame:{forward:'+X',up:'+Y',right:'+Z'},origin:'bottom-centred',doors};return root;
}
function animate(root){const f=root.userData.furnishing;if(f.lidNode)return[createClip('OpenLid',1.2,[rotationTrack(f.lidNode,[{time:0,rotation:[0,0,0]},{time:1.2,rotation:[0,0,f.lidAngle]}],'EASE_IN_OUT')],{loop:false})];if(f.doors.length)return[createClip('OpenDoors',1.2,f.doors.map(d=>rotationTrack(d.name,[{time:0,rotation:[0,0,0]},{time:1.2,rotation:[0,d.angle,0]}],'EASE_IN_OUT')),{loop:false})];return[];}

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