jatui

VideoPlayer

One video surface: waveform scrubber, chapters, diarized speakers, bookmarks and transcript — every intelligence prop optional

Everything on

Scroll over the band to zoom (double-click or Esc resets); scroll over the video for volume (Shift + scroll seeks). Hover a legend chip to raise that speaker on the timeline, click it to solo, and use the speaker icon to skip them. Chapter flags sit on the top edge, bookmark diamonds on the bottom.

0:00 0:10

One time axis — light ribbon + comments + likes

With an envelope the band owns the time axis: the native timeline stands down (Chromium). Scroll to zoom and a whole-video overview rail appears above the band with the zoomed window bracketed; click it to jump. The warm wash under the envelope is the light ribbon — bright passages glow before you reach them. Drag along the band to scrub (it replaces the native timeline, so it scrubs like one). Comment dots ride under the chapter flags (hover to read, click to jump, or { / } for previous / next — announced to screen readers); likes fold into a heat strip along the bottom edge.

0:00 0:10

onBandChange → (waiting for metadata)

Night dimming — meter, bias light, predictive dimming, strobe guard

A meter, not a preference: about once a second the player reads the frame's actual brightness and pulls the picture down in proportion, warming it through multiply layers so blacks stay black — a dark scene passes through untouched. auto arms it from the local clock (20:00–07:00), on always, off never; press N or click the moon under the band to cycle, scroll the moon to set the depth. The light track (luma) lets dimming start before the white-out at 6s, and its flash interval (3–4.5s) is held down by the strobe guard. While dimming, the frame's own colours glow softly behind the player; on a light theme the player's surround is pulled down with the picture. Needs a CORS-readable video (crossorigin="anonymous").

0:00 0:10

No waveform — the speaker lane takes over

Without an envelope the band falls back to a flat rail, and the slim lane beneath it carries who-spoke-when. Only ever one speaker surface, never two stacked strips saying the same thing.

0:00 0:00

Bare mp4 — no intelligence data at all

Every extra prop is optional. With none of them you still get the band as a real scrubber (hover for time, click to seek, arrows to step) plus wheel volume and the keyboard map.

0:00 0:00

Deep-link the timestamp (?t=) + CORS

With syncUrlTime on, a ?t= param seeds the start position and playback keeps it in step (replaceState, whole seconds, other params preserved) — refresh or share the URL and it picks up where you left off. crossorigin="anonymous" passes through to the <video> — what frame-reading features need. Press ? for the full keyboard map (speed steps, frame step, chapter jumps, bookmark, transcript toggle).

0:00 0:10

Side transcript

0:00 0:10

Long transcripts — windowed + theme-token speakers

A 2h talk is 2–3k transcript rows; this instance mounts 1,800 of them but only the rows near the viewport exist in the DOM (scroll it — the player auto-follows the active segment as it plays). Speaker identity colours are derived from the active theme's semantic tokens and lifted to WCAG AA against the surface, so they follow the ThemeSelector — switch theme in the header and the same speakers change colour with it.

0:00 0:00

Presentation mode — aspect-lock + autoplay + loop

The same component is the presentation primitive: aspect locks the stage box from the first frame (poster convention — the poster fills the ratio until the first frame decodes), autoplay starts it muted (honouring prefers-reduced-motion — under that preference it holds on the poster), and loop repeats it.

0:00 0:00

Props

PropTypeDefaultDescription
srcstring—Video URL (required)
posterstring | nullnullPoster frame
captionsSrcstring | nullnullVTT captions track
chaptersVideoChapter[][]Flags on the top edge; sections in the envelope; hover card titles
speakersVideoSpeakerTurn[][]Diarized turns — colour the envelope, or the fallback lane
transcriptVideoTranscriptSegment[][]Transcript pane + "what's being said here" on hover
bookmarksVideoBookmark[][]Diamonds on the bottom edge
waveformVideoWaveform | nullnullAudio envelope; peaks normalise against their own max
talkTimeVideoSpeakerTalkTime[][]Precomputed totals; derived from turns/transcript when omitted
startAtnumber | nullnullSeek here once metadata lands
transcriptPosition'below' | 'side''below'Transcript beneath, or beside on wide viewports
lumaVideoLumaTrack | nullnullLight track (0–99 at rate/s) — paints the light ribbon under the envelope
markersVideoMarker[][]Comment dots (hover/click) and a like heat strip on the band
oneAxisbooleantrueBand owns the axis while it has an envelope; zoomed ⇒ overview rail with bracket
onBandChange(state: BandState) => void—Four-state arbitration (band/overview/bar/both), real changes only, microtask-deferred
onMarkerClick(marker, cluster) => void—A comment dot was clicked (after the seek to the earliest); cluster = every comment merged into that dot
night'auto' | 'on' | 'off' (bindable)—Night dimming. Omitted ⇒ the feature doesn't exist here (no N, no button, no layers)
nightDepthnumber (bindable)0.70.2–1; depth 1 takes a white frame to about half brightness
nightWindow{ from, to } | nullnullLocal hours for auto (default 20–7; 18–8 when the OS prefers dark)
biasLightbooleantrueThe frame's own colours, blurred, behind the player while night acts
predictivebooleantrueRead luma ~1s ahead so dimming starts before a bright cut (only ever adds dimming)
strobeGuardbooleantrueHold the level down across luma.flashes — independent of night
onNightModeChange(mode) => void—N / the moon button changed the mode (persist it)
onNightBlind() => void—Frame readback refused (CORS) — night fell back to a fixed level
onTimeUpdate(video) => void—Every timeupdate tick (watch-progress reporting)
onAddBookmark(sec, label) => void—Present ⇒ renders the add-bookmark control
onBookmarkContext(sec, existing, x, y) => void—Right-click on the band; the host owns the panel

Keyboard

  • Space / K — play / pause
  • ← → / J L — seek ±5s (Shift for ±10s)
  • ↑ ↓ — volume ±5%, M — mute
  • − = — speed down / up one step, Backspace — reset to 1×
  • < > — frame step (pauses, ~1/30s per press)
  • [ ] — previous / next chapter, B — bookmark here, T — show / hide transcript
  • Home / End — jump to start / end
  • N — night dimming auto / on / off (when the host passes night)
  • ? — the in-player keyboard overlay (only advertises keys whose data exists)
  • Band focused: arrows seek, Esc resets zoom