pnpm add @uln/hls
Examples
| example | plays | UI |
|---|---|---|
| simplest | HLS | React |
| single-video/react | HLS | React |
| single-video/vanilla | HLS | DOM |
| clip-card | HLS MP4 | React |
| carousel/react | HLS MP4 | React |
| carousel/vanilla | HLS MP4 | DOM |
| hover-grid | HLS MP4 | React |
| loading-screen | HLS | React |
| film-page | HLS | React |
| custom-controls | HLS | React |
| background-loop | HLS MP4 | React |
| playlist | HLS | React |
Benchmarks
uln uln-0.3.0 hlsjs
fiber: 50 Mbps, 10 ms
| first frame (ms) | stalls | stalled (ms) | mean height shown | time at 1080p | switches | downloaded (MB) | main-thread script (ms) | |
|---|---|---|---|---|---|---|---|---|
| uln | 151 | 0.0 | 0 | 1006 | 90% | 1.0 | 85.3 | 44 |
| uln-0.3.0 | 335 | 0.0 | 0 | 1024 | 90% | 1.0 | 83.0 | 306 |
| hlsjs | 233 | 0.0 | 0 | 1006 | 90% | 1.0 | 82.5 | 341 |
cable: 15 Mbps, 20 ms
| first frame (ms) | stalls | stalled (ms) | mean height shown | time at 1080p | switches | downloaded (MB) | main-thread script (ms) | |
|---|---|---|---|---|---|---|---|---|
| uln | 397 | 0.0 | 0 | 1007 | 90% | 1.0 | 67.4 | 32 |
| uln-0.3.0 | 738 | 0.0 | 0 | 1024 | 90% | 1.0 | 67.9 | 279 |
| hlsjs | 447 | 0.0 | 0 | 1005 | 90% | 1.0 | 67.4 | 311 |
4g: 6 Mbps, 50 ms
| first frame (ms) | stalls | stalled (ms) | mean height shown | time at 1080p | switches | downloaded (MB) | main-thread script (ms) | |
|---|---|---|---|---|---|---|---|---|
| uln | 914 | 0.0 | 0 | 684 | 0% | 1.0 | 28.7 | 32 |
| uln-0.3.0 | 1574 | 0.0 | 0 | 701 | 0% | 1.0 | 27.5 | 250 |
| hlsjs | 974 | 0.0 | 0 | 682 | 0% | 1.0 | 28.7 | 261 |
slow: 1.6 Mbps, 150 ms
| first frame (ms) | stalls | stalled (ms) | mean height shown | time at 1080p | switches | downloaded (MB) | main-thread script (ms) | |
|---|---|---|---|---|---|---|---|---|
| uln | 3229 | 0.0 | 0 | 360 | 0% | 0.0 | 7.1 | 42 |
| uln-0.3.0 | 5584 | 0.0 | 0 | 381 | 0% | 1.0 | 7.1 | 183 |
| hlsjs | 3277 | 0.0 | 0 | 360 | 0% | 0.0 | 7.1 | 188 |
drop: 15 Mbps, falling to 1.2 Mbps at 0:12, back at 0:30
| first frame (ms) | stalls | stalled (ms) | mean height shown | time at 1080p | switches | downloaded (MB) | main-thread script (ms) | |
|---|---|---|---|---|---|---|---|---|
| uln | 423 | 0.0 | 0 | 942 | 81% | 2.0 | 39.8 | 39 |
| uln-0.3.0 | 750 | 0.0 | 0 | 892 | 71% | 2.0 | 40.9 | 256 |
| hlsjs | 448 | 0.0 | 0 | 869 | 71% | 2.0 | 40.2 | 278 |
fluctuating: 8 and 2 Mbps alternating every 6 s
| first frame (ms) | stalls | stalled (ms) | mean height shown | time at 1080p | switches | downloaded (MB) | main-thread script (ms) | |
|---|---|---|---|---|---|---|---|---|
| uln | 696 | 0.0 | 0 | 683 | 0% | 1.0 | 27.1 | 36 |
| uln-0.3.0 | 1266 | 0.0 | 0 | 663 | 0% | 3.0 | 27.8 | 247 |
| hlsjs | 777 | 0.0 | 0 | 682 | 0% | 1.0 | 26.4 | 262 |
seek: three seeks into unbuffered media, 15 Mbps
| seek to playing (ms) | stalls | downloaded (MB) | |
|---|---|---|---|
| uln | 815 | 0.0 | 36.2 |
| uln-0.3.0 | 3313 | 0.0 | 50.2 |
| hlsjs | 3376 | 0.0 | 50.1 |
warm start: 4 s on the page before the tap, 6 Mbps (preload for @uln/hls; hls.js buffers once attached)
| first frame after tap (ms) | fetched before the tap (MB) | mean height shown | |
|---|---|---|---|
| uln | 27 | 1.0 | 683 |
| uln-0.3.0 | 1432 | 1.0 | 701 |
| hlsjs | 176 | 2.2 | 684 |
Method
Chromium (headless), 3 runs each, medians. 40 s of playback per run on 2 minutes of Big Buck Bunny (360p 0.8 Mbps, 540p 1.6, 720p 3, 1080p 6; AAC audio apart; 4 s segments) in a 1920×1080 element. Generated by pnpm bench on 2026-10-26.
Contenders: uln is this package; uln-0.3.0 is the release before it, which played through hls.js with its own settings; hlsjs is hls.js 1.7.3 with its defaults.
Engine download, minified and gzipped: uln 9.1 KB, hls.js 183.6 KB.
Media
| film | 60 s HLS, 4 s fMP4 segments, H.264 360p 0.8 / 540p 1.6 / 720p 3 / 1080p 6 Mbps, AAC 128 kbps apart |
|---|---|
| clip | 6 s MP4 from 0:42, 540p, silent |
| serving | static files on Workers static assets, no Worker code |