11 KiB
status, date, definition
| status | date | definition |
|---|---|---|
| draft | 2026-05-22 | technical |
Background-looping video
Engine variant for silent, autoplay-looping video on ambient/decorative
surfaces (hero backgrounds, GIF-replacement loops, editorial previews).
The Case-2 Player feature per
../features/clusters.md § Feature classification axes;
ground-truth source the Mux mux-background-video
product adapted to Video.js 10. Phase 1 is the SPF foundation for
<mux-background-video> under parent epic
#873; the composition
demonstrates SPF composability by removing behaviors from the standard
playback engine rather than adding new logic.
Distinct from video-only-mode-override:
both subtract audio from mixed-source manifests, but background-looping-
video also commits to single-rendition playback, loop semantics,
autoplay-via-initial-state, and a product-shaped adapter — mode-override
is the narrower "deliver video-only despite mixed source" use case.
Status
Phase 1 implemented (#1586):
createBackgroundLoopingVideoEngine, BackgroundLoopingVideoMediaElement,
and the pickMaxResolutionVideoTrack primitive ship under
@videojs/spf/background-looping-video. Phases 2-3 (decorator composition
of audio and preload) and Phase 4 (Video.js component shell — out of SPF
scope) stay coarser.
Phases
Adopts the parent-epic #873 phase structure — phases map to discrete epic deliverables.
| Phase | What |
|---|---|
| 1 — Composition + adapter (#1586) | Subtractive composition removing audio, text, ABR, preload-monitoring, and play/seek-monitoring behaviors; adds selectVideoTrack with a max-resolution picker; seeds loadActivated: true; ships independent adapter parallel to SimpleHlsMediaElement. HLS multivariant source; native mediaElement.loop = true. |
2 — withAudio() decoration |
Composes audio-side behaviors back in for surfaces needing audio (user-initiated unmute, audible ambient). Decorator shape TBD. |
3 — withPreload() + optimizations |
Composes preload-state monitoring back in for lazy/viewport-gated tiles. Co-scoped with loop-around forward-buffer fetching, GPU/thermal-aware quality caps, and a sampling-strip alt-impl of loadVideoSegments. |
| 4 — Video.js component | Full <mux-background-video> integration. Out of SPF scope — adapter / consumer territory. |
Composition specifics
Phase 1 uses three mechanisms — subtract, add, and alternative default configuration. Alternative-implementation buckets surface in Phase 3.
Subtracted
From createSimpleHlsEngine:
syncPreload,trackLoadTriggers— no preload-state monitoring or DOMplay/seekingactivation; replaced byloadActivated: trueinitial state.selectAudioTrack,selectTextTrack,resolveAudioTrack,resolveTextTrack,setupAudioBufferActors,loadAudioSegments— no audio side.syncTextTracks,setupTextTrackActors,loadTextTrackSegments— no text-track machinery.switchVideoQuality— no ABR; commits to a single rendition for the session.
Added
selectVideoTrack (from select-tracks.ts)
with a config-provided picker, defaulting to pickMaxResolutionVideoTrack.
Per switchVideoQuality's docstring: "Composing selectVideoTrack alone
tree-shakes out the ABR code path." — exactly the affordance Phase 1 wants.
Alternative default configurations
initialState.loadActivated: true(Phase 1) — seeds the composition into the post-preload-gate state from frame 0. Combined with thesyncPreload/trackLoadTriggerssubtractions, every downstream behavior that would otherwise gate on!isBlockingPreload(preload) || loadActivatedseesloadActivatedtruthy from the start.picker(Phase 1) — defaults topickMaxResolutionVideoTrack; overridable for mobile/content-aware caps.- Back-buffer tuning (Phase 3 candidate) — larger back-buffer for gapless wrap-around (per
buffer-management'sBackBufferConfig.keepSegments). - GPU/thermal-aware quality caps (Phase 3 candidate) — shared concern with
video-only-mode-override.
Alternative implementations (Phase 3 candidates)
- Sampling-strip
loadVideoSegments— the standard loader samples bandwidth intostate.bandwidthStateto feed ABR. WithswitchVideoQualitysubtracted, no consumer reads it; sampling is harmless but wasted work. PerREADME.md§ Implementation note, likely Path B (the sampling assumption is structurally tied to ABR). - Loop-around forward-buffer fetching — pre-fetch the wrap-around for gapless restart. See
buffer-management"What's not implemented".
Customer-policy surface
Independent adapter parallel to SimpleHlsMediaElement:
const bgPlayer = new BackgroundLoopingVideoMediaElement({ picker: maxResolutionPicker });
bgPlayer.src = sourceUrl;
bgPlayer.loop = true; // native HTMLMediaElement.loop
bgPlayer.muted = true; // browser autoplay policy
bgPlayer.play();
Engine config: picker (TrackPicker, default max-resolution); later
phases add withAudio() / withPreload() decorator hooks. Native loop
/ muted live on the underlying media element. Adapter-layer concerns
(autoplay-muted defaults, loop policy refinements, GPU/thermal caps, the
Video.js component shell) live above the SPF engine.
Variant-decision signal source
Adapter-upfront. Selecting BackgroundLoopingVideoMediaElement is
the variant choice — no parser detection, no runtime config branch. Same
resolution as video-only-mode-override
and audio-only-mode-override: Case-2
use cases resolve via adapter choice.
Constituent features
Phase 1 baseline:
video-only-composition— used at the composition-mechanism level; same audio-side subtraction pattern as the Case-1 feature, driven by adapter choice instead of source-shape detection. Plus further subtractions (text, ABR, preload).engine-adapter-integration— variant adapter parallelsSimpleHlsMediaElementvia the sameSimpleHlsMediaMixin/shareSignalspattern.mse-mms-pipeline— used as-is. FirefoxmozHasAudio=falseverification under subtractive-audio composition is joint Phase 1 scope withvideo-only-mode-overrideand the Case-1video-only-compositionfeature.buffer-management— as-is in Phase 1; Phase 3 surfaces back-buffer tuning and loop-around forward-buffer fetching (the "loop-around buffer fetching" candidate in that feature's What's not implemented directly targets this use case).preload-modes— alternative initial state (loadActivated: true) plus subtraction ofsyncPreload+trackLoadTriggers. Semantic contract preserved; the variant just seeds the gate-passable state from composition time.
Subtracted (cross-link discipline):
video-abr— single rendition for the session.multi-language-audio— audio fully subtracted.subtitles— text fully subtracted; may resurface if awithCaptions()-style extension is scoped.
Phase 2 (decorations TBD): audio-playback, audio-abr.
Likely cross-cutting impact
- Shared engine factory. Three use cases now want subtractive-audio composition (this,
video-only-mode-override, Case-1video-only-composition). Lean: shared factory at the subtractive-audio level, with this use case layering further subtractions (text, ABR, preload) and an initial-state override on top. - Firefox
mozHasAudioverification. Joint scope with the two sibling cases — same mixed-source-with-audio-subtracted permutation. - Adapter proliferation. N+1 adapter parallel to
SimpleHlsMediaElement; three adapters share theSimpleHlsMediaMixin/shareSignalspattern — cost is configuration surface, not architecture. loadActivated: trueinitial-state pattern. Pioneered here. If a second use case wants the same shape, consider a sharedwithAutoLoad()-style helper or document treatment inpreload-modes.
Open questions
- Phase 2/3 decorator pattern shape. Decorator on the engine factory? Composable-feature abstraction? Engine-config flags re-including subtracted behaviors? Resolves when Phase 2/3 are scoped.
- Shared engine factory. Joint with
video-only-mode-overrideand Case-1video-only-composition. Lean: shared, with this case composing further subtractions. - Sampling-strip alt-impl Path A vs B. Likely Path B per
README.md§ Implementation note. - GPU/thermal-aware quality caps boundary. Engine-variant (compose a thermal-aware behavior) or adapter (cap the picker candidate set). Likely engine-variant given the product context.
Resolved Phase 1: picker location (pickMaxResolutionVideoTrack ships in media/primitives/select-tracks.ts next to pickFirstTrackId); adapter naming (BackgroundLoopingVideoMediaElement; product-shell naming <mux-background-video> lives in the adapter layer).
See also
video-only-mode-override.md— peer use case; shares constituent features and FirefoxmozHasAudioscope; differs in delivery-scenario specificity (this is the Mux-product-shaped variant with loop, single-rendition, autoplay-via-initial-state).audio-only-mode-override.md— inverse-axis sibling; shares adapter-upfront pattern and the shared-engine-factory open question.README.md— use-case-composition doc-type spec.../features/clusters.md§ Composition vs Policy vs middle pattern ·../conventions/behaviors.md§ Inverse: behaviors that operate uniformly across tracks.../../../../packages/spf/docs/hls-engine.md— HLS engine composition baseline the variant subtracts from.select-tracks.ts(add target) ·engine.ts(subtraction baseline).- GitHub #1586 (Phase 1) · #873 (parent epic) ·
mux-background-video(prior art) · SPF Epics Working Doc.