8f33744f8c
The isPlaying subscriber is unselected. Every store write during Vibe's feedback/replan handshake called play() on the element that had just ended. That replayed its final buffered milliseconds until the next source loaded. Gate that subscriber and the seek subscriber on an actual value change, and never resume a finished element. Then close the gap the handshake leaves behind. The engine now drives two <audio> elements. The next track buffers into the idle one 20s early. The handover starts before `ended`, so the round-trip happens under the outgoing tail. With a crossfade, that tail fades out under the new track. With crossfade off, the new track waits in silence and starts the moment the tail ends. Both are configurable under Settings -> Transitions and persist to localStorage. Preload is on and crossfade is 400ms by default. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>