import assert from 'node:assert/strict'; import {test} from 'node:test'; import * as THREE from 'three'; import {loadTypescript} from './support/load-typescript.mjs'; const {WindowFinish}=await loadTypescript(new URL('../src/objects/WindowFinish.ts',import.meta.url)); const {WindowReveal}=await loadTypescript(new URL('../src/objects/WindowReveal.ts',import.meta.url)); const {attachMeshRefraction}=await loadTypescript(new URL('../src/rendering/MeshRefraction.ts',import.meta.url)); function fixture(){ const geometry=new THREE.BoxGeometry(),materials=[new THREE.MeshBasicMaterial()],frames=Array.from({length:4},()=>new THREE.Mesh(geometry,materials)),scene=new THREE.Scene(),reveal=new WindowReveal(materials[0]); const finish=new WindowFinish(scene,frames,reveal,materials,materials[0]);finish.apply('wood'); return {scene,finish,reveal,dispose(){finish.dispose();reveal.dispose();geometry.dispose();materials.forEach(m=>m.dispose());}}; } test('room finish has neutral fill and upper-right daylight without new render passes',()=>{ const f=fixture(),lights=f.scene.children.filter(o=>o.isLight),ambient=lights.find(o=>o.isAmbientLight),key=lights.find(o=>o.isDirectionalLight); assert.equal(lights.length,2,'one ambient and one key keep existing B reveal and mobile light budget'); assert.ok(ambient.color.b/ambient.color.r>.95,'room fill must not turn ivory/plaster olive'); assert.ok(key.position.x>0&&key.position.y>0&&key.position.z>0,'daylight comes from upper right in the shipped frame scene'); assert.ok(ambient.intensity>=1.35&&ambient.intensity<=1.7); assert.ok(key.intensity>=2&&key.intensity<=2.5); assert.equal(key.castShadow,false,'portable authored contact shading avoids new shadow-map passes'); f.finish.apply('booth');assert.ok(lights.every(l=>!l.visible));f.finish.apply('wood');assert.ok(lights.every(l=>l.visible)); f.dispose();assert.ok(lights.every(l=>l.parent===null)); }); test('custom B reveal reads the same refined room lights, not stale preview lighting',()=>{ const f=fixture(),source=new THREE.Mesh(new THREE.PlaneGeometry(1,1),new THREE.ShaderMaterial({uniforms:{uDepthMap:{value:new THREE.Texture()},uDepthScale:{value:.25},uDepthBias:{value:0}}})); const glass=new THREE.MeshPhysicalMaterial(),optics=attachMeshRefraction(glass,source); optics.syncReveal(f.reveal.meshes,f.scene); const ambient=f.scene.children.find(o=>o.isAmbientLight),key=f.scene.children.find(o=>o.isDirectionalLight); assert.deepEqual(optics.uniforms.uBRevealAmbient.value.toArray(),ambient.color.clone().multiplyScalar(ambient.intensity).toArray()); assert.deepEqual(optics.uniforms.uBRevealLightColor.value.toArray(),key.color.clone().multiplyScalar(key.intensity).toArray()); assert.ok(optics.uniforms.uBRevealLightDirection.value.distanceTo(key.position.clone().normalize())<1e-12); f.dispose();source.geometry.dispose();source.material.uniforms.uDepthMap.value.dispose();source.material.dispose();glass.dispose(); });