Skip to content

Migrating from Other Players

Switching to the NoMercy Player SDK from another library. Each section maps that library’s concepts to the player core’s equivalents and highlights the most common translation mistakes.

From hls.js (direct usage)

hls.js is a low-level streaming library, it manages the <video> element and HLS parsing but provides no player abstraction. The NoMercy video player wraps hls.js behind IVideoBackend.

Concept mapping

hls.jsNoMercy video player
new Hls()nmplayer('id')
hls.loadSource(url)player.queue([{ url }])
hls.attachMedia(video)(implicit — nmplayer('id') mounts to that element id)
hls.on(Hls.Events.MANIFEST_PARSED, ...)player.on('levels', ...)
hls.on(Hls.Events.LEVEL_SWITCHED, ...)player.on('level-switched', ...)
hls.currentLevel = nplayer.quality(n)
hls.autoLevelEnabled = falseplayer.quality('auto') to re-enable ABR
hls.levelsplayer.qualityLevels()

Key differences

  • You do not instantiate hls.js directly. If you need custom hls.js config, use backendFactory, see HLS.
  • Auth header injection is handled by the player core’s auth pipeline, remove any hls.js xhrSetup or fetchSetup you had.
TypeScript
// hls.js (direct):
hls = new Hls({
xhrSetup: (xhr) => xhr.setRequestHeader('Authorization', `Bearer ${token}`),
});

// NoMercy player:
player.setup({
auth: { bearerToken: () => getToken() },
});

From video.js

video.js is a full-featured player with its own plugin system and UI.

Concept mapping

video.jsNoMercy video player
videojs('player-id', options)nmplayer('player-id').setup(options)
player.src({ src, type })player.queue([{ url, ... }])
player.play() / player.pause()Same
player.currentTime() / player.currentTime(t)player.time() / player.time(t)
player.volume() / player.volume(v)Same
player.on(event, handler)Same
player.off(event, handler)Same
player.plugin('name', plugin)player.addPlugin(PluginClass, options)
player.videoWidth() / player.videoHeight()player.backend().videoWidth() / player.backend().videoHeight()
player.dispose()Same

UI components

video.js renders UI inside the player container using its own component system. The NoMercy equivalent is DesktopUiPlugin. To customize the UI, subclass DesktopUiPlugin, do not add elements directly to the container outside the plugin.

Text tracks

TypeScript
// video.js:
// @ts-expect-error — addRemoteTextTrack is a video.js API, not available in the NoMercy player
player.addRemoteTextTrack({ kind: 'subtitles', src, srclang: 'en' });

// NoMercy player: declare subtitles per playlist item with url (not file):
player.setup({
playlist: [
{
subtitles: [{ id: 'en', language: 'en', label: 'English', url: src, kind: 'subtitles' }],
},
],
});
player.addPlugin(SubtitleOverlayPlugin);

From Plyr

Plyr is a minimal UI wrapper over the native <video> element. It has no HLS support built in, so users typically pair it with hls.js manually.

Concept mapping

PlyrNoMercy video player
new Plyr('#player', options)nmplayer('player').setup(options) (the id is the element id)
player.play() / player.pause()Same
player.currentTime (property)player.time() (method)
player.volume (property, 0–1)player.volume() (method, 0–100)
player.muted (property)player.mute() / player.unmute() / player.toggleMute()
player.fullscreen.enter()player.fullscreen(true)
player.fullscreen.exit()player.fullscreen(false)
player.on('play', cb)player.on('play', cb)
player.destroy()player.dispose()

HLS migration

If you were wiring hls.js into Plyr manually, remove that code. The NoMercy player handles HLS internally:

TypeScript
// Plyr + hls.js (old):
const hls = new Hls();
hls.loadSource(src);
hls.attachMedia(video);
const player = new Plyr(video);

// NoMercy player (new):
const player = nmplayer('main')
.addPlugin(DesktopUiPlugin)
.setup({
playlist: [{ id: '1', url: src }],
});

From Tone.js (audio / music apps)

Tone.js is a Web Audio framework for musical synthesis and scheduling. It is not a media player, so it does not handle queue management, HLS streaming, or playlist state. The migration target depends on what you used Tone.js for.

Tone.js as an audio effect chain

If you used Tone.js for an EQ or reverb chain applied to a <audio> element, use AudioGraphPlugin and EqualizerPlugin instead:

TypeScript
// Tone.js (EQ):
const eq = new Tone.EQ3({ low: 3, mid: 0, high: -2 });
const player = new Tone.Player(url).connect(eq);

// NoMercy music player (EQ):
player
.addPlugin(AudioGraphPlugin)
.addPlugin(EqualizerPlugin, {
preset: 'Rock',
});

const eq = player.getPlugin(EqualizerPlugin);
eq?.band(70, 4.875); // boost 70 Hz
eq?.preset('Rock'); // or apply by name

Tone.js for scheduling

If you used Tone.Transport to schedule playback events, replace it with the player core’s event system:

TypeScript
// Tone.js:
Tone.Transport.scheduleRepeat(() => {
/* tick */
}, '8n');

// NoMercy player, use plugin interval:
this.interval(() => {
/* tick */
}, intervalMs);

Key differences

  • Tone.js is synthesis-first. The NoMercy music player is a media player, it streams pre-encoded audio and does not synthesize.
  • Tone.js Tone.Player does not handle HLS. The NoMercy player does.
  • Tone.js Tone.Context must be started by a user gesture. The NoMercy player handles the AudioContext unlock internally.