Visualz 3.0.6
3.0.6 is a hotfix on top of yesterday's 3.0.5 release. A handful of things were broken in production that all looked unrelated but each had a clean root cause underneath.
Recording works in the packaged app
Main Set Record was silently failing in the shipped DMG with a generic "Could not start recording" toast, even though it worked in dev. The cause: ffmpeg-static returns a path pointing into app.asar at runtime, but the actual binary lives inapp.asar.unpacked (per our asarUnpack config). child_process.spawn can't execute a binary from inside an ASAR archive, so the IPC threw. The same latent bug was lurking in the media-library thumbnail / probe pipeline; both are fixed.
The custom resolution dropdown actually accepts input
Picking Custom… from Settings → Output → Resolution snapped right back to the previous preset, never revealing the width / height inputs. The dropdown was deriving its current value from the live dimensions, which still matched a preset row at the moment of the click, so the "Custom" selection round-tripped to nothing. There's now an explicit custom-mode latch — once you pick Custom, the inputs appear and stay until you pick a preset again.
Engine resolution actually reaches the output
Bumping Settings → Resolution to 4K used to do nothing visible on the 2nd-monitor output, and could freeze the output entirely until a tab switch. Three layered issues:
- A
ResizeObserveron the Perform-tab preview pane was forcing the engine canvas back to the on-screen preview size every time you navigated to Perform — overriding whatever Settings was set to. Removed; the preview now CSS-scales a higher-resolution backing buffer instead. - Each window output's slicer was rendering at the output's spec dimensions (typically 1080p) and shipping a too-small bitmap that the 2nd monitor would upscale back. Window outputs now auto-size their slicer to the target display's native physical pixel resolution when you click Send to Display — matching the display's pixel grid 1:1, with HiDPI / Retina factored in.
- The slicer's source-canvas texture allocation got stuck at the engine's original size — so once the engine resized away from 720p, every frame tried to upload a larger source into a smaller-allocated GL texture and Chromium spammed
glCopySubTextureCHROMIUM: Offset overflows texture dimensionsuntil the output went black. The slicer now reallocates its texture when the engine canvas resizes in place.
Net effect: Settings → Resolution change is a single quick blip on the output, the engine renders at the chosen resolution, and a 4K display gets a 4K bitmap end-to-end.
Audio bindings survive a clip drag between layers
Source-level modulations (e.g. bass → user slider audio bindings) are stored per-layer in the engine, not per-clip. The drag-between-layers helper swapped the source but skipped restoring those bindings onto the new layer — so dragging an audio-reactive clip to another layer silently dropped its audio routing. Every other place we replace a layer source already pairs with a modulation restore; this one was missed. Fixed.
Color pickers on the default shader source
The default shader clip now exposes two color params (Color A and Color B) and the built-in shader uses them out of the box — mix(iColorA, iColorB, …) in both the Shadertoy and Raw modes. Custom user-written shaders can opt in by reading the same iColorA / iColorB uniforms from the prelude. Goodbye hard-coded magenta-and-cyan; pick your palette.
