# Effects: particles, weather, day/night

## Particles

`createParticleEmitter(engine, opts)` in `src/graphics/Particles.js`. Camera-facing quads. One factory, named types:

| type | Where |
|------|--------|
| `fire` | Campfire puffs |
| `smoke` | Rising grey column |
| `sparks` | Short ballistic specks |
| `spray` | Hose / fountain jet |
| `dust` | Tire dirt, rate from speed |
| `wake` | Boat spray, rate from speed |

```js
createParticleEmitter(engine, { type: 'smoke', position: { x, y, z } });

const dust = createParticleEmitter(engine, {
  type: 'dust',
  rate: 0,
  getOrigin: () => wheelPos,
  getDrift: () => ({ x: -vx * 0.18, y: 0.25, z: -vz * 0.18 }),
});
dust.setRate(speed01); // 0–1
```

`createFirePuffs` is `type: 'fire'`. Soft disc map for now; pass `map` to swap in a texture. All puffs take scene fog; additive types (fire, sparks, wake) fade to black in fog so they do not glow through it.

Sandbox: fire pit uses fire + sparks + smoke; fountain uses spray; every vehicle emits dust; both boats emit wake.

## Weather

`createWeather(engine)` — rain (vertical streaks) and snow (camera-facing flakes), off by default. They spawn around the camera and recycle when you walk away.

```js
weather.setRain(true);
weather.setSnow(true);
```

GUI toggles in the sandbox.

## Day / night (optional)

`createEnvironment` loads named presets (`default-overcast`, `sunny`, `dusk`, `night`, `industrial`).

Optional cycle, off until you turn it on:

```js
environment.setCycle(true);
environment.setTimeOfDay(0.5); // 0 midnight · 0.25 dawn · 0.5 noon · 0.75 dusk
```

Moves the sun, intensity, fog, exposure, and PBR env-map intensity. Night is navy, not pitch black. Does not rebuild the sky cubemap every frame. PBR metals that used `trackIbl` go dark with the sun — the cubemap itself stays the daytime sky.

The sun’s shadow volume follows the camera (~64 m around you). Map size does not matter. Do not enlarge a world-fixed ortho box to “cover the level”.

## Lighting

PBR: `MeshStandardNodeMaterial` in `MaterialLibrary` (solid colours) and `loadPbrMaterial` in `PbrMaterial.js` (albedo, metallic, roughness, OpenGL normal, AO, height). Textured ground uses `createMappedMaterial` (lit + fog). PBR metals take `environment.envMap` on the material — not `scene.environment` — and `environment.trackIbl(mat)` so night dims the reflections. Do not use `MeshBasicNodeMaterial` for grass. Sun is a shadow-casting directional light; the shadow camera tracks the view. `createLighting(engine).addPointLight` for local lights (the campfire uses one). Player flashlight: `createFlashlight(engine, input, player, settings)` in `src/player/Flashlight.js`, toggle with L on foot (disabled while seated). Vehicle / boat lamps: `attachLamps` in `src/vehicle/Lights.js`, L toggles headlights while seated; braking brightens red tails. Fog is `THREE.Fog` plus a matching `scene.fogNode`, driven by the preset and the cycle.
