import { test } from 'node:test'; import assert from 'node:assert/strict'; import { Vector3 } from 'three'; import { createPrecipitation } from '../src/scene/precipitation.ts'; test('more precipitation draws more particles; mixed weather animates both and dry weather stops', (t) => { t.mock.method(Math, 'random', () => 0.5); const effect = createPrecipitation(() => -100); const camera = new Vector3(0, 10, 0); const [rain, snow] = effect.group.children as any[]; try { assert.equal(effect.update(0, camera, 0, 0, 1, 600), false); effect.update(0, camera, 0.2, 0, 1, 600); const light = rain.geometry.drawRange.count; assert.ok(light > 0); assert.equal(snow.visible, false); const before = rain.geometry.attributes.position.getY(0); effect.update(0.01, camera, 0.2, 0, 1, 600); assert.ok(rain.geometry.attributes.position.getY(0) < before); assert.equal(effect.update(0.01, camera, 15, 2, 1, 600), true); assert.ok(rain.geometry.drawRange.count > light); assert.ok(snow.visible && snow.geometry.drawRange.count > 0); const snowBefore = snow.geometry.attributes.position.getY(0); effect.update(0.01, camera, 15, 2, 1, 600); assert.ok(snow.geometry.attributes.position.getY(0) < snowBefore); assert.equal(effect.update(0.01, camera, 0, 0, 1, 600), false); assert.equal(rain.visible || snow.visible, false); } finally { effect.dispose(); } }); test('particles follow camera teleports and stay above the sampled ground', () => { const effect = createPrecipitation(() => 3); const camera = new Vector3(0, 10, 0); try { effect.update(0, camera, 8, 1, 1, 600); camera.set(1000, 20, -1000); effect.update(0.01, camera, 8, 1, 1, 600); for (const mesh of effect.group.children as any[]) { const positions = mesh.geometry.attributes.position; for (let i = 0; i < mesh.geometry.drawRange.count; i++) { assert.ok(Math.abs(positions.getX(i) - camera.x) < 25); assert.ok(Math.abs(positions.getZ(i) - camera.z) < 25); assert.ok(positions.getY(i) >= 3); } } } finally { effect.dispose(); } });