Black Gap and Playback Transitions
A black gap is a brief (or stuck) black / blank / frozen frame when the player changes content. TomorrowOS treats black gaps as a player-owned failure mode. The CMS (@tomorrowos/sdk) publishes a verified policy; the Tizen and BrightSign players keep the current picture on screen until the next item is ready, then hand off.
This guide describes what the shipped players do today for image and video transitions — not a fictional transition API.
Core principle
Never take good content off screen until the next content is ready.Shared player pattern:
- Two HTML content layers (front / back). Next item mounts on the back while the front stays visible.
- Image and video handoffs use an instant layer swap (not a fade). Opacity crossfade is reserved for widgets/web.
- Video often lives on a hardware plane (Tizen AVPlay / BrightSign
roVideoPlayer). The player bridges HTML ↔ hardware so neither plane exposes black between items. - Media is cached locally before play (see
assets-and-atomic-activation.md).
Shared mechanisms (both players)
Image → image
Tizen
- While the current image is on screen, the player prefetches the next image onto the back layer (multi-item only).
- At advance time it consumes that prefetch and does an instant layer swap — the next image is already painted under the previous one.
- If prefetch was missed (cold path), it mounts on the back layer (using decode warmup when available), then instant-swaps.
BrightSign
Same dual-layer + prefetch + instant-swap path as Tizen. NoroVideoPlayer involvement. Prefetch logs as image→image handoff prep; decode warmup feeds mountImageInLayer.
Image → video
Tizen
- Keep the image on the front layer.
- Mount video on the back (prefer dual AVPlay via
avplaystorewhen available; else singlewebapis.avplay; else HTML<video>). - Wait for first-frame readiness (AVPlay:
oncurrentplaytimeor a short timeout; HTML:playing+ paint frames). - Instant layer swap — only then clear the previous image.
- With AVPlay, HTML is made transparent so the hardware video plane shows through.
BrightSign
Video uses dualroVideoPlayer slots (not HTML HWZ for the normal playlist path).
- Keep the HTML image visible.
- Start the next
roVideoPlayerwith a hide-HTML delay (~300ms): play the file first, then fade the HTML widget alpha to 0 so the video plane covers the old image. - After a short JS delay (~420ms), instant layer-swap the HTML bookkeeping under the already-hidden widget.
- Gap cover = HTML image stays up until the video plane is actually playing, then HTML is hidden.
Video → image
Tizen
- During video (multi-item), prefetch the next image onto the back layer while AVPlay is still running.
- Dual AVPlay advances on
onstreamcompleted(not a wall-clock guess). For video → image it starts the image path without stopping AVPlay first — the last video frame stays up. - Consume prefetch (or cold-mount) → instant layer swap so the image is in the HTML stack.
- Then hold the video with
setVideoStillMode("true"), wait for HTML paint (~2 frames + short delay), and only then stop AVPlay / dual players.
BrightSign
- Prefetch next image on the back layer while
roVideoPlayeris still the active element (HTML stop is skipped while ro-video is active). - Instant-swap so the HTML image is visible.
- Then
handoffBrightSignRoVideoToHtml: wait for paint frames + ~120ms, restore HTML alpha, andStopClearboth ro-video slots. - Gap cover = image on screen before the video plane is torn down.
Video → video
Tizen (primary: dual AVPlay)
Whenwebapis.avplaystore is available:
- Two AVPlay instances ping-pong on
onstreamcompleted. - Completed slot:
setVideoStillMode("true")thenstop()— last frame frozen. - Other slot:
open→prepareAsync→ still mode off →play(). - No HTML layer remount for mid-playlist video → video — the cut stays on the hardware plane.
- Next file is warm-cached ahead of time.
- Single AVPlay — soft remount / preserve visual where possible; wait for first-frame gate; instant layer swap after mount.
- HTML
<video>— start the next item ~420ms early (VIDEO_TO_VIDEO_LEAD_MS), mount on back untilplaying, then instant swap.
BrightSign
- Playlist video uses two
roVideoPlayerslots with a rising z-index. - Next clip plays on the other slot at a higher z; the previous slot is not cleared while a ro-video remains active.
- HTML stays alpha 0 across the cut (
hideHtmlDelayMs: 0when already on ro-video). - Instant HTML layer swap is bookkeeping only — the visible cut is slot overlap on the video plane.
Loops
Single image loop
One image, repeating.
No transition → no black-gap opportunity.
Single video loop
One video, repeating.
Goal: avoid tearing down the decoder every lap.
Multi-item image / video loops
Playlist with two or more images and/or videos, cycling. Shared behaviour on both players:- One lap uses a frozen item list; hot policy updates that change composition apply on wrap.
- Mid-loop image → image / video → image: image prefetch on the back layer is the main anti-gap tool.
- Mid-loop video → video: platform dual-player path (AVPlay store / dual
roVideoPlayer). - Mid-loop image → video: keep image until video first frame / hide-HTML timing (platform-specific above).
- At wrap to index 0, prefetch for item 0 is cleared before restart — first item of the new lap may cold-mount; decode warmup and background cache still reduce risk.
- If composition changed on wrap, players take a full remount path instead of the in-place shortcuts.
Quick reference
What the SDK does (and does not)
@tomorrowos/sdk does not run these transitions. It:
- Verifies media reachability on publish
- Sends
device.content.setPolicywith playlist URLs / hashes - Lets the player cache and play
How to validate
On a real panel, publish playlists that exercise:- Image → image (two different images)
- Image → video
- Video → image
- Video → video (two different videos)
- Single image loop (long dwell)
- Single video loop
- Mixed multi-item loop (image / video / image / video …) for several full cycles
Goal
Keep the last good frame on screen until the next item can display — using dual HTML layers for images, and platform dual video players (AVPlay /roVideoPlayer) for video — so playlists look continuous on Tizen and BrightSign.