# Floating light and pooled particles The first particle path supplies soft, additive, depth-tested billboards for glowing motes and embers. In the editor, open **Atmosphere → Floating light**, add an effect, then adjust its center, half size, drift, color and glow. Preview leaves the saved draft unchanged. Save retains the source; Apply updates the shared development room. Discard, saved undo/redo, and source restoration use the existing authoring workflow. ## Source contract World format **14** adds optional `Place.particles`. Older formats reject that field; older worlds remain valid unchanged. `set-particles` replaces a place's complete emitter list, and `null` removes the optional field. A non-null list promotes the world to format 14 with the `particle-world.14` compiler identity. Durable undo restores both the prior field and the exact old world format. Concurrent edits to the same list conflict; other place properties retain their existing merge behavior. Each emitter declares a unique ID, world-space center, positive half extents, drift velocity, count, lifetime, billboard radius, RGB color, emission, unsigned 32-bit seed, `collision: "none"`, and low-quality count fraction. The supported ranges are defined in `packages/schema/particles.ts`. Limits are **8 emitters**, **512 slots per emitter**, and **2048 slots per place**. Invalid or oversized content is rejected before publication, leaving the accepted scene intact. The editor shows the requested count and budget. Particles are local presentation, with no ECS entities, colliders, durable state, or networked particle positions. Content revision identity includes their authored settings. Live effect edits preserve canonical simulation state, while simulation checkpoints retain and validate the world's new compiler identity. Clients share the same settings but do not synchronize individual particle phases. ## Renderer ownership Presentation envelope **8** carries the optional emitter list. Previous envelopes reject it. Both player projection and editor projection carry the field; place changes replace the whole list. Motion-only actor updates keep the emitter configuration without rebuilding it. The CPU pool reserves 2048 packed records and 2048 seeded random records once. Each slot loops over its declared lifetime, fades in and out, and reflects its center within the volume. Absolute presentation time avoids catch-up loops after suspension. Quality selects a stable prefix of each emitter's slots: High uses all, Balanced uses the midpoint between all and the declared low fraction, and Performance uses the low fraction, with at least one slot per active emitter. Reduced motion fixes visual time at zero. One fixed **65,536-byte storage buffer** belongs to each renderer. It adds no texture. The renderer uploads only the active prefix on an idle frame, draws one instanced billboard batch after opaque geometry, tests existing scene depth without writing it, and blends emitted light additively into the linear HDR target before tone mapping. Fog attenuates the emission. Particles cast no shadows and do not illuminate nearby objects. Additive blending does not require sorting. These are glowing particles, not general translucent surfaces, smoke, or physically colliding projectiles. The graphics owner disposes the particle buffer with its device and recreates it from retained presentation on recovery. The existing single-inflight submission rule governs uploads and resizing. Diagnostic exports include `particles` (the active quality-scaled count, including occluded/off-camera slots) and `requestedParticles` (the authored count). These are not visibility counters or measured GPU timing. ## Verification and remaining work `tests/particles.test.ts` covers malformed/budgeted source, deterministic bounded sampling across large time gaps, stable quality prefixes, exact source undo across restart, live simulation invariance, checkpoint restoration, and presentation versioning. The native renderer study compares pixels with particles behind and in front of a wall, checks time-dependent images, validates quality counts, rejects an oversized candidate without changing the image, exercises the maximum pool, repeats add/remove replacements, destroys the actual GPU device, and checks image/resource recovery. The browser authoring journey covers preview/discard, save/reload/undo/redo, narrow layout, shared live revisions and recovered quality counts. This implements the pooled CPU baseline. Compute emitters, textured sprite animation, world text, general transparency, material/effect graphs, emitter culling, pixel-overdraw budgets, physical device performance targets and the final art pass remain open in the full plan. Passing the software-GPU fixture does not close milestone 12. Verified results and source hashes: [acceptance record](evidence/particles-acceptance.json). The six distinct browser checks and 674 passing headless checks qualify the listed paths; no numbered roadmap milestone is closed.