Skip to content

Plugin: Touch Zones

TouchZonesPlugin (id 'touch-zones') renders a transparent tap-zone overlay for touch and mobile input, single-tap to show/hide controls or toggle playback, double-tap to seek or adjust volume, the interaction model most streaming apps train users to expect. It sits at a z-index between the video element and the desktop UI controls overlay, so it intercepts taps meant for the video area without blocking button clicks on a control bar mounted above it.

Options

OptionTypeDefaultPurpose
doubleTapThresholdnumber300Milliseconds between taps that still counts as a double-tap.
seekSecondsnumber10Seconds to seek on a double-tap in the left/right zones.
disableClickToPausebooleanfalseStop the center zone’s single-tap from toggling playback. Mirrors DesktopUiPlugin’s own disableClickToPause, both plugins ship independent click handlers on different DOM layers, so the same override is needed on both when a consumer wants a custom center-tap behavior.

Zone layout

A 3-column x 6-row grid. Desktop/tablet touch gets three columns spanning the full height (seek-back, playback+fullscreen, seek-forward); mobile additionally splits two rows off the top and bottom of the center column for volume up/down, detected via ontouchstart presence or navigator.maxTouchPoints.

ZoneSingle-tapDouble-tap
Left (seek back)Dismiss controls if visible, no-op otherwise, touchstart already woke them.Seek back seekSeconds.
Center (playback)Toggle playback (unless disableClickToPause).Toggle fullscreen.
Right (seek forward)Dismiss controls if visible, no-op otherwise, touchstart already woke them.Seek forward seekSeconds.
Top / bottom of center, mobile onlyDismiss controls if visible, no-op otherwise, touchstart already woke them.Volume up / down.

Each seek zone shows a floating circular indicator (chevron icon plus accumulated seconds, e.g. “-30s” after three rapid taps) that lazily mounts on first use and collapses back to zero after roughly a second of no further taps in that direction.

Rules & restrictions

  • Single-tap “toggle controls” reads a snapshot of visibility captured at pointerdown in the capture phase, before DesktopUiPlugin’s own bubble-phase wake handler can mutate the DOM. Without this, a tap from a hidden state would show controls on touchstart and then immediately hide them again when the deferred single-tap handler read the just-added .active class, a show-then-hide flicker that makes the tap look like it did nothing.
  • Mobile detection is a one-shot capability check at plugin startup (ontouchstart presence or maxTouchPoints > 0), not a live pointer-type check, a touch-capable laptop used with a mouse still gets the mobile volume zones.
  • Emits player.emit('activity', { active }) to coordinate with DesktopUiPlugin’s auto-hide timer, this plugin has no visible chrome of its own to hide.

How to extend it

There’s no subclass hook for zone geometry, the grid positions are internal. A different zone layout (a 5-zone grid, a corner-only seek gesture) is a new plugin built against the same player methods (rewind, forward, togglePlayback, toggleFullscreen, volumeUp, volumeDown) rather than a subclass:

TypeScript
import nmplayer from '@nomercy-entertainment/nomercy-video-player';
import { TouchZonesPlugin } from '@nomercy-entertainment/nomercy-video-player/plugins/touch-zones';

const player = nmplayer('player');

player.addPlugin(TouchZonesPlugin, {
seekSeconds: 15,
doubleTapThreshold: 250,
});

Next steps