diff --git a/README.md b/README.md index 73c36f5..dffc073 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,9 @@ app's config when adding it to a device. to show off different sections of its art over time instead of being stuck on one spot for its whole runtime. - **Static overlay** — On (default) or Off. When on, shows a brief - TV-static effect (sparse noise specks) over the album art during the - first/last few seconds of a track, as a transition cue. + TV-glitch effect (a jagged horizontal static band, plus scattered noise + specks) over the album art during the first/last few seconds of a + track, as a transition cue. ## How it works @@ -115,17 +116,25 @@ app's config when adding it to a device. its full module list) — so there's no way to pre-bake or crop-at-render- time from a source we don't have until the request hits the live station. -- When enabled (Static overlay config), shows a brief TV-static effect +- When enabled (Static overlay config), shows a brief TV-glitch effect over the album art during the first/last `STATIC_OVERLAY_SECONDS` (5s) of a track, as a transition cue. Implemented as a small bundled animated - GIF (`images/static.gif` — sparse noise specks over a transparent - background, built with Pillow) composited over the zoomed art via - `render.Stack`, not generated at render time: pixlet's Starlark sandbox - has no per-frame procedural drawing hook, and `animation.Transformation` - only interpolates between fixed keyframes, so there's no way to get - genuine random noise out of it. `render.Image` plays back animated GIFs - natively, looping independently of the zoom's own animation timeline. - Like the progress bar, this only works correctly on a long-lived server + GIF (`images/static.gif` — a jagged horizontal static band plus + scattered noise specks, over a transparent background, procedurally + generated with Pillow, not sourced from any existing footage) + composited over the zoomed art via `render.Stack`, not generated at + render time: pixlet's Starlark sandbox has no per-frame procedural + drawing hook, and `animation.Transformation` only interpolates between + fixed keyframes, so there's no way to get genuine random noise out of + it. `render.Image` plays back animated GIFs natively, looping + independently of the zoom's own animation timeline. An earlier version + tried deriving this effect from a real "VHS glitch" stock-footage clip + (downloaded, downsampled, and thresholded for transparency) instead of + generating it — dropped because, even licensed as free-to-use, cropping + it down to 32x32 let recognizable footage content show through at any + opacity that read as an actual "band" rather than sparse noise, and it + compressed noticeably worse than procedural noise does. Like the + progress bar, this only works correctly on a long-lived server with a persistent cache — a one-shot `pixlet render` CLI call always sees `elapsed=0`, so it'll always show the "starting" static, never the "ending" one. Tuned the GIF's frame count/density/flicker speed down diff --git a/images/static.gif b/images/static.gif index 4265a21..c36ed98 100644 Binary files a/images/static.gif and b/images/static.gif differ