FAQ
Can I use this player without the NoMercy media server?
Yes. @nomercy-entertainment/nomercy-music-player is a standalone npm package.
Point it at any reachable audio URL, a CDN, an S3 bucket, a local dev server, anything.
The server integration (auth.bearerToken, HLS stream handling) is opt-in.
What is the difference between IMusicPlayer and NMMusicPlayer?
NMMusicPlayer<T> is the concrete class.
IMusicPlayer<T> is the interface you should use for consumer-held references (props, context, dependency injection).
This prevents consumers from depending on the concrete constructor and keeps the type boundary clean.
// Do this:
const player: IMusicPlayer = nmMPlayer('main').setup(config);
// Not this (unnecessarily depends on the class):
const player: NMMusicPlayer = nmMPlayer('main').setup(config);
How many player instances can I have?
As many as you need.
Each nmMPlayer(id) call with a unique id creates an independent instance.
They share no state and each has its own audio backend, queue, and plugin set.
A typical app has one global instance.
A multi-room app might have one per room.
Does the player work server-side (SSR/Node)?
Not for playback. The player needs browser APIs (HTMLAudioElement, AudioContext, requestAnimationFrame, navigator.mediaSession) to actually play. Construction is SSR-safe — it no-ops the container lookup when document is absent and does not throw on import — but transport won’t work in Node.
In SSR frameworks (Next.js, Nuxt), create and drive the player only in browser-side code.
Why does autoplay block in the browser?
Browsers require a user gesture before allowing audio playback. Common patterns:
- Call
player.play()inside aclickorkeydownevent handler. - On page load, set up the player and queue, but defer
play()until the first interaction.
The ready event fires when setup is complete.
You can queue tracks there, but do not call play() from ready unless you know a user gesture has already occurred.
What formats are supported?
| Format | Notes |
|---|---|
| MP3 | Universal |
| AAC / M4A | Universal |
| FLAC | All modern browsers |
| OGG / Opus | Chrome, Firefox, Edge (not Safari) |
| WAV | Universal |
HLS (.m3u8) | Native on Safari; hls.js handles other browsers |
hls.js is a production dependency of @nomercy-entertainment/nomercy-player-core, which this package depends on, so it arrives transitively.
No extra install required for HLS.
How do I crossfade?
Two ways:
-
Automatic: Use
AutoAdvancePluginwithcrossfade: trueandcrossfadeDuration: 5. The plugin starts the crossfade automatically before each track ends. -
Manual: Call
player.crossfadeTo(track, { duration: 3 })from your own code. A manual crossfade always ramps linearly; thecurveoption shapes only the automatic AutoAdvance transition.
The default backend (audio-element) uses a requestAnimationFrame loop (~50 fps).
For sample-accurate fades, switch to WebAudioBackend first:
await player.backend('webaudio');
await player.crossfadeTo(nextTrack, { duration: 5 });
What is the difference between audio-element and webaudio backends?
audio-element | webaudio | |
|---|---|---|
| Default | Yes | No |
| Crossfade accuracy | ~50 fps (RAF) | Sample-accurate |
| EQ / Spectrum plugins | Via lazy MediaElementSourceNode | Native Web Audio graph |
| iOS autoplay | Easier | Requires user gesture |
| Memory overhead | Lower | Slightly higher |
Switch at any time with await player.backend('webaudio').
Can I switch backends at runtime?
Yes. await player.backend('webaudio') disposes the current backend, creates the new one, and re-wires all events.
Playback pauses during the switch.
Resume with player.play().
How do I persist volume / shuffle / repeat preferences?
Implement a StorageAdapter and pass it in setup:
import { LocalStorageBackend } from '@nomercy-entertainment/nomercy-player-core';
const player = nmMPlayer('main').setup({
playlist: [],
storage: new LocalStorageBackend(), // the default; pass your own IStorage to persist elsewhere
});
A custom storage must implement the full IStorage interface (get, set, remove, getJSON, setJSON) — extend LocalStorageBackend or wrap your own backend.
The core itself does not persist volume, shuffleState, repeatState, or playbackRate — these are held in memory only (the storage config is read by plugins via Plugin.storage, not by the core). Persist them yourself by listening for the relevant events and writing to your storage, or let a plugin do it (e.g. EqualizerPlugin’s persistKey).
How do I add lyrics?
- Add
LyricsPluginto the player. - Set
lyricsUrlon eachMusicPlaylistItem(must be a.lrcor.vttURL). - Listen to
lineEnterfor the active line.
player.on('plugin:lyrics:lineEnter', ({ text }) => {
document.getElementById('lyric-line').textContent = text;
});
See Lyrics for full details.
Can I use a custom lyric format?
Yes. Register a CueParser:
player.registerCueParser({
id: 'my-format',
canParse: (url) => url.endsWith('.txt'),
parse: (text) => {
// Return CueList
},
});
Parser selection is by URL extension. The built-in LRC and VTT parsers are registered by default.
How do I show a spectrum analyzer or equalizer?
Both require AudioGraphPlugin (which routes audio through a Web Audio graph). It works on either backend: on the default audio-element backend it lazily creates a MediaElementAudioSourceNode; WebAudioBackend gives a full native graph.
const player = nmMPlayer('main')
.addPlugin(AudioGraphPlugin)
.addPlugin(EqualizerPlugin)
.setup({ playlist: [] });
EqualizerPlugin and SpectrumPlugin are re-exported from the music player’s /plugins subpath for ergonomic imports:
import {
AudioGraphPlugin,
EqualizerPlugin,
SpectrumPlugin,
} from '@nomercy-entertainment/nomercy-music-player/plugins';
How do I integrate with React?
Use a custom hook with useRef for the player instance and useState for reactive state.
See React Integration for the complete pattern.
How do I integrate with Vue?
Use a composable with ref for reactive state.
See Vue Integration for the complete pattern.
Is TypeScript required?
No, but strongly recommended. All events, methods, and configuration options are typed. Without TypeScript you lose autocomplete and will have to consult the docs for every method signature.
How do I clean up the player?
Call player.dispose().
This stops playback, removes all event listeners, disposes all plugins, frees the audio backend, and removes the instance from the internal registry.
After dispose(), calling nmMPlayer('same-id') creates a fresh instance.
See also
- Troubleshooting: error diagnosis
- Quick Start: minimal working example
- Configuration: all setup options