SnapDOMGitHub★ 8K
Labs Experiment

An HTML overlay, sent over WebRTC

Left: video with an HTML scorebug composited on top. Right: the same picture received as a WebRTC track. No OBS, no server.

TL;DR

The stream plugin keeps the overlay as a canvas. A program canvas draws it over the footage, captureStream() turns that into a video track, and WebRTC carries it.

Try it

Change the score, slide the lower third, or put your camera behind the graphics. The right side follows a few frames later. Open a viewer tab to add a receiver.

Program output (sender)canvas
Received over WebRTCvideo
Open a viewer tab
starting

How it works

  1. The overlay is HTML

    Scoreboard, live badge and lower third are plain DOM on a transparent 960×540 stage. The lower third slides with left, not transform, so the stream patches a strip instead of repainting the frame.

  2. stream() keeps it as a canvas

    After the first full capture, only changes are captured and patched in. The stats line shows the median repaint cost.

  3. A program canvas composites it

    Each frame draws the footage, then the overlay canvas on top.

  4. captureStream() makes it a track

    The program canvas becomes a MediaStreamTrack. contentHint: 'detail' keeps the text sharp when bandwidth drops.

  5. WebRTC carries it

    Both peers run in your browser; viewer tabs find the sender through a BroadcastChannel. A real app does the offer/answer through its own signalling server. The media path is the same.

The code

import { stream } from '@zumer/snapdom-plugins/stream'

const overlay = stream(stage, { embedFonts: false })

function frame() {
  ctx.drawImage(footage, 0, 0, 960, 540)
  ctx.drawImage(overlay.canvas, 0, 0, 960, 540)
  requestAnimationFrame(frame)
}
requestAnimationFrame(frame)

const track = program.captureStream(30).getVideoTracks()[0]
track.contentHint = 'detail'
peerConnection.addTrack(track)