import assert from 'node:assert/strict'; import {test} from 'node:test'; import * as THREE from 'three'; import {loadTypescript} from './support/load-typescript.mjs'; const {peekingLayout,placePeekingDog}=await loadTypescript(new URL('../src/objects/PeekingComposition.ts',import.meta.url)); const {fitWindowScale}=await loadTypescript(new URL('../src/objects/BlenderWindowFrame.ts',import.meta.url)); const {CameraController}=await loadTypescript(new URL('../src/input/CameraController.ts',import.meta.url)); test('experimental door keeps fixed proportions and legacy clearance reference dimensions',()=>{ for(const view of[375/812,812/375,1.4])for(const photo of[.2,.5625,.8,1,1.5,5,12]){ const layout=peekingLayout(view,photo),scale=fitWindowScale(view,photo)*.82; assert.ok(Math.abs(layout.width/layout.height-.74)<1e-12); assert.deepEqual(layout.cameraBounds,[scale*photo*.8,scale*.8,.6]); for(const max of[.35,.75,.9])for(const x of[-1,-.5,0,.5,1])for(const y of[-1,-.5,0,.5,1]){ const oldCamera=new THREE.PerspectiveCamera(40,view,.1,100),newCamera=oldCamera.clone(); const old=new CameraController(oldCamera,max),fresh=new CameraController(newCamera,max); old.setRoomBounds(scale*photo*.8,scale*.8,.6);fresh.setRoomBounds(...layout.cameraBounds); old.setView(x,y);fresh.setView(x,y); for(const dt of[0,.016,.1,10]){old.update(dt,1);fresh.update(dt,1);assert.deepEqual(newCamera.position.toArray(),oldCamera.position.toArray());assert.deepEqual(newCamera.quaternion.toArray(),oldCamera.quaternion.toArray());assert.equal(newCamera.near,oldCamera.near);} assert.ok(newCamera.position.y-newCamera.near> -layout.height/2-.24*Math.min(layout.width,layout.height),'eye/near above resized indoor floor'); } } }); test('dog mask occupies lower right with cropped bottom hidden below sill, world-fixed independently of slide',()=>{ const layout=peekingLayout(.6,1.5),bounds={x:.15,y:.1,width:.55,height:.8}; const a=placePeekingDog(layout,1.5,bounds,0.4704,1,0,0); const maskTop=a.y+(.5-bounds.y)*a.height,maskBottom=a.y+(.5-bounds.y-bounds.height)*a.height; const maskCenterX=a.x+(bounds.x+bounds.width/2-.5)*a.width; assert.ok(maskCenterX>0);assert.ok(maskTop<0);assert.ok(maskTop>-.35*layout.height);assert.ok(maskBottom<-.5*layout.height); assert.equal(a.z,.4704);assert.ok(a.width/a.height===1.5); const moved=placePeekingDog(layout,1.5,bounds,.4704,1,1,1);assert.ok(moved.x>a.x&&moved.y>a.y,'position controls work at zoom 1'); }); test('experimental house preserves conservative front-detail clearance and closed rear room',async()=>{ const {loadFrameGeometry}=await import('./support/load-frame-geometry.mjs'); const {prepareHouseAsset}=await loadTypescript(new URL('../src/objects/BlenderHouseSurround.ts',import.meta.url)); const root=loadFrameGeometry(new URL('../public/assets/window/grandma-house-surround.glb',import.meta.url)),asset=prepareHouseAsset(root); const layout=peekingLayout(375/812,12);asset.resize(layout.width,layout.height,.6,layout.clearanceScale);root.updateMatrixWorld(true); const curtain=root.getObjectByName('HouseCurtain');curtain.geometry.computeBoundingBox(); assert.ok(curtain.geometry.boundingBox.max.z<=.448*layout.clearanceScale,'foreground thickness retains its conservative legacy clearance'); for(const d of[[0,0,1],[0,-1,0],[1,0,0]])assert.ok(new THREE.Raycaster(new THREE.Vector3(0,0,3),new THREE.Vector3(...d),.001,20).intersectObject(root,true).length,'room closure survives shallow front'); asset.dispose(); });