Lowest latency in the browser

How the page around the player, fullscreen and the display's refresh rate add to the delay a viewer sees, and what to do when every millisecond counts.

Once a frame reaches the browser, the page decides how quickly it reaches the screen. Most apps never need to think about this. If yours is steered by the person watching (a robot, a vehicle, a remote machine), these few rules take the most off the delay between the camera and the viewer's eyes.

Draw nothing over the video

The browser can hand a video picture to the screen directly only when nothing is drawn on top of it. Any HTML layered over the video (a control bar, a caption, a badge, a semi-transparent panel) makes the browser compose the whole page into one picture first, which adds a step for every frame.

  • For anything you steer (robotics, remote control, a remote desktop), put the controls, status and chat beside the video, not on it.
  • Where a few milliseconds do not matter (a crowd game, chat over a live event, a watch party), overlays are fine.

<nearglass-player> draws nothing over the video: its mode, status and buttons are in a bar under the picture.

Fullscreen is the fastest path

Fullscreen, with nothing over the video, is the fastest way to the screen. In Chrome on Windows, a fullscreen <video> that fills the screen with nothing above it can become its own layer that the display shows without composing the page. In glass-to-glass measurements of the same technique on a Windows desktop (not through the Nearglass service), this path was clearly faster than drawing to a canvas; the figures are not published.

The player's engine, createPlayer, can take this path in Chrome when you give it a <video> and tell it when the page goes fullscreen. Make the whole page fullscreen (document.documentElement), not the video element, and hide everything else while it is:

const player = createPlayer({ /* ... */ canvas, video });  // video: an empty <video muted playsinline>

fullscreenButton.addEventListener('click', async () => {
  player.fullscreen.before();
  try { await document.documentElement.requestFullscreen({ navigationUI: 'hide' }); }
  catch { player.fullscreen.refused(); }
});
document.addEventListener('fullscreenchange', () => {
  if (document.fullscreenElement) player.fullscreen.enter(); else player.fullscreen.exit();
});
addEventListener('resize', () => player.fullscreen.layout());

The switch is seamless both ways: the canvas keeps the last frame until the video has shown its first, and back. Where the browser cannot take this path, the player keeps drawing on the canvas. It is not available yet with present: 'worker', play() or <nearglass-player>. See the player reference for the video, layout and scanTargetClass options.

The refresh rate matters

A display shows a new picture only at its next refresh. A frame that arrives just after one waits for the next:

DisplayLongest waitAverage wait
60 Hz16.7 msabout 8 ms
144 Hz6.9 msabout 3.5 ms

For the lowest delay, use a high refresh rate display, and the player's default latency mode, which draws each frame as soon as it arrives rather than holding it for an even pace (Presentation modes).

How the player draws today

PathStatusWhen
Canvas on the pageVerified, the defaultevery browser that plays MoQ
Canvas drawn in a worker (present: 'worker')Available, as an optionkeeps drawing off the page's busy main thread
Fullscreen video, drawn by the display directlyBeta: in createPlayer, Chrome only; its geometry and the switch checked in software on one machinepage fullscreen with nothing over the video, as above
The player trying each path on the viewer's own setup and choosing the fastest, and fullscreen video in the worker path, play() and <nearglass-player>Planned

None of these paths has been measured glass to glass through the service yet (Performance).

On this page