@htmlbricks/hb-matrix-video
v0.76.5
Published
Responsive video wall: lays out `items` in Bulma `columns` / `column` rows (gapless) sized from the viewport (16:9-friendly). Each cell can be an iframe, plain MP4 `<video>`, `hb-player-live` (WHEP), or `hb-player-live-camera-ptz`. Tracks hover selection
Readme
hb-matrix-video
Category: media · Tags: media, video, grid · Package: @htmlbricks/hb-matrix-video
Overview
hb-matrix-video is a responsive video wall custom element. It lays out a list of tiles (items) in a gapless Bulma columns / column grid, sizes the grid from the host viewport, and biases layouts toward a 16:9 cell aspect ratio. Each tile can embed a page (iframe), an MP4 stream (video), a WHEP live player (hb-player-live via mediamtx-webrtc), or a PTZ camera player (hb-player-live-camera-ptz via mediamtx-webrtc-ptz).
The component tracks which tile is under the pointer and emits hoverItem and clickItem custom events (see Events).
Custom element
hb-matrix-video
Dependencies
The bundle registers hb-player-live and hb-player-live-camera-ptz (same package version as this component). PTZ tiles render hb-player-live-camera-ptz with media_type="whep" and live_uri="{uri}/whep". Plain WebRTC tiles use hb-player-live with media_type="whep" and mediauri="{uri}/whep".
Attributes (snake_case; string values in HTML)
Web component attributes are strings. Complex data must be JSON on a single attribute (see HTML Bricks development conventions for your bundle version).
| Attribute | Required | Description |
|-----------|----------|-------------|
| items | Yes | JSON string: array of tile objects (see Tile items). |
| id | No | Optional element id. |
| style | No | Optional; present in authoring types for host styling when supported by your integration. |
Tile items
Each entry is an object with:
| Field | Required | Description |
|-------|----------|-------------|
| type | Yes | "iframe" | "video" | "mediamtx-webrtc" | "mediamtx-webrtc-ptz". |
| id | Yes | Stable string id for the tile (used in events and DOM id="select_{id}"). |
| uri | Yes | iframe: src URL. video: MP4 source URL. mediamtx-*: base URL; the component appends /whep for the player. |
| title | No | iframe: title attribute. video: passed to <source> (may be ignored by browsers for source). |
Example items value (escaped for HTML):
[
{"type":"iframe","id":"cam-1","uri":"https://example.com/embed","title":"Camera 1"},
{"type":"mediamtx-webrtc","id":"live-1","uri":"https://mediamtx.example.com/mystream"}
]Layout behavior
- Sizing: On mount and on window resize (debounced), the inner
#matrixcontainer height is set from the window height minus its offset from the top; width uses the container client width. Rows and columns are recomputed from that box. - One tile: Single row and column.
- Narrow viewports: If the container width is below 450px, tiles stack in one column (one tile per row).
- Two tiles: If the container is wider than 16:9, tiles sit side by side; if taller, they stack vertically.
- Three or more: The implementation searches row/column counts that keep the implied 16:9 grid within the container (different strategy for landscape vs portrait container aspect ratio).
Empty or invalid items JSON is logged to the console; the grid renders when items is a valid array.
Events
Listen with addEventListener or your framework’s DOM bindings.
| Event | detail | When it fires |
|-------|----------|----------------|
| hoverItem | { id?: string; selected: boolean } | Pointer enters a tile (id set, selected: true) or leaves the tile (id omitted, selected: false). |
| clickItem | { id: string } | When a selected tile id exists and an iframe tile’s same-origin document receives a click (the implementation attaches a listener on iframe load). Other tile types do not currently wire this path in the source. |
Styling (Bulma + host tokens)
The shadow root includes Bulma columns / column and spacing utilities. You can theme the wall with CSS variables; see Bulma CSS variables and extra/docs.ts for defaults.
| Variable | Purpose |
|----------|---------|
| --bulma-column-gap | Horizontal gap between column cells (default 0.75rem in metadata). |
| --bulma-scheme-invert | Default full-bleed background behind tiles when --hb-matrix-video-bg is unset. |
| --hb-matrix-video-bg | Optional explicit host background behind the grid (falls back to --bulma-scheme-invert). |
CSS parts
None.
Slots
None.
TypeScript (authoring)
export type Component = {
id?: string;
style?: string;
items: {
type: "video" | "iframe" | "mediamtx-webrtc" | "mediamtx-webrtc-ptz";
id: string;
uri: string;
title?: string;
}[];
};
export type Events = {
hoverItem: { id?: string; selected: boolean };
clickItem: { id: string };
};Minimal HTML example
<hb-matrix-video
id="wall-1"
items='[{"type":"iframe","id":"1","uri":"https://example.com/embed","title":"Stream"}]'
></hb-matrix-video>Vanilla JavaScript example
const el = document.querySelector("hb-matrix-video");
el.addEventListener("hoverItem", (e) => {
console.log("hover", e.detail.id, e.detail.selected);
});
el.addEventListener("clickItem", (e) => {
console.log("click", e.detail.id);
});
el.setAttribute(
"items",
JSON.stringify([
{ type: "video", id: "a", uri: "https://example.com/file.mp4" },
{ type: "iframe", id: "b", uri: "https://example.com/other" },
])
);Notes
- Cross-origin iframes: Browsers block access to
contentWindowfor cross-origin documents; in that case theiframeclick bridge may not run andclickItemmay not fire—hoverItemstill reflects pointer hover. - Console: The implementation may log layout debug information during development builds.
