Every comparison below runs two real builds at once: the released v0.6.0 bundle, pinned and
committed to the repo, and the current working build. Same markup, same state, same harness code — only the
library differs.
This player is mounted by <script src="fideo.global.js"> alone. The released build could
not do that: its page-scope CSS positioned the shadow host, so a missing <link> left the
controls stacked in the top-left corner. Hover for the controls.
16-second procedurally generated clip, 101 KB, bundled with the repo — no external requests.
formatTime divided seconds by 60 once and stopped, so an hour-long video reported inflated
minutes. Both frames are driven with the same state: 3,904 seconds total, 2,704 elapsed.
Any video over 60 minutes displayed a duration that did not exist. Now covered by unit tests.
The HTML5 provider had always populated state.buffered. Nothing consumed it. The timeline now
paints it as a third band behind the played portion. Both frames are driven with buffered: 0.62
at 23% elapsed.
Data the library already had, surfaced for zero runtime cost — one extra gradient stop.
Menu items were plain menuitem buttons with no selected state — nothing visual, nothing for
assistive tech. They are now menuitemradio with a live aria-checked state and a tick.
Both frames are driven at 1.5× with the menu open.
A screen reader now announces the rate as selected instead of reading four identical buttons.
A transparent button covers the whole video to catch play/pause clicks, and it is first in tab order. It had no focus style, so tabbing into a player moved focus nowhere visible. Click inside either frame and press Tab.
Required for WCAG 2.4.7. The ring uses the player's own accent variable.
Progress is interpolated on requestAnimationFrame so the bar moves smoothly. The released build
rewrote both time labels, the aria-valuetext attribute, the input value and the progress
property on every frame — even though the visible clock only changes once a second, and screen readers were
re-announced 60 times a second.
The current build keeps the per-frame property update and drops every write whose value has not changed. The harness below mounts six players in each build and pushes one state update per animation frame for three seconds, with playback time advancing in real time.
| Operation | v0.6.0 | Current | Delta |
|---|---|---|---|
| Waiting for both builds… | |||
DOM writes are a proxy for style and layout work, not a direct measure of frame time. The reduction is real; what it saves depends on the page.
Controls live in a shadow root. The released build copied all 7.6 KB of CSS into a fresh
<style> node per player, and that CSS carried every page-scope rule
(.fideo, .fideo__poster, .fideo__click-target) which can never match
inside a shadow root. The sheet is now split in two, and the controls half is adopted once and shared by
every instance.
| Measurement | v0.6.0 | Current | Delta |
|---|---|---|---|
| Waiting for both builds… | |||
initFideo() mapped over its matches, so the first element that threw — a disabled provider, an
iframe a provider rejects — aborted every remaining mount. It now warns and continues. The harness mounts a
Vimeo iframe with disabledProviders: ['vimeo'] next to one healthy video.
| Build | Outcome | Players mounted |
|---|---|---|
| Waiting for both builds… | ||
Because the page-scope CSS is what positions the shadow host, forgetting the stylesheet produced a broken
player rather than an unstyled one. That half is now injected once per document, prepended to
<head> so author CSS still wins the cascade. Opt out with injectStyles: false.
| Measurement | v0.6.0 | Current | Delta |
|---|---|---|---|
| Waiting for both builds… | |||
| File | v0.6.0 | Current | Delta |
|---|---|---|---|
fideo.global.js | 14,011 B | 14,839 B | +828 B |
fideo.css | 1,818 B | 919 B | −899 B |
| Script + stylesheet | 15,829 B | 15,758 B | −71 B |
| Script only — not possible before | 15,829 B | 14,839 B | −990 B · −6.3% |
| Requests for a styled player | 2 | 1 | −1 |
fideo.css, uncompressed | 7,661 B | 2,904 B | −62.1% |
MediaQueryList on every timeupdate.object-fit: cover, so a 4:3 or vertical source is cropped rather than fitted.Memory held by duplicated stylesheets is reported as attached CSS text, not heap usage — the real cost is larger than the text and engine-dependent.