annie.pages.videoclock

Frame-accurate control of one HTML5 <video> element (UI, browser-gated).

The Event-annotation task drives a single ui.video from Python: play/pause, seek to a time or a frame, step frame-by-frame, and jump ±5 s. HTML5 video exposes only a time cursor (currentTime in seconds), not a frame cursor, so every frame operation converts through the video’s fps:

frame -> currentTime = frame / fps + half_frame_nudge time -> frame = round(currentTime * fps)

Documented limitation. Because seeking is time-based, the landed frame is round(currentTime * fps). On constant-fps media — which Annie’s convert pipeline produces (see annie.media.convert) — this is exact. On a variable-fps source it can be off by one frame. That is the accepted trade-off for smooth playback with audio, which a torchcodec frame-by-frame decoder cannot give; an exact confirm is a possible later refinement, deliberately out of scope here.

This module is a thin bridge: each function returns the JavaScript that acts on the element, run via nicegui.ui.run_javascript(). It holds no state — the task owns the model. It is exercised in the browser, not unit-tested, like the other ui.video paths.

Functions

element_id(→ str)

Return the stable DOM id given to the task's video element for a client.

play(→ None)

Start playback of the video element.

pause(→ None)

Pause the video element.

toggle(→ None)

Toggle play/pause on the video element.

seek_seconds(→ None)

Seek the video to an absolute time in seconds (clamped at zero).

seek_frame(→ None)

Seek the video to a specific frame via its time, with a half-frame nudge.

step_frames(→ None)

Pause and move the cursor by delta frames (positive forward, negative back).

nudge_seconds(→ None)

Jump the cursor by delta seconds (the ±5 s buttons), clamped at the start.

current_time(→ collections.abc.Awaitable[float])

Read the video's current time in seconds from the browser.

set_playhead_x(→ None)

Move the timeline playhead line to a horizontal fraction without a full re-render.

set_scrollbar(→ None)

Move the pan scrollbar's thumb without rebuilding it (so a drag is not interrupted).

set_pending_band(→ None)

Resize the amber capture band without a full re-render, while a start is armed.

Module Contents

annie.pages.videoclock.element_id(client_id: str) → str[source]

Return the stable DOM id given to the task’s video element for a client.

Parameters:

client_id – The NiceGUI client id (context.client.id).

Returns:

A DOM id unique to that client’s Event-annotation video.

annie.pages.videoclock.play(element_id_: str) → None[source]

Start playback of the video element.

annie.pages.videoclock.pause(element_id_: str) → None[source]

Pause the video element.

annie.pages.videoclock.toggle(element_id_: str) → None[source]

Toggle play/pause on the video element.

annie.pages.videoclock.seek_seconds(element_id_: str, seconds: float) → None[source]

Seek the video to an absolute time in seconds (clamped at zero).

Parameters:
  • element_id – The video element’s DOM id.

  • seconds – The target time; negative values clamp to the start.

annie.pages.videoclock.seek_frame(element_id_: str, frame: int, fps: float) → None[source]

Seek the video to a specific frame via its time, with a half-frame nudge.

Parameters:
  • element_id – The video element’s DOM id.

  • frame – The target frame index (clamped at zero).

  • fps – Frames per second; a non-positive fps seeks to the start.

annie.pages.videoclock.step_frames(element_id_: str, delta: int, fps: float) → None[source]

Pause and move the cursor by delta frames (positive forward, negative back).

Parameters:
  • element_id – The video element’s DOM id.

  • delta – Number of frames to move; sign gives the direction.

  • fps – Frames per second; a non-positive fps is a no-op.

annie.pages.videoclock.nudge_seconds(element_id_: str, delta: float) → None[source]

Jump the cursor by delta seconds (the ±5 s buttons), clamped at the start.

Parameters:
  • element_id – The video element’s DOM id.

  • delta – Seconds to move; sign gives the direction.

annie.pages.videoclock.current_time(element_id_: str) → collections.abc.Awaitable[float][source]

Read the video’s current time in seconds from the browser.

Used when I/O capture the playhead: the caller awaits this, converts to a frame, and writes the event boundary. Returns 0.0 if the element is gone.

Parameters:

element_id – The video element’s DOM id.

Returns:

An awaitable resolving to the current time in seconds.

annie.pages.videoclock.set_playhead_x(timeline_id: str, x_fraction: float | None) → None[source]

Move the timeline playhead line to a horizontal fraction without a full re-render.

The playhead is a single SVG line inside the timeline element; the poll updates only its position so playback stays cheap (no server round-trip re-draw of the event boxes).

Parameters:
  • timeline_id – DOM id of the timeline’s SVG element.

  • x_fraction – Playhead position as a fraction [0, 1] of the visible window, or None when the playhead is outside it — the line is then hidden, never pinned to an edge.

annie.pages.videoclock.set_scrollbar(scroll_id: str, left: float, width: float) → None[source]

Move the pan scrollbar’s thumb without rebuilding it (so a drag is not interrupted).

Parameters:
  • scroll_id – DOM id of the scrollbar track.

  • left – The thumb’s left edge as a fraction of the track.

  • width – The thumb’s width as a fraction of the track.

annie.pages.videoclock.set_pending_band(timeline_id: str, start_fraction: float, end_fraction: float) → None[source]

Resize the amber capture band without a full re-render, while a start is armed.

Mirrors set_playhead_x(): the band is one .annie-pending rect, and the poll updates only its x/width from two [0, 1] fractions so it grows with the playhead cheaply. Fractions are ordered and clamped, so a playhead left of the start still yields a valid (leftward) band.

Parameters:
  • timeline_id – DOM id of the timeline’s SVG element.

  • start_fraction – The band’s start edge as a fraction of the timeline width.

  • end_fraction – The band’s end edge (the live playhead) as a fraction of the width.