When a visitor takes over
A busker plays to whoever is passing. When someone actually walks up, they stop playing and let them have a go. Busker works the same way: the first real click ends the show and hands the mock to the visitor.
What happens on a click
Section titled “What happens on a click”- If the click hit a route target, that scene comes up — the same code path the cursor’s own clicks use.
- The loop stops for good and the root gets
is-aside, which hides the cursor. - If the click hit nothing clickable, every route target gets
is-hintfor 1.5s, so they can see what is live.
From then on the mock is an ordinary bit of interactive markup. Busker is not going to grab the pointer back mid-thought, which is the whole reason it stops for good rather than resuming after a pause.
Its own clicks do not count
Section titled “Its own clicks do not count”Busker’s presses go through el.click() — real clicks, real handlers, real routes. It knows which ones are its own and does not mistake them for a visitor. You do not have to filter anything in your handlers.
event.isTrusted will not tell you the difference either, by the way: it is false for anything scripted, including test-runner and devtools clicks. Busker tracks its own presses directly instead.
Handing over on purpose
Section titled “Handing over on purpose”stepAside() does the same thing from your code — for a “try it yourself” button, or when a visitor focuses something inside the mock:
const show = busk(root, routine);
document.querySelector('#try-it')?.addEventListener('click', () => show.stepAside());Stopping and starting
Section titled “Stopping and starting”play() and pause() are there if you need them, but you usually do not: busker already pauses when the mock scrolls off screen or the tab goes to the background, and resumes when it comes back. That is one IntersectionObserver and one visibilitychange listener, both cleaned up by destroy().
destroy() puts everything back — listeners, observers, and every class busker added. Call it when the component unmounts.
Reduced motion
Section titled “Reduced motion”Under prefers-reduced-motion: reduce there is no loop, no cursor, and no observer. Busker renders the freezeAt frame once and leaves it there. Routes are still wired, so the mock stays clickable — it just never moves on its own.
← Hand-timed routines · Next: Styling