Scrubber Preview
Headless seek-bar preview: sprite, WebVTT, or captured video thumbnails with hover time.
|
|
| Package |
@vizejs/ui/scrubber-preview |
| Maturity |
stable |
| Own the source |
vize lib pull scrubber-preview |
| Requires |
context, controllable-state |
| Aliases |
scrubber preview, video thumbnail, seek preview, storyboard, trick play, thumbnail track |
| Covers |
WebVTT thumbnail tracks (JW Player / Video.js convention), Media Fragments URI xywh, Vidstack slider thumbnails, HTMLVideoElement + canvas frame capture |
Usage
import { ScrubberPreview, ScrubberPreviewRoot, ScrubberPreviewThumbnail, ScrubberPreviewTime, ScrubberPreviewTrack } from "@vizejs/ui/scrubber-preview";
Or copy the source into your project with vize lib pull scrubber-preview (see Source Distribution).
API
ScrubberPreview
Source: src/families/media/scrubber-preview/scrubber-preview-root.vue
Props
| Prop |
Type |
Default |
Description |
duration (required) |
number |
required |
Media duration in seconds. |
time |
number | null |
undefined |
Controlled preview time (v-model:time). null hides the preview; undefined is uncontrolled. |
dir |
ScrubberPreviewDirection |
"ltr" |
Reading direction; RTL tracks map the right edge to time zero. |
disabled |
boolean |
false |
Stop previewing and seeking. |
sprite |
ScrubberPreviewSprite |
undefined |
Sprite-sheet thumbnails. Takes precedence over thumbnails and videoSrc. |
thumbnails |
string | readonly ScrubberPreviewCue[] |
undefined |
WebVTT thumbnails track text, or pre-parsed cues. Takes precedence over videoSrc. |
thumbnailsBaseUrl |
string |
undefined |
Base URL that relative image URLs in VTT text resolve against. |
videoSrc |
string |
undefined |
Video URL used to capture frames on the fly in the browser (same-origin or CORS-enabled). |
captureWidth |
number |
160 |
Width of captured frames in pixels. |
captureInterval |
number |
1 |
Captured frames are shared across this many seconds (cache granularity). |
cacheSize |
number |
40 |
Maximum captured frames kept; older object URLs are revoked. |
Events
| Event |
Payload |
Description |
update:time |
[time: number | null] |
Fired when the preview time requests a new controlled value. |
seek |
[time: number, nativeEvent: Event] |
Fired when the user releases a click or scrub on the track. |
Slots
| Slot |
Slot props |
Description |
default |
ScrubberPreviewSlotState |
Track, thumbnail, and time parts. Receives the preview state. |
Exposed
| Member |
Type |
Description |
active |
— |
|
duration |
— |
|
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
ratio |
— |
|
setTime |
— |
|
time |
— |
|
ScrubberPreviewRoot
Source: src/families/media/scrubber-preview/scrubber-preview-root.vue
Props
| Prop |
Type |
Default |
Description |
duration (required) |
number |
required |
Media duration in seconds. |
time |
number | null |
undefined |
Controlled preview time (v-model:time). null hides the preview; undefined is uncontrolled. |
dir |
ScrubberPreviewDirection |
"ltr" |
Reading direction; RTL tracks map the right edge to time zero. |
disabled |
boolean |
false |
Stop previewing and seeking. |
sprite |
ScrubberPreviewSprite |
undefined |
Sprite-sheet thumbnails. Takes precedence over thumbnails and videoSrc. |
thumbnails |
string | readonly ScrubberPreviewCue[] |
undefined |
WebVTT thumbnails track text, or pre-parsed cues. Takes precedence over videoSrc. |
thumbnailsBaseUrl |
string |
undefined |
Base URL that relative image URLs in VTT text resolve against. |
videoSrc |
string |
undefined |
Video URL used to capture frames on the fly in the browser (same-origin or CORS-enabled). |
captureWidth |
number |
160 |
Width of captured frames in pixels. |
captureInterval |
number |
1 |
Captured frames are shared across this many seconds (cache granularity). |
cacheSize |
number |
40 |
Maximum captured frames kept; older object URLs are revoked. |
Events
| Event |
Payload |
Description |
update:time |
[time: number | null] |
Fired when the preview time requests a new controlled value. |
seek |
[time: number, nativeEvent: Event] |
Fired when the user releases a click or scrub on the track. |
Slots
| Slot |
Slot props |
Description |
default |
ScrubberPreviewSlotState |
Track, thumbnail, and time parts. Receives the preview state. |
Exposed
| Member |
Type |
Description |
time |
number | null |
Previewed time in seconds, or null while no preview is shown. |
ratio |
number | null |
Previewed position 0..1 along the track, or null. |
active |
boolean |
Whether a preview is shown. |
duration |
number |
Media duration in seconds. |
element |
HTMLDivElement | null |
Rendered root element. |
setTime |
(time: number | null) => boolean |
Show a preview for a time (e.g. while a seek slider has keyboard focus), or hide it. |
ScrubberPreviewThumbnail
Source: src/families/media/scrubber-preview/scrubber-preview-thumbnail.vue
Events
| Event |
Payload |
Description |
error |
[error: ScrubberPreviewError] |
Fired when a thumbnail cannot be produced. |
Slots
| Slot |
Slot props |
Description |
default |
ScrubberPreviewThumbnailSlotState |
Custom thumbnail rendering. Defaults to an <img> for captured frames; sprite and VTT frames are published as custom properties for CSS backgrounds. |
Exposed
| Member |
Type |
Description |
kind |
ScrubberPreviewKind |
Source of preview images. |
status |
ScrubberPreviewStatus |
Availability of the current frame. |
frame |
ScrubberPreviewFrame | null |
Resolved frame, or null. |
time |
number | null |
Previewed time in seconds, or null. |
error |
ScrubberPreviewErrorCode | null |
Failure code after an error, or null. |
element |
HTMLDivElement | null |
Rendered thumbnail element. |
ScrubberPreviewTime
Source: src/families/media/scrubber-preview/scrubber-preview-time.vue
Props
| Prop |
Type |
Default |
Description |
format |
(seconds: number) => string |
undefined |
Custom formatter. Defaults to m:ss, or h:mm:ss for media of an hour or longer. |
Slots
| Slot |
Slot props |
Description |
default |
ScrubberPreviewTimeSlotState |
Custom time rendering. Receives the previewed time and its formatted text. |
Exposed
| Member |
Type |
Description |
time |
number | null |
Previewed time in seconds, or null. |
text |
string |
Formatted time, e.g. "1:05" or "1:02:03"; empty while inactive. |
element |
HTMLSpanElement | null |
Rendered time element. |
ScrubberPreviewTrack
Source: src/families/media/scrubber-preview/scrubber-preview-track.vue
Slots
| Slot |
Slot props |
Description |
default |
ScrubberPreviewSlotState |
Track contents, typically the consumer's seek bar. Receives the preview state. |
Exposed
| Member |
Type |
Description |
element |
HTMLDivElement | null |
Rendered track element. |
scrubbing |
boolean |
Whether a pointer is scrubbing (pressed) on the track. |
Behavior
Normative state x input -> outcome table for scrubber-preview-root.vue,
scrubber-preview-track.vue, scrubber-preview-thumbnail.vue, and
scrubber-preview-time.vue (@vizejs/ui/scrubber-preview). Every row is proven by the named
test.
The preview is a visual affordance layered on the consumer's seek control: the track maps pointer
positions to a preview time, the thumbnail resolves a frame for that time, and the time part shows
it. All parts are aria-hidden; keyboard users hear the seek slider's own value text, and
setTime() lets a focused slider drive the same preview. Frame sources, in precedence order, are a
sprite sheet, a WebVTT thumbnails track, or frames captured on the fly from a hidden client-only
<video>.
| ID |
State |
Input |
Outcome |
Evidence |
| SP1 |
idle |
render |
root is idle with ratio 0; thumbnail is hidden and decorative; time text is empty |
renders an idle preview with hidden, decorative thumbnail and time parts |
| SP2 |
mouse hover |
pointerenter / move / leave |
the pointer position maps to a time and ratio (--vize-ui-scrubber-preview-ratio); leaving hides the preview; update:time reports each |
hovering the track previews the time under the pointer and leaving hides it |
| SP3 |
press on track |
pointerdown, move, up / cancel / touch |
pressing captures the pointer and keeps the preview while outside; release emits seek(time, event); cancel never seeks; touch hides on lift; RTL maps the right edge to zero; secondary buttons are ignored |
clicking or scrubbing the track emits seek on release; touch hides on lift |
| SP4 |
controlled / disabled |
time prop, setTime(), disabled |
a controlled time wins and clamps to the duration; setTime() shows or hides the preview and reports changes; disabled roots neither preview nor seek |
controlled time, setTime, and disabled roots |
| SP5 |
sprite |
preview time |
the frame's sheet URL and offset/size are published as custom properties; unsafe sheet URLs render nothing and report error |
sprite thumbnails publish background geometry for the previewed frame |
| SP6 |
WebVTT |
preview time |
cues (text or parsed) resolve relative to thumbnailsBaseUrl; regions become offsets; slots receive the frame; gaps are idle |
WebVTT thumbnails resolve cues and expose frames to slots |
| SP7 |
capture |
preview time |
a client-only hidden video captures one frame per captureInterval slot into an LRU cache of object URLs; evicted and unmounted frames are revoked; the default slot renders an <img alt=""> |
captured thumbnails are generated once per interval, cached, and revoked |
| SP8 |
capture busy |
rapid time changes |
only the latest pending slot is captured after the current one; intermediate requests are skipped |
rapid capture requests keep only the latest pending frame |
| SP9 |
capture failure |
seek error / unsafe videoSrc |
the thumbnail reports error with a typed ScrubberPreviewError; unsafe video URLs disable capture (kind="none") |
capture failures surface typed errors |
| SP10 |
captureVideoFrame |
call |
waits for metadata, clamps and seeks, scales to the requested width keeping aspect, and encodes a Blob or data URL |
captureVideoFrame waits for metadata, seeks, scales, and encodes |
| SP11 |
captureVideoFrame |
failure |
no 2D context is …_UNSUPPORTED, draw failures are …_CAPTURE_FAILED, cross-origin encoding is …_TAINTED, empty encodes are …_CAPTURE_FAILED |
captureVideoFrame reports unsupported, tainted, and failed encodes |
| SP12 |
missing provider |
setup |
parts fail closed with the shared context diagnostic |
compound parts require a matching root provider |
| SP13 |
VTT parser |
text |
cues with #xywh= (optionally pixel:) regions parse; malformed cues are skipped; URLs resolve against a base |
parses WebVTT thumbnail cues with sprite regions and resolves relative URLs |
| SP14 |
cue lookup |
time |
binary search finds the covering cue with an exclusive end; gaps return nothing |
finds the cue covering a time by binary search |
| SP15 |
sprite math |
time |
frames fill rows then sheets, clamp to frameCount, and invalid geometry throws a typed RangeError |
maps times to sprite frames across rows and sheets |
| SP16 |
helpers |
pointer, quantize, format |
ratios clamp and mirror for RTL; times snap to capture slots; times format as m:ss or h:mm:ss |
maps pointers to ratios, quantizes times, and formats durations |
| SP17 |
frame cache |
get / set / clear |
least-recently-used entries are evicted and every released URL is reported |
the frame cache evicts least-recently-used URLs |
| SP18 |
SSR |
isolated requests |
markup is byte-identical, never renders the capture <video> or an <img>, and renders sprite geometry for a controlled time |
renders byte-identical scrubber preview markup across isolated SSR requests |
| SP19 |
SSR / hydration |
hydrate |
server markup hydrates without warnings or node replacement |
hydrates scrubber preview markup without warnings or node replacement |
| SP20 |
types |
compile |
kinds, statuses, and error codes are closed; captureVideoFrame returns Blob or string by output |
scrubber-preview.types.test-d.ts |
Captured thumbnails need a same-origin video or CORS headers (the capture video sets
crossorigin="anonymous"); otherwise canvases are tainted and capture reports …_TAINTED.