Skip to content

WIP: WASM/WebGPU support for running vibe in the browser - #5

Draft
marksverdhei wants to merge 17 commits into
htfrom
vibe.wasm
Draft

WIP: WASM/WebGPU support for running vibe in the browser#5
marksverdhei wants to merge 17 commits into
htfrom
vibe.wasm

Conversation

@marksverdhei

Copy link
Copy Markdown
Collaborator

Summary

  • Adds cfg(target_arch = "wasm32") gates across vibe-audio and vibe-renderer to compile without native-only deps (cpal, pollster, xdg, filesystem I/O)
  • Introduces vibe-web crate — a standalone browser entry point using wasm-bindgen, with its own WebGPU render pipeline, uniform management, and shader hot-swap via JS
  • Adds WebAudioFetcher in vibe-audio for pulling audio from the Web Audio API's AnalyserNode
  • Makes Renderer initialization async-capable (new_async on WASM, new stays blocking on native)
  • Moves vulkan backend feature out of workspace default into the native vibe crate only

Current issues

  • vibe-web duplicates the render pipeline — it has its own standalone WebGPU setup rather than reusing vibe-renderer. The uniform layout (preamble, bind group) is duplicated and will drift from the native version. Ideally vibe-web should be a thin shell that drives vibe-renderer components.
  • WebAudioFetcher is not wired into vibe-web — the fetcher exists in vibe-audio but vibe-web/src/lib.rs doesn't use it; frequency data is currently pushed from JS via set_frequencies(). Need to decide: keep JS-driven approach, or integrate the Rust-side fetcher.
  • No freqs storage buffer on web — the native FragmentCanvas uses a storage buffer for frequency data, but WebGPU uniform buffers have a 64KB limit. The web version packs freqs into array<vec4f, 64> (256 floats) as a workaround. Shaders that use var<storage> won't work unmodified.
  • Shader compatibility — existing vibe shaders use storage bindings and arrayLength(&freqs) which aren't available in the web uniform-only layout. Shaders need porting or a compatibility layer.
  • No BPM detection on webBpmDetector isn't integrated in the web path.
  • Error scope / validation gappush_error_scope + pop (with blocking) is skipped on WASM. Shader compilation errors in the browser will be silent or only show in on_uncaptured_error.
  • No automated WASM build in CIvibe-web/build.sh is a manual script calling wasm-pack. No CI integration yet.
  • Native tests not verified — need to confirm the cfg gates don't break the native cargo test / cargo build paths.

Test plan

  • cargo build (native) still works
  • cargo test (native) still passes
  • wasm-pack build in vibe-web/ produces working pkg
  • Browser loads canvas and renders the fallback shader
  • set_shader() hot-swaps a custom WGSL fragment
  • set_frequencies() drives audio reactivity from JS AnalyserNode data
  • Resize handling works

🤖 Generated with Claude Code

marksverdhei and others added 15 commits March 4, 2026 07:20
Re-implements both features on top of upstream's refactored codebase
(no more ResourceManager, new Component trait, texture support):

- BPM detector: spectral flux + autocorrelation with median smoothing,
  exposed as iBPM uniform (binding 4), writes /tmp/vibe-bpm for waybar
- Color palette: 4 configurable colors from ~/.config/vibe/colors.toml,
  exposed as iColors uniform (binding 5), live-reloads via mtime check

Texture bindings bumped to 6/7 to accommodate new uniforms.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Some AMD GPUs expose Rgba16Unorm first which isn't renderable.
Prefer known-good 8-bit formats with fallback chain.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…capture

On PipeWire/ALSA, build_input_stream on an output device doesn't do
loopback capture. Switch to using the default input device with
supported_input_configs so PipeWire can route a monitor source for
capturing system audio output.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Start normalize_factor at 0.1 instead of 1.0 so newly loaded shaders
fade in from dim rather than flashing bright and slowly settling. Use a
faster ramp-up rate (3% vs 0.2% per frame) while below 0.5 to reach
equilibrium in ~1-2 seconds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Covers uniforms, audio-reactive techniques, color vibrancy,
texture sampling, and best practices for FragmentCanvas shaders.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add iMouseClick (vec4f, binding 8) and iLocalTime (binding 9) uniforms.
Implements GPU pixel readback via post_render hook, nearest-neighbor
texture sampling, and external tool integration (/tmp/vibe-click).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
18 WGSL fragment shaders for the FragmentCanvas component:
aurora, cluster, deep_sea, event_horizon, grass, liquid,
mandelbrot_light, monolith, nebula, plasma, pokemon_grass,
pokemon_grass_3d, singularity, solar_system, starfield,
tesseract, vortex, waveform

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add comprehensive changelog to README documenting all fork features
(18 shaders, BPM detection, click-to-interact, color palette, fixes).

Add utility scripts from ~/.config/vibe to utils/:
- cycle-shader.sh: cycle shaders per output/window
- vibe-key-cycle.sh: Hyprland keybinding shader cycling
- randomize-colors.sh: randomize color palette
- pokemon-click-cry.py: click-triggered Pokemon cry daemon
- pokemon-cries-daemon.sh: ambient random cries
- cluster-status-feeder.sh: K8s metrics → shader constants

Include Pokemon grass shader spec doc.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add shared compositor abstraction (utils/lib/compositor.sh) that
auto-detects Hyprland, Sway, and KDE Plasma for focused-window
queries. Keybinding scripts now work on any supported compositor
instead of only Hyprland.

- vibe-key-cycle.sh: use compositor.sh instead of hyprctl directly
- randomize-colors.sh: use compositor.sh with graceful fallback
- cluster-status-feeder.sh: externalize node config to TOML file
- Add cluster-nodes.toml.example for user configuration
- Add utils/README.md with setup docs for all compositors

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only update last_mtime after successfully parsing the species file.
Previously, a partial/incomplete read would update the mtime tracker
and never retry, silently dropping the click event.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ht-fork changelog to README documenting all fork features, fixes, and docs.
Add portable utility scripts (shader cycling, color randomization, Pokemon cry
daemons, K8s cluster status feeder) with shared compositor abstraction supporting
Hyprland, Sway, and KDE Plasma. Include Pokemon grass shader spec and utils README.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dedicated changelog for all fork-specific features, fixes, and CI
changes with commit links. Linked from README.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@marksverdhei
marksverdhei changed the base branch from main to ht March 4, 2026 09:46
Introduce platform abstractions across vibe-audio, vibe-renderer, and a new
vibe-web crate to enable compilation to wasm32 targets using WebGPU.

- Add cfg(target_arch = "wasm32") gates throughout for cpal, pollster, xdg, fs
- Replace cpal::SampleRate with a platform-agnostic type alias on WASM
- Make Renderer::new async-capable with new_async for WASM
- Add web-sys/wasm-bindgen/js-sys workspace dependencies
- Add vibe-web crate as the browser entry point
- Add WebAudioFetcher for browser audio capture
- Move vulkan backend feature to native-only (vibe crate)
- Skip error scope blocking and file I/O on WASM targets

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add default-members to workspace Cargo.toml so native builds skip vibe-web
- Fix import path for WASM pkg (./pkg/ not ../pkg/)
- Add Web Audio API integration (getUserMedia → AnalyserNode → frequency data)
- DPI-aware canvas sizing with devicePixelRatio
- Graceful audio fallback with click-to-retry
- Normalize mouse coordinates using clientWidth/clientHeight

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant