@htmlbricks/hb-player-live
v0.76.5
Published
Live streaming `<video>` player for HLS (hls.js or native), WebSocket WebRTC (`simple-webrtc-element`), or WHEP (MediaMTX). Polls the manifest for HLS liveness, exposes the element via `getVideoElement`, and emits `liveStatus` and `htmlVideoInit`. When th
Downloads
7,629
Readme
hb-player-live — integrator guide
Category: media · Tags: media, video, streaming · Package: @htmlbricks/hb-player-live
Summary
Live streaming player built on a native <video> element. It supports HLS (via hls.js when Media Source Extensions are available, or the browser’s built-in HLS where supported), WebRTC over WebSocket (simple-webrtc-element), and WHEP (MediaMTXWebRTCReader for MediaMTX-style endpoints).
For HLS, the component periodically fetches the manifest URL to decide whether the source is reachable (“live” for overlay purposes). For WebRTC and WHEP, online/offline is driven by the underlying player callbacks, which also update liveStatus.
When the URI is missing, the stream is considered offline, or you force a cover state, the component can show a full-area overlay (default copy, replacewithtext JSON, and optional slots).
Custom element tag
<hb-player-live …></hb-player-live>Attributes (snake_case; string values in HTML)
Web component attributes are always strings. Use yes / no for boolean-like flags where noted. Pass JSON as a single string for object props (for example replacewithtext='{"title":"…"}').
| Attribute | Required | Description |
| --- | --- | --- |
| mediauri | Yes | Stream endpoint: HLS playlist (.m3u8), WebSocket signaling URL for webrtc, or WHEP URL for whep. Use an empty string if you intentionally have no URI (placeholder state). |
| media_type | No | Playback mode: hls, webrtc, whep, or auto (see Media type). Default in the implementation is auto. The <video> node is only rendered when both mediauri and media_type are non-empty. |
| forcecover | No | Any non-empty value (commonly yes) forces the structured overlay when the conditions in the template are met (together with replacewithtext shape). |
| replacewithtext | No | JSON string: { "title": string, "subtitle"?: string, "text"?: string }. Used for default overlay copy; the component also parses a string value into an object when possible. |
| no_controls | No | Hide native <video> controls when set to any truthy value except the strings no or false (for example yes). |
| id | No | Passed through on custom events and when exposing the video element. |
The authoring Component type also allows style; styling is normally done via CSS variables, ::part, and host layout.
Media type
Set media_type explicitly for working playback:
hls— Loadsmediauriwith hls.js (or assignssrcon Safari / browsers that report native HLS support). Autoplay is attempted with muted video.webrtc— Usessimple-webrtc-elementwithwsUri: mediaurion the bound<video>.whep— UsesMediaMTXWebRTCReaderwithurl: mediauri; the first stream track is assigned tovideo.srcObject.
The literal value auto appears in the public type union and is the Svelte default, but the internal setVideo path only wires hls, webrtc, and whep. Treat auto as reserved / not implemented for playback until a future version adds detection.
Live status and polling
hls:loadLive()performs afetch(mediauri)on the manifest. A response in the 1xx–299 range sets internal “live” to true and dispatchesliveStatuswithlive: true. On failure, it dispatcheslive: falseand retries after 5 seconds (also whenmediauriis empty).webrtc/whep:liveStatusis dispatched from online/offline handlers in the respective integrations (live: true/live: false).
Overlay and fallback UI
The dark 16:9 surface uses Bulma variables --bulma-dark and --bulma-dark-invert (see Styling).
Rough behavior (see component.wc.svelte for exact conditions):
forcecoveris set, ormediauriis set,isLiveis false, andreplacewithtextincludes at least one oftitle,subtitle, ortext— shows thereplacewithtextpart with the default slot layout (one, two, or three lines depending on which JSON fields are present), unless you override thereplacewithtextslot entirely.- Otherwise, if there is a
mediauribut the stream is not live and there is noreplacewithtextcopy — shows the literalofflinelabel in the overlay. - If there is no
mediauri— showsnouriin the overlay.
If you supply the replacewithtext slot, you replace the entire default overlay markup for that branch; the inner slots (replacetitle, replacesubtitle, replacetext) only apply inside the default structure.
Events
Listen with addEventListener on the host element (names are camelCase in the type definitions).
| Event | detail (runtime) |
| --- | --- |
| liveStatus | { live: boolean; id: string } |
| htmlVideoInit | { htmlVideoElement: HTMLVideoElement; id: string } — fired when the <video> is bound. |
TypeScript typings (authoring)
types/webcomponent.type.d.ts defines Component, Events (liveStatus, htmlVideoInit with htmlVideoElement), and nested shapes for replacewithtext.
Host API
After upgrade, the custom element exposes:
getVideoElement()— Returns the internalHTMLVideoElementwhen it exists, otherwiseundefined.
Styling (CSS custom properties)
Set on the host or an ancestor. The video frame and overlay use Bulma dark tokens.
| Variable | Role |
| --- | --- |
| --bulma-dark | Background of the 16:9 video area and offline/cover overlay. |
| --bulma-dark-invert | Foreground (text) on that surface. |
See Bulma CSS variables for theme-wide tuning.
CSS parts (::part(...))
| Part | Purpose |
| --- | --- |
| container | Root wrapper around the player and overlay; sizing and positioning of the whole component. |
| replacewithtext | Full-bleed overlay when the stream is missing, not live, forcecover applies, or placeholder copy is shown. |
| video | The native <video> element (streaming surface, native controls when enabled). |
HTML slots
| Slot | When it matters | Purpose |
| --- | --- | --- |
| replacewithtext | Overlay branch with default structure | Replace the entire offline/cover layout. If you fill this slot, the default grid and nested slots are not used unless you reintroduce them in your markup. |
| replacetitle | Default overlay only | Title line; falls back to replacewithtext.title. |
| replacesubtitle | Default overlay (two- or three-line layout) | Subtitle line; falls back to replacewithtext.subtitle when the prop defines both title and subtitle. |
| replacetext | Default three-line layout | Body copy; falls back to replacewithtext.text. |
Usage notes
- Autoplay: The implementation sets
mutedand callsplay()where possible; browser policies may still block autoplay with sound or without user gesture. - Changing
mediauri: When the URI changes, WHEP readers are closed, live state is reset, and the video is reinitialized. - Accessibility: The markup includes a captions
<track>placeholder; provide real captions/tracks in your integration if you need accessibility compliance.
Examples
HLS (public test stream)
<hb-player-live
mediauri="https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8"
media_type="hls"
></hb-player-live>WHEP endpoint (replace with your server URL)
<hb-player-live
mediauri="https://example.com/path/to/whep"
media_type="whep"
></hb-player-live>Forced cover with JSON copy (replacewithtext must be a valid JSON string attribute)
<hb-player-live
mediauri="https://example.com/stream/whep"
media_type="whep"
forcecover="yes"
replacewithtext='{"title":"Stream paused","subtitle":"We will be back soon","text":"Thank you for waiting."}'
></hb-player-live>Hide native controls
<hb-player-live
mediauri="https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8"
media_type="hls"
no_controls="yes"
></hb-player-live>Listen for live state and grab the video element
<hb-player-live
id="cam1"
mediauri="https://example.com/live.m3u8"
media_type="hls"
></hb-player-live>
<script>
const el = document.querySelector("#cam1");
el.addEventListener("liveStatus", (e) => {
console.log(e.detail.live, e.detail.id);
});
el.addEventListener("htmlVideoInit", (e) => {
console.log(e.detail.htmlVideoElement, e.detail.id);
});
customElements.whenDefined("hb-player-live").then(() => {
const v = el.getVideoElement?.();
if (v) console.log("video", v);
});
</script>