(P,drop)
| 1804 | } |
| 1805 | |
| 1806 | function buildFalls(P,drop){ |
| 1807 | const g=new THREE.Group(); |
| 1808 | const w=0.9; |
| 1809 | /* Two crossed sheets: a single plane vanishes to a line whenever the camera |
| 1810 | swings to face it edge-on, which on a free iso view is a quarter of all |
| 1811 | headings. */ |
| 1812 | const sheetMat=mat(P.water,{opacity:0.45,flat:false,rough:0.1, |
| 1813 | emissive:P.water,ei:P.liquidGlow??0.3,side:THREE.DoubleSide}); |
| 1814 | for(const rot of [0,Math.PI/2]){ |
| 1815 | const sheet=meshOf(new THREE.PlaneGeometry(w,drop),sheetMat,false,false); |
| 1816 | sheet.position.y=-drop/2; sheet.rotation.y=rot; g.add(sheet); |
| 1817 | } |
| 1818 | const spray=P.kit==='forge'?P.lavaHot:0xFFFFFF; |
| 1819 | for(let i=0;i<4;i++){ |
| 1820 | const u=(i+1)/4; |
| 1821 | const puff=meshOf(new THREE.IcosahedronGeometry(0.3+u*0.55,0), |
| 1822 | mat(spray,{opacity:0.22*(1-u*0.7),flat:false}),false,false); |
| 1823 | puff.position.y=-drop*u; puff.scale.y=0.7; g.add(puff); |
| 1824 | } |
| 1825 | /* Own material per streak. Sharing one cached glow meant seven streaks all |
| 1826 | wrote `.opacity` on the same material every frame and the falls strobed |
| 1827 | instead of falling. */ |
| 1828 | for(let i=0;i<6;i++){ |
| 1829 | const sm=new THREE.MeshStandardMaterial({color:spray,emissive:spray, |
| 1830 | emissiveIntensity:0.8,roughness:0.35,transparent:true,opacity:0.75}); |
| 1831 | const st=meshOf(new THREE.BoxGeometry(0.07,0.5,0.03),sm,false,false); |
| 1832 | const off=i/6, xo=(i/6-0.5)*w*0.8; |
| 1833 | st.userData.tick=t=>{ |
| 1834 | const u=(t*0.55+off)%1; |
| 1835 | st.position.set(xo,-u*drop,0.02); |
| 1836 | st.scale.y=0.6+u*1.4; |
| 1837 | sm.opacity=0.75*(1-u*0.8); |
| 1838 | }; |
| 1839 | g.add(st); animated.push(st); |
| 1840 | } |
| 1841 | return g; |
| 1842 | } |
| 1843 | |
| 1844 | /* -------------------------------------------- building off the rim, and life */ |
| 1845 | /* The platform braced off the rim. It was ONE builder for all six realms — |
no test coverage detected