In my latest push to Pixie-Anim, I ran into a classic WASM "heisenbug": a RuntimeError: unreachable that only manifested when certain GIFs were re-optimized. Here’s a breakdown of the two architectural bottlenecks we hit and how we cleared them.
The "Parallelism" Panic
The first culprit was Rayon. While Pixie-Anim uses SIMD and multi-threading to achieve its performance on the CLI, the wasm32-unknown-unknown target is fundamentally single-threaded in standard browser environments. Rayon’s default behavior is to initialize a thread pool; on WASM, this triggers a panic because the system can't spawn threads.
The Fix: Gemini CLI helped me decouple the wasm feature from the rayon dependency in Cargo.toml. By using #[cfg(not(feature = "rayon"))] guards, the engine now gracefully falls back to sequential iterators for web builds, while maintaining multi-threaded performance for the native CLI.
The GIF Sub-Rectangle Trap
The second issue was more subtle: a buffer length mismatch. When re-optimizing an existing GIF, the gif crate decodes frames as they are stored—often as small "delta" rectangles that only contain changed pixels.
If a 640x480 GIF has a frame that only updates a 10x10 area, the decoder returns a 400-byte buffer instead of the expected 1.2MB RGBA buffer. When this was passed back into our encoder (which expected full-size frames), it caused an out-of-bounds access.
The Fix: Gemini CLI then implemented a Compositing Virtual Canvas in the Rust WASM bridge.
let mut canvas = vec![0u8; width * height * 4];
// ... for each frame ...
// Copy frame sub-rectangle onto the persistent canvas
// Handle DisposalMethod (e.g., Background) to clear the canvas for the next frame
frames.extend_from_slice(&canvas);
This ensures that the encoder always receives a consistent, full-frame buffer, regardless of how the source GIF was optimized.
Memory Safety in the JS/WASM Bridge
Finally, we hardened the frontend. We moved away from creating Uint8Array views into WASM memory (which can become detached if the WASM heap grows and reallocates) and switched to .slice(). This creates a stable copy of the data, preventing the "Detached Buffer" errors that often plague high-memory WASM applications.
The result? Pixie-Anim is now rock-solid for both MP4-to-GIF conversion and GIF-to-GIF re-optimization.