Skip to content
Sponsored by

MagicPlayer

MagicPlayer is a collection of components made to build a flexible, streaming ready media player for video as well as audio playback.

Poster
<template>
  <div class="aspect-[16/9] w-full">
    <magic-player-provider
      id="magic-player-default-demo"
      :options="{
        src: 'https://stream.mux.com/3wVFr42nN3VqIVv01ugl00oSJTzKlhsZ01ep2yKz5vqeZ8.m3u8',
        srcType: 'hls',
      }"
    >
      <magic-player-video />
      <magic-player-poster>
        <magic-player-provider
          id="magic-player-default-demo-poster"
          :options="{
            src: 'https://stream.mux.com/kj7uNjRztuyNotBkAI55oUeVKSSN1C4ONrIYuYcRKxo/highest.mp4',
            autoplay: true,
            loop: true,
          }"
        >
          <magic-player-video />
          <magic-player-poster>
            <img
              src="https://image.mux.com/kj7uNjRztuyNotBkAI55oUeVKSSN1C4ONrIYuYcRKxo/thumbnail.png?time=0"
              alt="Poster"
            />
          </magic-player-poster>
        </magic-player-provider>
      </magic-player-poster>
      <magic-player-overlay />
      <magic-player-video-controls>
        <template #popover>
          <magic-player-mux-popover />
        </template>
      </magic-player-video-controls>
    </magic-player-provider>
  </div>
</template>

<style>
@import '@maas/vue-equipment/plugins/MagicPlayer/css/magic-player-video-controls.css';
</style>

Overview

Anatomy

vue
<template>
  <magic-player-provider id="your-player-id" src="your-src.m3u8">
    <magic-player-video />
    <magic-player-poster>
      <!-- your content -->
    </magic-player-poster>
    <magic-player-overlay />
    <magic-player-video-controls>
      <template #seek-popover>
        <magic-player-mux-popover />
      </template>
    </magic-player-video-controls>
  </magic-player-provider>
</template>

<script>
const { playerApi } = useMagicPlayer('your-player-id')
</script>

<style>
@import '@maas/vue-equipment/MagicPlayer/css/magic-player-video-controls.css';
</style>

Overview

Vue

If you are using Vue, import and add MagicPlayerPlugin to your app.

js
import { createApp } from 'vue'
import { MagicPlayerPlugin } from '@maas/vue-equipment/plugins/MagicPlayer'

const app = createApp({})

app.use(MagicPlayerPlugin)

Nuxt

The player is available as a Nuxt module. In your Nuxt config file add @maas/vue-equipment/nuxt to your modules and add MagicPlayer to the plugins in your configuration.

js
export default defineNuxtConfig({
  modules: ['@maas/vue-equipment/nuxt'],
  vueEquipment: {
    plugins: ['MagicPlayer'],
  },
})

Composable

In order to interact with the player from anywhere within your app, we provide a useMagicPlayer composable. Import it directly when needed.

js
import { useMagicPlayer } from '@maas/vue-equipment/plugins/MagicPlayer'

const { playerApi } = useMagicPlayer('your-player-id')

function handleClick() {
  playerApi.play()
}

TIP

If you have installed the component as a Nuxt module, the composable will be auto-imported and is automatically available in your Nuxt app.

Peer Dependencies

If you haven’t installed the required peer dependencies automatically, you’ll need to install the following packages manually.

Installation

sh
pnpm install @nuxt/kit @vueuse/core defu hls.js
sh
npm install @nuxt/kit @vueuse/core defu hls.js
sh
yarn add @nuxt/kit @vueuse/core defu hls.js
sh
bun install @nuxt/kit @vueuse/core defu hls.js

API Reference

MagicPlayerProvider

The MagicPlayerProvider wraps the menu and configures all child components according to the provided options.

Props

PropTypeRequired
id
MaybeRef<string>true
options
MagicPlayerOptionsfalse

Options

To customize the player override the necessary options. Any custom options will be merged with the default options.

OptionTypeDefault
src
string
mode
PlayerMode
video
srcType
string
native
preload
string
metadata
autoplaybooleanfalse
playback
string[]
['viewport'] | ['viewport', 'window']
loop
booleanfalse
debug
booleanfalse
transition.videoControls
stringmagic-player-video-controls
transition.overlay
stringmagic-player-overlay
transition.icons
stringmagic-player-icons

CSS Variables

VariableDefault
--magic-player-provider-heightauto
--magic-player-provider-aspect-ratio16 / 9
--magic-player-provider-background#000

MagicPlayerOverlay

CSS Variables

VariableDefault
--magic-player-overlay-backgroundrgba(0, 0, 0, 0.3)
--magic-player-overlay-colorrgba(255, 255, 255, 1)
--magic-player-overlay-button-size2rem

MagicPlayerVideoControls

Props

PropTypeRequired
id
MaybeRef<string>false
standalone
booleanfalse
transition.overlay
stringfalse
transition.icons
stringfalse

CSS

Due to their complexity and opinionated nature, we have externalized the styles for this component. Make sure to import them if needed. If not style the component manually.

css
@import '@maas/vue-equipment/MagicPlayer/css/magic-player-video-controls.css';

MagicPlayerMuxPopover

Props

PropTypeRequired
playbackId
stringfalse

CSS Variables

VariableDefault
--magic-player-popover-border-radius0.25rem

MagicPlayerAudioControls

Props

PropTypeRequired
id
MaybeRef<string>false

CSS

Due to their complexity and opinionated nature, we have externalized the styles for this component. Make sure to import them if needed. If not style the component manually.

css
@import '@maas/vue-equipment/MagicPlayer/css/magic-player-audio-controls.css';

MagicPlayerDisplayTime

This component is used internally by both the video and audio controls components. You are most likely not going to need it directly, unless you want to implement your own custom controls.

Props

PropTypeRequired
type
string
false

Errors

SourceError CodeMessage
MagicPlayerMuxPopovermissing_instance_idMagicPlayerMuxPopover must be nested inside MagicPlayerProvider or a playbackId must be provided
MagicPlayerMuxPopovermissing_optionsMagicPlayerMuxPopover must be nested inside MagicPlayerVideoControls
MagicPlayerMuxPopoverfetch_timeline_errorFailed to fetch timeline preview
MagicPlayerMuxPopoverinitialize_timeline_errorCan not initialize timeline preview
MagicPlayerAudioControlsmissing_instance_idMagicPlayerAudioControls must be nested inside MagicPlayerProvider
MagicPlayerVideomissing_instance_idMagicPlayerVideo must be used within a MagicPlayerProvider
MagicPlayerVideomissing_optionsMagicPlayerVideo must be used within a MagicPlayerProvider
MagicPlayerPostermissing_instance_idMagicPlayerPoster must be nested inside MagicPlayerProvider
MagicPlayerOverlaymissing_instance_idMagicPlayerOverlay must be nested inside MagicPlayerProvider
MagicPlayerTimelinemissing_instance_idMagicPlayerTimeline must be nested inside MagicPlayerProvider
MagicPlayerDisplayTimemissing_instance_idMagicPlayerDisplayTime must be nested inside MagicPlayerProvider
MagicPlayerVideoControlsmissing_instance_idMagicPlayerVideoControls must be nested inside MagicPlayerProvider
usePlayerMediaApiplay_promise_rejectedPlay promise was rejected
usePlayerMediaApiplay_promise_abortedThe play() request was aborted
usePlayerMediaApiplay_promise_not_allowedAutoplay was prevented, user interaction required
usePlayerMediaApiplay_promise_not_supportedMedia format not supported
usePlayerMediaApimedia_element_errorMedia element error
usePlayerMediaApimedia_element_abortedMedia loading was aborted by the user
usePlayerMediaApimedia_element_networkA network error occurred while loading the media
usePlayerMediaApimedia_element_decodeAn error occurred while decoding the media
usePlayerMediaApimedia_element_src_not_supportedThe media source is not supported
usePlayerRuntimehls_network_errorHLS network error
usePlayerRuntimehls_media_recovery_failedHLS media recovery failed
usePlayerRuntimehls_media_errorHLS media error
usePlayerRuntimehls_fatal_errorHLS fatal error
usePlayerRuntimeplayer_initialization_failedPlayer initialization failed

Examples

Audio Player

Loveless
0:00
0:00
<template>
  <div class="w-full">
    <magic-player-provider
      id="magic-player-audio-demo"
      :options="{ mode: 'audio', src: '/demo/magic-player/loveless.mp3' }"
      class="bg-surface-high rounded-surface-sm flex flex-col gap-2 p-2"
    >
      <span
        class="bg-surface-base rounded-surface-sm-inset type-surface-callout-md block w-full p-4"
      >
        Loveless
      </span>
      <magic-player-audio-controls class="px-4" />
      <magic-player-audio />
    </magic-player-provider>
  </div>
</template>

<style>
@import '@maas/vue-equipment/plugins/MagicPlayer/css/magic-player-audio-controls.css';
</style>

Autoplay

<template>
  <div class="aspect-[16/9] w-full">
    <magic-player-provider
      id="magic-player-autoplay-demo"
      :options="{
        autoplay: true,
        loop: true,
        src: 'https://stream.mux.com/kj7uNjRztuyNotBkAI55oUeVKSSN1C4ONrIYuYcRKxo/highest.mp4',
      }"
    >
      <magic-player-video />
    </magic-player-provider>
  </div>
</template>

Autoplay with Controls

<template>
  <div class="aspect-[16/9] w-full">
    <magic-player-provider
      id="magic-player-autoplay-controls-demo"
      :options="{
        src: 'https://stream.mux.com/3wVFr42nN3VqIVv01ugl00oSJTzKlhsZ01ep2yKz5vqeZ8.m3u8',
        srcType: 'hls',
        autoplay: true,
      }"
    >
      <magic-player-video />
      <magic-player-overlay />
      <magic-player-video-controls>
        <template #popover>
          <magic-player-mux-popover />
        </template>
      </magic-player-video-controls>
    </magic-player-provider>
  </div>
</template>

<style>
@import '@maas/vue-equipment/plugins/MagicPlayer/css/magic-player-video-controls.css';
</style>

Controls without Overlay

<template>
  <div class="aspect-[16/9] w-full">
    <magic-player-provider
      id="magic-player-omit-overlay-demo"
      :options="{
        src: 'https://stream.mux.com/3wVFr42nN3VqIVv01ugl00oSJTzKlhsZ01ep2yKz5vqeZ8.m3u8',
        srcType: 'hls',
      }"
    >
      <magic-player-video />

      <magic-player-video-controls>
        <template #popover>
          <magic-player-mux-popover />
        </template>
      </magic-player-video-controls>
    </magic-player-provider>
  </div>
</template>

<style>
@import '@maas/vue-equipment/plugins/MagicPlayer/css/magic-player-video-controls.css';
</style>

Standalone Controls

Poster
<template>
  <div class="flex w-full flex-col">
    <magic-player-provider
      id="magic-player-standalone-controls-demo"
      :options="{
        src: 'https://stream.mux.com/3wVFr42nN3VqIVv01ugl00oSJTzKlhsZ01ep2yKz5vqeZ8.m3u8',
        srcType: 'hls',
      }"
    >
      <magic-player-video />
      <magic-player-poster>
        <img
          src="https://image.mux.com/3wVFr42nN3VqIVv01ugl00oSJTzKlhsZ01ep2yKz5vqeZ8/thumbnail.jpg?time=4"
          alt="Poster"
        />
      </magic-player-poster>
      <magic-player-overlay />
    </magic-player-provider>
    <div class="relative flex w-full items-center pt-4">
      <magic-player-video-controls
        id="magic-player-standalone-controls-demo"
        class="bg-black"
        standalone
      >
        <template #timeline-before>
          <magic-player-display-time type="current" />
        </template>
        <template #timeline-after>
          <magic-player-display-time type="duration" />
        </template>
      </magic-player-video-controls>
    </div>
  </div>
</template>

<style>
@import '@maas/vue-equipment/plugins/MagicPlayer/css/magic-player-video-controls.css';
</style>

Native Controls

<template>
  <div class="aspect-[16/9] w-full">
    <magic-player-provider
      id="magic-player-native-controls-demo"
      :options="{
        src: 'https://stream.mux.com/3wVFr42nN3VqIVv01ugl00oSJTzKlhsZ01ep2yKz5vqeZ8.m3u8',
        srcType: 'hls',
      }"
    >
      <magic-player-video controls />
    </magic-player-provider>
  </div>
</template>

Poster Image

Poster
<template>
  <div class="aspect-[9/16] w-full">
    <magic-player-provider
      id="magic-player-image-poster-demo"
      :style="{ '--magic-player-provider-aspect-ratio': '9/16' }"
      :options="{
        src: 'https://stream.mux.com/PniSBG6rbyou2x5jExB9EwYQAgBXGyqxXA023GC6JeXQ/highest.mp4',
      }"
    >
      <magic-player-video />
      <magic-player-poster>
        <img
          src="https://image.mux.com/PniSBG6rbyou2x5jExB9EwYQAgBXGyqxXA023GC6JeXQ/thumbnail.jpg?time=8"
          alt="Poster"
        />
      </magic-player-poster>
      <magic-player-overlay />
    </magic-player-provider>
  </div>
</template>

Composable

<template>
  <div class="flex w-full flex-col items-center gap-4">
    <div class="aspect-[16/9] w-full">
      <magic-player-provider
        id="magic-player-composable-demo"
        :options="{
          autoplay: true,
          loop: true,
          src: 'https://stream.mux.com/kj7uNjRztuyNotBkAI55oUeVKSSN1C4ONrIYuYcRKxo/highest.mp4',
        }"
      >
        <magic-player-video />
      </magic-player-provider>
    </div>
    <div class="flex gap-4">
      <m-button @click="playerApi.videoApi.togglePlay()">
        Toggle Play
      </m-button>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { useMagicPlayer } from '@maas/vue-equipment/plugins/MagicPlayer'
const playerApi = useMagicPlayer('magic-player-composable-demo')
</script>