v1.5.0
QwenAudio/CosyVoicev1.5.0Mar 6, 2026by github-actions[bot]
AI Summary
Adds the Morph effect, WBOIT transparency, new audio features, and a significant UI overhaul.
Key Highlights
- New Morph effect with multiple targets and styles
- WBOIT transparency support
- UI overhaul for Scenes, Layers, and Presets panels
- New audio features (dominant_chroma, zcr)
New Features
- Morph effect
- WBOIT
- Audio features (dominant_chroma, zcr)
- UI overhaul
Full Release Notes
### Fixed - Scene cue delete button disappearing when the same preset is added as a cue multiple times (egui widget ID collision) - Crash (index out of bounds) when deleting a scene cue while the timeline is playing ### UI - Right panel restyle: single-row param layout (name/slider/value/M/O), compact 16×14 MIDI/OSC badges, smaller Reset All button, large particle count header with 3px health bar, standalone bordered blend mode badge, compact particle param rows replacing grid, tab-strip obstacle source selector with active state styling, compact obstacle slider rows with separate value labels, audio mapping hover background lift with fixed-width 52px feature names - Remove redundant activity dots from Settings subsection enable rows; status bar always shows MIDI/OSC/WEB/NDI indicators with three-state dots (active/enabled-idle/disabled) - Consolidate MIDI, OSC, Web, NDI/Outputs, and Global into single collapsible "Settings" section with subsections — header shows labeled status dots, subsection headers use smaller font/arrow for visual hierarchy, protocol-specific badge colors - Trigger grids (MIDI + OSC) use fixed-width label columns (52px) for proper badge alignment across rows - OSC TX settings wrapped in subtle bordered frame; Global settings use fixed-width labels aligned to dropdowns - Layers panel visual refresh: type color legend (FX/MD/WC), left color strip per card, layer index numbers, type badges, type-colored add buttons (all three on one row), subtle "Clear All" text link with red hover/confirm, footer type breakdown counts, hover-only delete buttons, stronger dimming for disabled layers - Reorder sidebar panels: Effects → Layers → Presets → Scenes - Layer badge shows "N/8" capacity format - Scenes panel visual refresh: 2-column scene grid tiles, two-line cue rows with bottom progress bars (hold elapsed + transition progress with stripes), accent active-cue highlighting, pulsing red LIVE dot, GO button green fill, STOP red outline, hover-reveal delete buttons, hold time always visible, scrollable cue list (up to 6 visible), add-cue bar with separator - Timeline bar polish: accent-colored active cue, striped from-cue during transitions, two-line target cue label (name + "Morph 58%"), transition-typed playhead colors - Presets panel: add "Save current state as preset:" label above name input, and make "+ New" button clear all layers to a fresh Phosphor state with two-click confirmation when unsaved changes exist - Amber dirty-state styling for presets panel: custom header with pulsing dot and inline preset name, amber-tinted dirty bar with Update/Reset buttons, amber selected tile, pulsing card border, and bumped tile height to 26px - Add effect type indicators to effects panel: left color strip (purple SH / orange PS / teal FB), two-char badge, type legend, and footer breakdown count - Add hover tooltips to effect type color legend explaining Shader, Particle+Shader, and Feedback categories - Show Copy and Edit buttons side by side — Copy enabled for visible built-ins only, Edit enabled for user effects only; fixes Copy being clickable on hidden Phosphor branding effect - Add "msc: N" badge to PARTICLES panel showing `max_scaled_count` with tooltip; merge blend mode and feature badges into single wrapping horizontal row; normalize morph section to 9pt font - Add `EffectType` enum (Shader, Particle, Feedback) with optional `effect_type` field in .pfx format — auto-detects from data when absent - Tag 5 feedback effects (Accretion, Array, Chaos, Mycelium, Turing) with explicit `"effect_type": "feedback"` in their .pfx files ### Audio - Add `dominant_chroma` feature: CPU-side argmax of 12 chroma bins, normalized 0–1, forwarded to both fragment and particle GPU uniforms - Cymatics audio remapping: chroma-driven Chladni mode selection (curated visually-distinct (n,m) pairs per pitch class), mfcc[0] vibrational amplitude, chroma peakedness pattern clarity - Murmur audio remapping: mfcc[1] flock cohesion (bright=tight, dark=dispersed), mfcc[3] predator aggressiveness, flux speed agitation, dominant_chroma rim/sky hue; fix emitter waves by probing whole screen + inheriting donor heading - Symbiosis audio remapping: mfcc[4-6] per-species force modulation (timbre shifts ecology), dominant_chroma species color rotation, flux interaction radius expansion, zcr Brownian noise jitter - Morph audio remapping: dominant_chroma target shape selection (pitch class picks morph target instead of sequential), mfcc[1] transition speed modulation, mfcc[2] mid-transition scatter/explosion strength, chroma-tinted background - Flux audio remapping: mfcc[1] curl strength (bright=tight spirals, dark=loose), flux-driven turbulence agitation, dominant_chroma emission/background hue anchor - Add `zcr` (zero-crossing rate) to ParticleUniforms for compute shader access ### Effects - Add obstacle collision to all 11 remaining particle sim shaders (phosphor, flux, murmur, raster, tesla, genesis, cymatics, symbiosis, turing, morph, as) — obstacles now work across all 16 effects ### Fixes - Fix preset showing as dirty during ParamMorph scene transitions — morph interpolation now resets param changed flags since it's timeline playback, not user edits - Clamp particle count to GPU dispatch dimension limit (`max_compute_workgroups_per_dimension × 256`) to prevent validation errors on high-count effects - Add per-effect `max_scaled_count` field — quality multiplier won't push past this ceiling; applied to Accretion (60K), Genesis (24K), Murmur (2.4M), and Symbiosis (4M) - Hide Stress test effect from effects panel - Fix morph slider animating when auto-cycle mode is "Off" — transition progress now only advances when auto-cycling is active - Remove redundant image source UI (IMG badge, image selector dropdown, Load Image/Video/Webcam buttons) from particle panel — morph targets handle image loading - Fix morph snapshot/image/text/video filling wrong slot when `target_count` diverges from def count — all handlers now use def vector length for slot selection and pad gaps ### Morph Effect (New) - **Shape target morphing**: particles store home positions for up to 4 target shapes and morph between them on beat drops with spring physics and turbulence - **Multiple target types**: image files, geometry shapes (circle, ring, grid, spiral, heart, star), and random scatter — mixed freely across 4 slots - **5 transition styles**: Spring (default), Explode-reform, Flow (curl noise), Cascade (left-to-right wave), and Direct (pure lerp) — selectable via UI dropdown - **Per-particle stagger**: each particle transitions at a slightly different time for organic cascading motion - **Audio reactivity**: onset triggers morph to next target, bass drives spring vibration, mid adds turbulence during transition, brilliance creates scatter - **Strided aux buffer**: 4x normal aux size interleaves target data (32MB at 500K particles), no bind group changes - **ParticleUniforms extended**: 4 new fields (morph_progress, morph_source, morph_dest, morph_flags) — 784→800 bytes, existing effects unaffected - **Morph UI controls**: target slot display with click-to-morph buttons, transition progress bar, auto-cycle mode (Off/On Beat/Timed), hold duration slider, transition style dropdown, runtime image and geometry loading into morph slots - **Text morph targets**: type any string in the morph panel and particles form the letters — uses fontdue to rasterize Inter-Bold glyphs into a bitmap, then samples through the standard image pipeline. Supports `"text:HELLO"` in .pfx files - **Video frame morph targets**: click "+ Video" to load a video file — evenly-spaced frames fill available morph slots (up to 4), cycling between different video frames on beat - **Snapshot morph targets**: click "Snapshot" to freeze current particle positions into a new morph target — GPU readback captures alive particles as a reusable shape ### WBOIT (Weighted Blended Order-Independent Transparency) - **Order-independent transparency**: new `"blend": "wboit"` mode approximates correct alpha compositing in a single unsorted pass — no back-to-front sort needed - **Two-pass rendering**: particles render into accumulation (Rgba16Float) + revealage (R8Unorm) targets with WBOIT weight function, then a fullscreen composite blends onto the scene - **Automatic compute raster fallback**: WBOIT is incompatible with compute rasterization; `"render_mode": "compute"` + `"wboit"` falls back to billboard with a warning, and `"auto"` mode excludes WBOIT effects - **Resize-safe**: WBOIT textures recreated on window resize alongside compute raster framebuffer ### Symbiosis Effect (New) - **Multi-species particle life simulation**: 2–8 species interact via an asymmetric 8×8 force matrix, producing emergent ecosystems, crystals, and predator-prey dynamics - **6 named presets**: Ecosystem, Crystals, Hunters, Membrane, Chaos, Symmetric — smoothly interpolated on switch - **Audio-reactive matrix**: bass boosts force scale, mid modulates friction, presence/brilliance expand interaction radius, onset shuffles random matrix entries for emergent disruption - **Toroidal topology**: particles wrap around screen edges with correct wrapped-distance neighbor queries - **Force matrix in ParticleUniforms**: 8×8 float matrix (256 bytes) appended to uniforms — no new bind groups needed, all existing effects unaffected ### Fix: CR scatter bind group crash on particle quality change - **Request adapter-supported buffer limits**: device now requests the GPU adapter's actual `max_storage_buffer_binding_size` and `max_buffer_size` instead of wgpu defaults (128MB/256MB), allowing high-VRAM GPUs to use their full capacity - **Cap particle count to device limits**: after applying quality multiplier, particle count is clamped so the largest buffer (`sorted_particles_buffer` = N×9×4 bytes) stays within the device's storage buffer binding limit — prevents invalid bind groups and crash on quality change ### Gaussian Area Splat for Compute Rasterizer (Fix) - **Soft Gaussian splat for particles >1.5px**: compute raster now matches billboard renderer output for larger particles (e.g., Array at ~2.7px radius). Previously all energy concentrated into a 2×2 bilinear kernel, making dim-colored effects nearly invisible - **Three-tier kernel**: single-pixel (≤1px), bilinear 2×2 (1–1.5px), Gaussian area splat (>1.5px, capped at 8px). Weight `col.a × glow²` matches billboard's `SrcAlpha` blend - **Multi-tile binning**: particles overlapping multiple 16×16 tiles are binned/scattered to all covered tiles (up to 3×3). Sorted buffer sized 9× max_particles accordingly - **Tiled path support**: Gaussian loop in shared-memory tiled shader with per-pixel tile boundary clipping ### Preset: Particle Image Save/Restore (Fix) - **Particle image path now saved in presets**: selecting a different particle image (e.g., skull → phoenix) and updating the preset persists the choice across preset loads - **Mark dirty on particle/obstacle changes**: changing particle image, video source, webcam source, video transport settings, or obstacle settings now marks the preset as dirty so the Update button appears - **Backward compatible**: old presets without `particle_image_path` load normally (default image from .pfx) ### Particle Quality Setting (New) - **Global quality multiplier**: Low (0.25x), Medium (0.5x), High (1x), Ultra (2x), Max (4x) — scales both `max_count` and `emit_rate` proportionally so fill time stays consistent - **Default: High (1x)** — no change for existing users; backward-compatible with old settings.json files - **Combo box in Global panel**: same pattern as theme selector; changing quality mid-session reloads the active effect to rebuild GPU buffers - **Built-in effects upgraded**: all effects now default to 1–2M particles with compute rasterization as the baseline ### Window Size - **Default window size changed to 1920×1080** (was 1280×720) ### Compute Rasterization (New) - **Atomic framebuffer rendering**: 3-pass compute raster pipeline bypasses vertex→rasterizer→fragment for sub-pixel particles. Eliminates 2×2 fragment quad waste and rasterizer bottleneck for high particle counts - **Fixed-point encoding**: 12-bit fractional precision (4096 scale) via `atomicAdd` on 4 separate i32 storage buffers (R/G/B/A), supporting up to ~1000 overlapping particles per pixel within i32 range - **Size-adaptive kernel**: single-pixel fast path for particles ≤1.5px, Gaussian kernel footprint for 1.5–5px, billboard fallback for larger particles - **Render mode field**: `"render_mode"` in .pfx files — `"billboard"` (default), `"compute"`, or `"auto"` (auto-selects compute for ≥100K particles with no sprites/trails and size ≤0.005) - **Fullscreen resolve**: render pass with hardware blend state (additive or alpha) reads decoded framebuffer with Reinhard tonemapping for additive mode - **COMPUTE badge**: cyan badge in particle panel when compute rasterization is active - **Tiled shared-memory accumulation**: 4-pass bin→prefix-sum→scatter→tile-raster pipeline for ≥50K particles. Accumulates in 4 KB workgroup shared memory per 16×16 tile (~100× faster atomics), then flushes to global framebuffer with plain stores. Direct draw path retained as fallback for low counts. Automatic path selection based on 1-frame-latent alive count ### Performance & Build Optimization - **Build profiles**: dev builds use opt-level 1 (deps at 2 for faster shader compilation), release uses thin LTO + codegen-units=1 - **GPU buffer clears**: spatial hash dispatch uses `encoder.clear_buffer()` instead of allocating a zeroed Vec per frame (up to 262KB saved per frame at max grid) - **Sort params cached**: bitonic sort parameters written once at buffer creation via `mapped_at_creation` instead of ~210 `write_buffer` calls per frame - **Parallel prefix sum**: spatial hash prefix sum upgraded from single-thread sequential to 256-thread Blelloch scan with shared memory (supports up to 65K cells) - **Pipeline cache**: compiled shader data persisted to `~/.config/phosphor/pipeline_cache.bin` for faster startup on subsequent launches - **Device loss handling**: GPU device lost callback + uncaptured error handler + graceful render-time detection (no more hard crash on driver reset) - **GPU profiler** (`--features profiling`): wgpu-profiler integration with egui overlay panel, timestamp query support - **Clippy pedantic**: workspace-level clippy lints enabled, auto-fixed 500+ warnings, rustfmt config added - **FxHashMap**: `rustc-hash` for runtime-only hash maps (MIDI trigger tracking) ### Audio Panel Redesign (Improved) - **BPM ring**: circular beat-phase arc with orbiting dot replaces static BPM number; flashes white on downbeat - **Chroma wheel**: radial 12-segment pie chart with energy-proportional radius replaces linear bars; dominant note displayed in center - **MFCC heatmap**: single-row dark blue→cyan→white timbral fingerprint replaces bar graph; selective labels (DC, Slope, Shape, Formant, Det6) - **Spectrum bars**: vertical gradient mesh bars (bright top→faded bottom) with peak-hold markers (0.95 decay) - **Dynamics section**: 7 labeled rows with thin track bars + percentage values; kick uses boolean dot indicator - **Section headers**: self-documenting sections (SPECTRUM 7 bands, DYNAMICS 7 features, CHROMA 12 pitch classes, TIMBRE·MFCC 13 coefficients) - **Tooltips**: per-bar spectrum tooltips (name, Hz range, character), per-row dynamics tooltips (feature description), per-cell MFCC tooltips (coefficient meaning), chroma wheel and BPM ring tooltips - **Footer**: feature count summary (7 bands · 7 dynamics · 12 chroma · 13 mfcc · 512 fft) ### MFCC + Chroma Audio Feature Extraction (New) - **13 Mel-Frequency Cepstral Coefficients**: captures timbral content — different instruments/voices produce distinct MFCC patterns. Computed from 26-band mel filterbank + DCT-II on the existing 4096-pt FFT - **12 Chroma pitch-class energies**: maps spectral energy to musical pitch classes (C through B). Individual notes/chords light up specific bars. Frequency range 20–5000 Hz - **GPU-accessible**: new `mfcc(i)` and `chroma_val(i)` WGSL helper functions in both fragment and compute shaders. ShaderUniforms 256→288 bytes, ParticleUniforms 416→528 bytes - **Audio panel visualization**: chromatic-colored chroma bars (12 pitch classes) and MFCC bar graph in the audio panel overlay - **Smoothed + normalized**: 25 new features go through the existing adaptive normalizer and asymmetric EMA smoother (attack 0.03s, release 0.15s) - **Non-breaking**: existing effects unchanged — they simply don't read the new fields. NUM_FEATURES 20→45 ### Spatial Hash Grid (Improved) - **Dynamic grid sizing**: `grid_dims(N)` computes `clamp(sqrt(N/16), 40, 256)` — grid scales automatically with particle count instead of fixed 40×40 - **Shader constant patching**: SH_GRID_W/H constants in particle_lib, count, prefix_sum, and scatter shaders patched at pipeline creation time - **Particle panel slider fix**: emit_rate slider max now scales to 10% of max_count for high-count effects (e.g. 100K emit_rate for 1M particles) ### Murmur Effect (Upgraded) - **Topological K=7 nearest neighbors**: replaced fixed-radius Boids with scale-free K-nearest neighbor queries — flock correlations work from 40K to 1M particles without parameter tuning - **Vicsek noise phase transitions**: angular noise (eta parameter) modulated by bass drives order→chaos transitions; proper research-accurate model instead of ad-hoc disorder - **Predator avoidance**: Lissajous-drifting predator with onset-triggered strike jumps; exponential falloff repulsion causes realistic flock splits - **Heading-level roost centering**: quadratic ramp centering force feeds into heading computation (not just position) — prevents alignment-consensus drift that plagued the old position-only correction - **KNN-based rim lighting**: edge detection from neighbor anisotropy (COM displacement / k-radius); color_mode slider (0=silhouette, 1=full rim); audio-reactive brightness (RMS) and color temperature (centroid: cool blue ↔ warm amber) - **Non-accumulating color**: base color re-derived from gradient each frame instead of reading previous frame's output — prevents wash-out over time - **Adaptive separation**: K-th neighbor distance as interaction scale; density-invariant at any particle count - **Donor-based emission**: new particles spawn near existing flock members for organic growth - 1M particles, 8 params (noise_eta, cohesion, color_mode, predator, separation, speed, smoothing, audio_drive), alpha blending, bloom postprocess ### Mycelium Effect (New) - **Chain-based growth system**: 2,500 pre-allocated chains (80 segments max each, 200K particles total) — leader particles at tips follow curl noise flow fields while depositing follower particles that form spring-connected tendrils - **Self-activation architecture**: dead particles detect when they should activate by reading chain state from the input buffer — no cross-thread writes, no race conditions. Growth propagates via time-based segment intervals - **Branching on audio onset**: reserve chains (beyond initial 100 leaders) self-activate by branching from random active chain tips; onset boosts branch probability 15×, brilliance widens branch angles - **Spring physics**: followers connected by asymmetric springs (strong toward tip, weak toward root) with critical damping; creates organic elastic motion through the network - **Death cascade**: roots age faster with spectral flux; when a root dies, death propagates tip-ward with 50ms/segment delay — visual dissolve from root to tip, then chain slot recycles for new branches - **4 color modes**: depth (teal-blue root → forest green → phosphorescent tip), generation (teal/gold/magenta by branch depth), velocity (dim blue → bright green), age (bright green → dark brown) - **Beat-phase traveling wave**: periodic brightness pulse travels root→tip synced to detected beat, modulated by RMS - **Bioluminescent feedback trails**: background shader with differential RGB decay (green persists longest), organic noise warp for living feel, HDR clamp - **Audio integration**: bass→growth speed, onset→branching, mid→curl intensity, brilliance→branch angle, flux→death rate, beat_phase→traveling glow, rms→brightness, centroid→hue shift - 200K particles, 8 params, additive blending, bloom postprocess, obstacle collision ### Chaos Effect (New) - **Strange attractor dynamics**: 5 classic attractors (Lorenz, Rössler, Halvorsen, Thomas, Chen) with RK4 integration — particles trace chaotic trajectories that reveal butterfly, torus, and knot-like shapes through accumulated feedback trails - **Attractor morphing**: spectral centroid smoothly blends between adjacent attractor types; slider + audio drive crossfade the derivative functions (all attractors normalized to [-1,1] space) - **Audio-reactive bifurcation**: bass shifts the bifurcation parameter across chaos boundaries (e.g. Lorenz ρ through ~24.74), onset provides impulse push past critical points for dramatic order→chaos transitions - **RK4 integrator**: 4th-order Runge-Kutta for accurate trajectory integration; brilliance modulates time step for faster/more chaotic motion at high frequencies - **4 color modes**: velocity (blue→gold speed ramp), z-depth (cool→warm gradient), wing (cyan vs magenta by sign of attractor x), age (bright warm→dim cool fade) - **Feedback trail rendering**: background shader with centripetal UV warp, differential RGB decay (red fades fastest → cool aging trails), HDR clamp - **3D projection**: slow constant-speed Y-axis rotation, perspective depth scaling via projection param, depth-based size and brightness modulation - **Divergence guard**: NaN/out-of-bounds particles reset to random position near origin; soft clamp to normalized space prevents runaway - 50K particles, 8 params, additive blending, bloom postprocess, obstacle collision ### Turing Effect (New) - **Gray-Scott reaction-diffusion**: full 2D R-D simulation on ping-pong compute textures, running N steps/frame (default 8, audio-modulated up to 32) - **Hybrid R-D + particles**: 200K particles sample the R-D field for gradient-based chemotactic forces, flowing toward high-concentration pattern regions - **Particle coloring from chemistry**: color, size, and alpha derived from local B concentration — particles are visible in pattern regions, transparent in substrate - **Audio-reactive chemistry**: bass→feed rate (2.5× boost), mid→kill rate (2.5× boost), brilliance→diffuse_b, onset injects 4 randomized B drops per beat (PCG hash, 0.35 strength), beat doubles sim steps - **Particle audio reactivity**: onset pulses gradient force (3× surge), bass pumps particle size, beat kicks velocity, RMS brightness (0.8 coeff), centroid shifts palette (0.5 coeff) - **Gray-Scott parameter space**: feed/kill rate sliders traverse spots → worms → mitosis → coral → chaos regimes - **R-D infrastructure**: new `ReactionDiffusionDef` in particle types, `RDUniforms` struct, group 4 bind group for particle compute, `create_rd_resources()` factory - 512×512 R-D grid, 8 params (gradient_strength, drag, feed_rate, kill_rate, diffuse_b, sim_speed, drop_size, brightness) ### Accretion Effect (New) - **Tiled N-body gravity**: O(N²) gravitational simulation using workgroup shared-memory tiling (GPU Gems 3 Ch. 31) — every particle attracts every other, forming orbital systems, accretion discs, and slingshot ejections - **Angular-momentum-preserving damping**: only radial velocity is damped, preserving tangential (orbital) velocity for stable long-lived disc structure - **Audio seed injection**: beat onsets inject "seed" particles (local attractors within the disc); seed mass scales with `mid`, gravity strength modulated by `bass` - **Spiral feedback trails**: background shader warps trails with inward pull + rotation, creating galaxy-like spiral arms; differential RGB decay shifts aging trails from warm gold to cool blue - **4 init patterns**: disc (tangential orbits), ring (near-circular), two-body (binary system), collapse (zero-velocity infall) - **3 color modes**: velocity (blue→gold), proximity to seeds (blue→orange), orbital energy (blue=bound, red=escaping) - **Audio reactivity**: onset brightness flash (warm-tinted), bass particle size breathing, RMS glow, bass/mid drive feedback warp strength - 30K particles, 8 params, additive blending, central pressure support, obstacle collision ### Array Effect (New) - **Audio-band speaker emitters**: 5 toroidal ring emitters, one per frequency band (sub-bass through brilliance), each firing disc-shaped particle rings outward like speaker cones pushing air - **Two layout modes**: vertical speaker stack (default) and concentric rings — crossfade with `layout` param - **Per-band audio reactivity**: each emitter responds to its own frequency band for emission density, speed, and glow - **Beat-phase breathing**: ring radii modulate with beat phase for rhythmic pulsing - **ParticleUniforms expanded** 400→416 bytes: added `low_mid`, `upper_mid`, `presence`, `brilliance` audio fields to compute shaders (all 7 bands now available) - 300K particles, 8 params (trail_decay, ring_radius, spread, layout, color_mode, speed_mult, beat_pulse, emitter_glow) ### Obstacle Refinements - **Contain mode**: new collision mode that traps particles inside the obstacle shape — inverted collision test, binary search, and normals - **Flow Around improvement**: redirects approach energy into tangential direction instead of stripping it, preventing pile-ups - **Video obstacles**: luminance-to-alpha conversion so video frames work as obstacles (bright = solid, dark = passable); UI now shows "Video: filename" - **Webcam cleanup**: Clear and source-switching now properly stop webcam/depth when no longer needed - **Tooltips**: all obstacle panel controls have descriptive hover text ### Monocular Depth Estimation (New) - Feature-gated `depth`: `cargo run --features depth,webcam` for MiDaS v2.1 small monocular depth estimation - Webcam frames → background `phosphor-depth` thread → ONNX Runtime (ort crate) → 256×256 depth map → obstacle texture - Particles collide with person's depth silhouette — nearby objects block, far objects pass through - Model download from HuggingFace (~66 MB), user-initiated via UI button with progress indicator - Model cached at `~/.config/phosphor/models/midas_v21_small_256.onnx` - 1-2 frame latency depth pipeline: bounded(1) channels, try_send drops stale frames - UI: "Depth" button in Obstacle panel (auto-shows "Download" if model missing, progress % during download) - Preset save/load: `obstacle_depth` field with backward-compatible serde defaults - 7 new tests (downscale, model path, download progress states, preset serde) — 352 total ### Obstacle Collision (New) - Image-based 2D obstacle textures for particle collision — load PNG/JPEG/WebP with alpha channel - 3 collision modes: **Bounce** (reflect velocity along surface normal, scale by elasticity), **Stick** (zero velocity, hold at surface), **Flow Around** (tangent projection, remove normal component) - Obstacle texture extends compute group 1 bind group (bindings 2+3) alongside existing flow field - WGSL collision helpers in `particle_lib.wgsl`: `obstacle_alpha()`, `obstacle_normal()` (central-difference gradient), `apply_obstacle_collision()` — any `*_sim.wgsl` can call them with 3 lines - `ParticleUniforms` extended 384→400 bytes: obstacle_enabled, obstacle_threshold, obstacle_mode, obstacle_elasticity - Collapsible "Obstacle" UI panel in right sidebar: enable toggle, Load Image (rfd), Clear, mode dropdown, threshold/elasticity sliders - Integrated into Cascade effect; same 3-line pattern (`prev_pos`, integrate, `apply_obstacle_collision`) works in any particle sim - Preset save/load with backward-compatible serde defaults - Opaque image support: images without alpha (JPEG, opaque PNG) auto-detect and use luminance as collision mask — dark areas are passthrough, bright areas are solid - Anti-strobe: binary search finds exact surface contact point along integration step (4 iterations), places particle just outside surface; velocity reflection only when moving into obstacle - Texture format `Rgba8Unorm` (not sRGB) for raw data sampling; UV Y-flip for correct clip→texture mapping - 6 new tests (ObstacleMode conversions, preset serde, backward compat, alpha preprocessing) — 351 total ### Cascade Effect (Fix) - Fixed beat flash strobe: replaced binary `u.beat` full-screen flash with smooth `beat_phase` envelope (fast 25%-of-beat quadratic fade), reduced amplitude from 0.05 to 0.03 ### Cascade Effect (New) - **Cascade**: solid walls of particles emit inward from all 4 screen edges, audio-segmented by frequency band - Pixel-perfect wall emission: particle index maps deterministically to perimeter pixels (1920 top/bottom + 1080 left/right at 1080p), guaranteeing gap-free solid walls that scale with resolution - Band-to-edge mapping: bottom=bass+sub_bass (red-orange), left=mid (teal), right=mid (blue-violet), top=centroid (white-cyan) - Audio directly drives wall penetration depth: band energy controls particle speed, so walls extend/retract with the music like Aurora's ribbons - Continuous audio push force during simulation keeps accelerating particles when their band is active - Curl noise turbulence for organic lateral drift, beat-triggered velocity pulse, onset jitter - 3 color modes: band colors (4 distinct per edge), monochrome white-blue, speed/energy gradient - Background shader: feedback trails with directional inward UV warp, per-band audio-reactive edge glow strips (width scales with audio), beat flash - Functions as both standalone effect and layerable edge frame via convergence param + brightness alpha compositing - 8 params: trail_decay, inward_speed, spread, curl_strength, color_mode, edge_glow, convergence, beat_sync ### Genesis Effect (Retuned) - **Genesis** (Particle Lenia): retuned from reference implementation (znah.net/lenia) for proper self-organizing behavior - Ring kernel calibrated to reference ratios: peak at 30% of R, width 23% of R (proper ring with falloff) - Kernel weight W_K scaled from 0.003 → 0.02 for correct field density at particle count - Interaction radius narrowed to [0.05, 0.20] from [0.10, 0.50] — manageable search radius - Removed curl rotation (was compensating for over-smooth density field at 20K) - Stronger growth forces (step×0.10) and higher speed cap (MAX_SPEED=0.25) for VJ-paced dynamics - Soft radial containment spring past screen edge + hard clamp safety net (replaces square boundary) - Beat-triggered seed drops: ~3% of particles teleport to a random screen location on each beat, creating fresh organisms that self-organize from the music - 9 initial seed clusters in 3×3 grid (fills screen), zero-mean paired-hash noise (no drift bias) - Stronger bloom (threshold 0.15, intensity 0.55) for visual presence ### Tesla Effect (New) - **Tesla** (magnetic field): 200K charged particles follow magnetic field lines as a flow field, creating interweaving helical trajectories - Magnetic monopole flow field: particles follow superposition of dipole field directions; charge sign determines direction along field lines (+charge follows B, -charge follows -B) - 4 dipole arrangements via `dipole_mode` param: parallel (same polarity), antiparallel (bar magnet, default), ring (4 alternating), quadrupole (4 + oscillating center) - Orbital correction near poles: smoothly blends field-following to tangential orbit, preventing convergence at sink poles - Helical oscillation: per-particle perpendicular sine wave with random phase, controlled by `helix_tightness` - Proximity dimming: particles near dipoles render dim, brightening as they arc away - Charge-based coloring: cyan for positive, magenta for negative; `charge_ratio` controls mix - Audio-reactive: bass drives flow speed, onset triggers velocity jitter, beat triggers per-particle polarity flips (cyan↔magenta) - 3 color modes: charge-based (cyan/magenta), speed-based (cool→hot), lifetime gradient (cool→warm) - Feedback trails with electric UV shimmer, dim background field line visualization - 8 params: trail_decay, field_strength, charge_ratio, dipole_mode, field_rotation, color_mode, helix_tightness, flip_sensitivity ### AoS → SoA Particle Buffer Refactor - **Structure of Arrays layout**: split single 64-byte `Particle` storage buffer into 4 separate 16-byte SoA buffers (`pos_life`, `vel_size`, `color`, `flags`) — position-only reads (spatial hash, sort keygen) now load 16 instead of 64 bytes per particle (4× bandwidth savings) - **13-entry compute bind group**: bindings 1-4 read, 5-8 write, 9 counters, 10 aux, 11 dead, 12 alive indices - **6-entry render bind group**: 4 SoA read buffers + uniforms + alive indices - **`read_particle()` / `write_particle()` helpers** in particle_lib.wgsl — effect compute shaders use convenience functions, hot-path neighbor reads (murmur boids) access individual arrays directly - **Spatial hash and sort keygen optimized**: count/scatter shaders bind only `pos_life`, sort keygen binds only `vel_size` - Request `max_storage_buffers_per_shader_stage: 16` (all desktop GPUs support this) - Total memory identical (64 bytes/particle), just reorganized for better GPU cache line utilization ### Raster Shard Flex - **Flexible shard motion**: Voronoi shards deform organically instead of moving as rigid blocks — distance-dependent rotation twist, per-particle noise within shards, and wider burst spread with outer particles flying further ### Raster Grid Artifact Fix - **Jittered grid sampling**: ±0.4×step deterministic offset per particle breaks up visible row/column banding in smooth gradient areas - **Bilinear color interpolation**: fractional pixel positions sample from 4 surrounding pixels, eliminating color stairstepping in gradients - **Gradient-based size modulation**: luminance gradient magnitude stored in `home.w`; smooth areas get 30% larger particles (fill gaps), edges stay neutral - **Sparkle boost**: bright pixels at high-gradient locations (stars, glints) get audio-reactive size pulsing — per-particle phase offset creates independent twinkling driven by onset and mids - New unit tests for jitter, bilinear sampling, and gradient helpers ### Raster Image Loading Fixes - **Fix 2048x2048 image loading**: `upload_aux_data()` no longer shrinks aux buffer below `max_particles` size — subsequent `update_aux_in_place()` calls for larger images were silently dropped - **Fix image selector not updating**: switching built-in images now updates `ps.def.emitter.image` so the ComboBox reflects the active selection - **Fix particle slider clamping**: slider ranges now dynamically extend to include the current value — prevents Raster's `emit_rate=100K` / `lifetime=999` from being silently clamped to slider defaults, which corrupted the effect every frame the panel was drawn - **Built-in effects are runtime-only**: particle slider changes no longer write back to `effect_loader` for built-in effects — use presets to persist tweaks - **Warning on aux buffer overflow**: `update_aux_in_place()` now logs a warning when a write is skipped due to buffer size - Raster particle cap raised from 500K to 2M (covers 2048² images at grid step=1) - Raster default particle size reduced from 0.004 to 0.002 ### Particle Video/Webcam Source + Transitions - **Video as particle source**: Raster (and any image-emitter effect) can now use video files as particle source — particles update home positions per-frame tracking video content - **Webcam as particle source**: live webcam feed drives particle positions in real-time (feature-gated `webcam`) - **Source transitions**: smooth 0.5s interpolation of particle home positions when switching between image/video/webcam sources (no hard snap) - **Per-frame aux updates**: pre-allocated aux buffer at `max_particles` size enables `write_buffer` updates without recreating GPU bind groups (8MB DMA transfer for 500K particles) - **`sample_rgba_buffer()`**: new function samples raw RGBA byte data directly, skipping file I/O — used for video frame and webcam frame particle sampling - **UI source controls**: particle panel shows source type badge (IMG/VIDEO/CAM), source name, Load Video / Webcam buttons (feature-gated), video transport (play/pause, speed, loop, seek) - **Preset save/load**: particle video path, speed, looping, and webcam source persisted in `LayerPreset` with serde defaults for backward compat - **Load Image button**: users can load custom PNG/JPEG/WebP images as particle source (replaces default image) - **Animated GIF as particle source**: GIFs with multiple frames auto-detect as animated source with per-frame particle position updates (same as video, no feature gate required) - **Background loading**: all particle source loading (image, GIF, video) happens on a background thread via `ParticleSourceLoader` — no UI freeze during decode - **EmitterDef `video` field**: `.pfx` files can specify `"video": "clip.mp4"` or `"video": "webcam"` for built-in video/webcam source at effect load time - Video decode reuses existing `media/video.rs` infrastructure (ffmpeg pre-decode to RAM, 60s max) - **Built-in image selector**: combo box in particle panel for quick-switching between bundled raster images (skull, phoenix, jellyfish, hand, samurai_mask) without file dialog - **Morph-safe preset loading**: when a preset layer has the same effect already loaded, skip the full effect reload — keeps particle systems alive so morph transitions interpolate params smoothly instead of destroying and rebuilding all particles - 12 new tests: `sample_rgba_buffer` (5), `ParticleImageSource` (2), `SourceTransition` (3), `LayerPreset` serde (3), `EmitterDef` serde with video (2) ### Raster Effect (New) - **Raster** (video wall): 500K particles map to image pixel positions, colored by source image - Voronoi shard fragmentation: 32 seed points create irregular fragments with per-shard rotation, translation, and depth variation - Frayed edges: particles near Voronoi cell boundaries break free with individual jitter - Three bass displacement modes via `bass_mode` param: shards (default), tangential swirl, radial push - 2D sinusoidal wave displacement from mids, onset-driven per-particle scatter from highs - Spring-return physics pull particles back to displaced home positions (sustained audio holds displacement) - Beat onset impulse with shard-coherent burst direction - Luminance-based particle sizing: brighter pixels render larger for visual depth - 8 exposed params: trail_decay, spring_k, bass_strength, mid_wave, high_scatter, burst_force, depth_scale, bass_mode - Optional feedback trails via trail_decay for motion blur during scatter - Image source `MAX_DIM` raised from 512 to 2048 for higher-resolution sampling ### Particle Effects Overhaul - **Delete 4 effects**: removed Coral, Helix, Nova, Vortex (low quality, never worked well) - **Murmuration → Murmur**: renamed, removed feedback trails (root cause of "sperm" look), brighter sky for contrast, larger/darker/more opaque particles (0.014 size, 0.9 alpha), reduced count 70K→40K - **Ribbons fix**: lower feedback clamp 0.12→0.06, stronger vignette, halved particle brightness and alpha to prevent additive washout - **Veil fix**: lower feedback cap 0.4→0.15, stronger decay dampening, halved particle brightness and alpha, minimum dampening floor even without audio - **Cymatics enhancement**: 25K→50K particles, emit rate 1700→3500, burst 100→500, 3 new params (rotation, symmetry, glow), more vivid color gradient, stronger nodal line contrast - **Swarm → Spirograph**: complete reimagine — hypotrochoid parametric curves with 5 arms of different petal-count patterns, drifting centers, audio-reactive ratio morphing. 6 params: trail_decay, draw_speed, pattern_scale, complexity, drift, color_spread - **Spirograph** (new): multi-pattern hypotrochoid curves with 5 arms of distinct petal-count patterns, drifting centers, audio-reactive ratio morphing. Replaces Swarm. - **Compute shader `param()` access**: particle compute shaders can now access effect params 0-7 via `param(i)` helper, forwarded from ParamStore through `effect_params` fields in ParticleUniforms (repurposed padding bytes, no size change) - Updated Crucible and Spectral Eye presets (Swarm→Spirograph) - Effect count: 15 curated effects (was 12 before particle additions, peaked at 19, now curated down to 15) ### Particle System Hardening for 1M Support - **GPU-side buffer zero-init**: replaced CPU `vec![0u8; 128MB]` + `write_buffer` with `encoder.clear_buffer()` — eliminates 128MB+ CPU allocation at 1M particles - **Device limits validation**: `max_count` clamped to device `max_storage_buffer_binding_size` with log warning - **Bitonic sort auto-cap**: depth sort auto-disabled above 65K particles (would require 210 dispatches/frame at 1M) - **Trail buffer safety**: trails disabled above 500K particles; trail length capped to fit device binding limit ### Parameter Persistence - **Slider values persist to .pfx**: adjusting parameters in the Parameters panel now updates the `default` values in the .pfx file for user effects, so values survive effect reload and app restart - Debounced 500ms save — writes only after slider stops moving, not on every frame - Editor's Effect tab stays in sync when params are saved from UI ### Shader Editor - **Fix: Save now persists both tabs**: Save (Ctrl+S) writes both the active and paired file when either has unsaved changes — previously only saved the currently active tab, losing edits to the other file ### Effect Browser - **Particle badge**: small accent-colored dot in top-right corner of effect buttons that use particles - **Particle count in hover**: hover text shows particle count (e.g. "70K particles", "1M particles") ### Veil Effect - Fix feedback blowout on loud audio: particle brightness now decreases with volume, stronger loudness dampening on alpha, audio-reactive decay, lowered feedback clamp ### Helix Effect Overhaul - **Dipole field-guided particles**: replaced uniform B_z Lorentz force with magnetic dipole field — particles follow curved field lines from emitter, creating visible force field pattern through trails - **Helical oscillation**: perpendicular oscillation around field lines (charge-dependent CW/CCW), bass tightens helix frequency - **Feedback warps along field**: particle trails flow along magnetic field direction with chromatic aberration, creating persistent field line visualization - **Dark background**: replaced overpowering painted field lines with near-black background + very subtle dipole hints; particles are the main visual - **Bright particles**: brightness 0.22→0.70, alpha 0.30→0.55, particle size 0.010→0.018; emit rate 100→200 for dense field coverage - **Beat burst**: speed pulse along field lines on beat detection; onset scatters particles laterally off field lines - **Tuned post-processing**: bloom threshold 0.50→0.35, bloom intensity 0.45→0.60 for force-field glow; brighter saturated color gradient ### Chaos Effect Overhaul - **Visible Lorenz butterfly**: fixed base rho from 22 (below chaos threshold) to 28 (canonical chaotic regime); particles now trace the iconic butterfly attractor pattern - **XZ butterfly projection**: replaced Y-axis rotation with XZ plane view (the classic Lorenz butterfly orientation) plus gentle ±8° tilt oscillation for 3D depth feel - **Stable attractor dynamics**: reduced audio modulation of sigma/rho/beta to subtle range (was dramatically reshaping the attractor every frame); fixed `time * audio-varying` rotation bug that caused violent camera jumps - **Trail-based visualization**: dim particles (alpha × 0.2) with high trail persistence (decay 0.92) accumulate into visible trajectory lines; clean feedback without twist distortion preserves tight attractor lines - **Density increase**: 20K particles at 500/s emit (was 6K at 80/s) for dense attractor coverage - **Removed dead params**: attractor_mix, zoom, speed inputs were not wired to compute shader (compute shaders cannot access `param()`) - **Brightness fixes**: removed × 0.18 fallback color dim, raised initial alpha 0.3→1.0, unclamped color from 0.5→1.0 max ### Particle Effect Review & Enhancement - **Murmuration** (hero effect): full Boids flocking model with separation, cohesion, and alignment; angular heading smoothing eliminates jitter; alpha blend for opaque bird silhouettes; twilight sky gradient background; depth-based sizing; 15K particles; audio: beat→cohesion spike, bass→disorder, onset→flock split - **Coral** (fix): replaced numerical central-difference gradient with analytical derivative of Turing cosine waves; added soft exponential boundary repulsion (no more hard clamp collapse); FBM curl noise for organic diffusion; reduced attraction_strength 2.5→1.2; aspect ratio correction; color gradient and size curve - **Chaos** (fix): adaptive sub-stepping (4 steps) prevents divergence; NaN/divergence detection auto-kills bad particles; proper Rossler scaling (native scale then rescale); centered perspective projection around attractor center; color gradient for temperature-based trajectory coloring; size/opacity curves - **Helix** (fix): increased E-field upward from 0.05→0.20; reduced B_z from 3.0→1.5 base (wider spirals that actually rise); beat adds upward levitation pulse; moved emitter from y=-0.6 to y=-0.4; RMS-reactive upward drift; two-strand DNA color gradient; size/opacity curves - **Nova** (overhaul): color gradient lifecycle (white-hot→vivid→orange→dim red); size/opacity lifetime curves; ground bounce for trailing sparks (restitution 0.3); speed/size/life variance for natural variation; 15→85% shell/spark ratio; staggered burst emission; stronger ground glow with beat pulse - **Phosphor** (polish): reduced sparkle overbright (mix 0.55→0.3, mult 1.6→1.2); tightened feedback decay 0.88→0.84; stronger beat inward pull 0.02→0.06; size/opacity curves for crisp particle falloff; reduced bloom intensity 1.2→1.1 - **Veil** (bloom fix): raised background cap 0.2→0.6 for richer fabric; lowered bloom_threshold 0.9→0.7 - **Ribbons** (bloom fix): raised bloom_threshold 0.4→0.60; reduced bloom_intensity 0.6→0.40; reduced trail_width 0.008→0.005; capped feedback at 0.8 - **Cymatics** (polish): analytical Chladni gradient (no numerical eps); smooth bilinear mode crossfade between integer modes; raised background cap 0.5→0.85; sharper nodal line glow (exp factor 12→18); soft boundary repulsion; color gradient and size curve - **Vortex**: chromatic aberration in gravitational lensing (R/G/B channel separation); accretion glow flash near event horizon on beat; temperature-based color gradient for disk coloring - **Swarm**: wider orbit radius 0.3→0.5; reduced radial damping 8.0→4.5; stronger beat orbit expansion - **Flux**: sparkle system (8% of particles get 2.5x brightness with flicker); opacity curve for gentle fade-out; raised background cap 0.5→0.8 ### Advanced Particle Forces - ParticleUniforms extended from 192 to 384 bytes with new force, emitter, curve, and sort fields - FBM noise forces: configurable octaves, lacunarity, persistence with turbulence and curl noise modes - Wind force: constant directional force via `wind: [x, y]` - Vortex field: rotational force with center, strength, and falloff radius - Ground bounce: configurable y-level and restitution coefficient - New emitter shapes: disc (uniform area fill), cone (directional spread with angle control) - Emitter velocity inheritance: particles inherit emitter motion for trailing effects - Speed, lifetime, and size variance: per-particle randomization (0-1 range) - Lifetime curves: 8-point LUT for size and opacity over particle lifetime - Color gradient: up to 8 hex colors interpolated over lifetime - Particle spin: per-particle rotation with configurable speed, rendered via vertex rotation - `apply_builtin_forces()` helper in `particle_lib.wgsl`: single call applies all forces (gravity, wind, drag, noise, attraction, vortex, flow field) - Curve/gradient evaluation helpers: `eval_size_curve()`, `eval_opacity_curve()`, `eval_color_gradient()` - Bitonic depth sort: optional GPU merge-sort on alive indices for correct alpha-blended rendering - `parse_hex_color()` utility for `#RRGGBB` / `#RRGGBBAA` to packed u32 - All new fields default to zero/disabled — existing .pfx files and custom shaders work unchanged ### PFX Hot-Reload + Editor Integration - `.pfx` file hot-reload: editing effect metadata (params, postprocess, passes, particles) live-updates without restarting - Differential updates: param-only or postprocess-only changes skip GPU pipeline rebuilds - `merge_from_defs` on ParamStore preserves slider positions when param definitions change - Editor tab switching: Shader and Effect tabs in code editor for `.wgsl` and `.pfx` side by side - JSON syntax highlighting for `.pfx` editing - "Edit Shader" → "Edit Effect", "Copy Shader" → "Copy Effect" button labels - 12 new unit tests for PfxDiff and merge_from_defs ### Bug Fixes - Fix BPM detection reporting double tempo (~290 instead of ~145 BPM): remove cascading octave-up correction that fought multi-ratio disambiguation, tighten tempo prior σ from 1.5 to 1.0, widen frame time clamp to tolerate real audio thread timing, reduce Kalman snap escape from 50 to 30 frames ## Downloads | Platform | File | Notes | |----------|------|-------| | **macOS** | `.dmg` | Universal binary (Apple Silicon + Intel) | | **Linux x86_64** | `.tar.gz` | glibc 2.35+ (Ubuntu 22.04+, Debian 12+) | | **Windows x64** | `.zip` | Windows 10+ | ## Getting started **macOS**: Open the DMG, drag Phosphor.app to Applications (or run directly). Signed and notarized. **Linux / Windows**: Extract, run `phosphor` from the extracted directory. The `assets/` folder must be next to the binary. ## Requirements - **GPU**: Vulkan (Linux/Windows) or Metal (macOS) - **Audio**: Built-in mic or line-in for audio-reactive visuals - **NDI®** (optional): [NDI® SDK runtime](https://ndi.video) for network video output - **Video playback** (optional): `ffmpeg` on PATH for media layers --- NDI® is a registered trademark of Vizrt NDI AB.