Skip to content

Framework Integration

nomercy-video-player is framework-agnostic. The player mounts into a plain <div> and exposes its entire surface through methods and events, so the integration pattern is the same everywhere regardless of which framework renders the surrounding UI.

The lifecycle has three steps:

  1. Render a container element with a stable ID.
  2. Add plugins with addPlugin(PluginClass), then call .setup(config). Plugin registration before setup is the conventional order that ensures plugins run in the initial lifecycle phase.
  3. Call player.dispose() when the component unmounts or the page navigates away.

Install

See Installation for the npm and CDN setup.

Imports

Player types and the factory come from the package root. Plugin classes come from the /plugins subpath:

TypeScript
import nmplayer from '@nomercy-entertainment/nomercy-video-player';
import { DesktopUiPlugin } from '@nomercy-entertainment/nomercy-video-player/plugins';
import type {
NMVideoPlayer,
VideoPlayerConfig,
VideoPlaylistItem,
} from '@nomercy-entertainment/nomercy-video-player';

Shared playlist example

Every framework guide on this site uses the same playlist shape. Here it is in one place so the per-framework pages stay focused on framework-specific wiring:

TypeScript
import type { VideoPlaylistItem } from '@nomercy-entertainment/nomercy-video-player';

const BASE = 'https://raw.githubusercontent.com/NoMercy-Entertainment/nomercy-media/master/Films';

const playlist: VideoPlaylistItem[] = [
{
id: 'sintel',
title: 'Sintel',
url: '/Sintel.(2010)/Sintel.(2010).NoMercy.m3u8',
image: 'https://image.tmdb.org/t/p/w780/q2bVM5z90tCGbmXYtq2J38T5hSX.jpg',
duration: 888,
subtitles: [
{
id: 'sintel-en',
label: 'English',
url: '/Sintel.(2010)/subtitles/Sintel.(2010).NoMercy.eng.full.vtt',
language: 'eng',
kind: 'subtitles',
},
],
},
{
id: 'tears-of-steel',
title: 'Tears of Steel',
url: '/Tears.of.Steel.(2012)/Tears.of.Steel.(2012).NoMercy.m3u8',
image: 'https://image.tmdb.org/t/p/w780/4TTgBp9Q4shlJLZMsuPuViBhpM2.jpg',
duration: 724,
subtitles: [
{
id: 'tos-en',
label: 'English',
url: '/Tears.of.Steel.(2012)/subtitles/Tears.of.Steel.(2012).NoMercy.eng.full.vtt',
language: 'eng',
kind: 'subtitles',
},
],
},
{
id: 'bbb',
title: 'Big Buck Bunny',
url: '/Big.Buck.Bunny.(2008)/Big.Buck.Bunny.(2008).NoMercy.m3u8',
image: 'https://image.tmdb.org/t/p/w780/uVEFQvFMMsg4e6yb03xOfVsDz0o.jpg',
duration: 596,
},
];

The baseUrl option resolves relative url paths on playlist items, so you pass it once in the config rather than embedding it in every item:

TypeScript
const config: VideoPlayerConfig = {
baseUrl: BASE,
playlist,
};

The mount/init/dispose lifecycle

This is the complete pattern in plain TypeScript, without any framework glue:

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

// Step 1: container must already be in the DOM.
const container = document.getElementById('player')!;

// Step 2: create the player, add plugins, set up config.
const player = nmplayer('main')
.addPlugin(DesktopUiPlugin)
.setup({
baseUrl: 'https://raw.githubusercontent.com/NoMercy-Entertainment/nomercy-media/master/Films',
playlist,
});

player.on('ready', () => {
player.item(0, { autoplay: true });
});

// Step 3: clean up when done.
// Call this in your framework's unmount hook.
function cleanup() {
player.dispose();
}

Note: calling setup() before the container element exists in the DOM will throw. Always initialise inside the framework lifecycle hook that guarantees the DOM is ready, such as onMounted, useEffect, onMount, ngAfterViewInit, or DOMContentLoaded.

Where each framework hooks in

FrameworkInit hookCleanup hook
Vue 3onMountedonBeforeUnmount
ReactuseEffect (return cleanup fn)useEffect cleanup / useRef
SvelteonMountonDestroy
AngularngAfterViewInitngOnDestroy
Vanilla JSDOMContentLoadedbeforeunload or manual

Framework guides