A watch-video dialog with real player chrome: a clearing overlay, glass control
pills, a loading ring, a seek bar that reads the clock honestly. Point it at your own
<video src> and it plays that; give it nothing and it falls back to a
drawn clip so the page never shows a broken frame.
The dialog is the product. role="dialog" and aria-modal,
focus moved in on open and handed back to the trigger on close, everything behind it
inert, Esc to close, and a scroll lock that compensates for the
scrollbar so the page underneath does not jump. Press H to hide the control panel.
Each card owns its own instance, bound to its own trigger — so focus returns to the button you actually pressed. The control panel drives whichever preset is selected.
There is no clip file in this folder and nothing to fetch, so the demo
bakes one in the browser: an animated canvas is captured with
captureStream and encoded by MediaRecorder into a blob the
<video> element can actually play. Where that pair is missing or
refuses, the engine runs its canvas path instead and says so. In your build you pass a
real src and the video path is the only one you ever see.
Measured on the page, not asserted in a README. Open a dialog and this block records where focus was, where it went, where it came back to, whether the background scroll locked, and how many pixels the page behind shifted while it did.
initialFocus moves it to play or the dialog.inert and aria-hidden.<html>; the scrollbar width is added back as padding.data-scroll-lock-pad is padded too — the panel is.