MagicPlayer
MagicPlayer is a collection of components made to build a flexible, streaming ready media player for video as well as audio playback.
<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>Anatomy
<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/plugins/MagicPlayer/css/magic-player-video-controls.css';
</style>
Installation
CLI
Add @maas/vue-equipment to your dependencies.
pnpm add @maas/vue-equipment
Vue
If you are using Vue, import and add MagicPlayerPlugin to your app.
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.
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.
import { useMagicPlayer } from '@maas/vue-equipment/plugins/MagicPlayer'
const { playerApi } = useMagicPlayer('your-player-id')
function handleClick() {
playerApi.play()
}
Peer Dependencies
MagicPlayer relies on the following optional peer dependencies in addition to the core peer dependencies. Package managers don’t install optional peer dependencies automatically, so add them to your project.
Installation
pnpm add hls.js
API Reference
MagicPlayerProvider
The MagicPlayerProvider wraps the menu and configures all child components according to the provided options.
Props
Options
To customize the player, override the necessary options. Any custom options will be merged with the default options.
CSS Variables
MagicPlayerOverlay
CSS Variables
MagicPlayerVideoControls
Props
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.
@import '@maas/vue-equipment/plugins/MagicPlayer/css/magic-player-video-controls.css';
MagicPlayerMuxPopover
Props
CSS Variables
MagicPlayerAudioControls
Props
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.
@import '@maas/vue-equipment/plugins/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
Playlist
Pass an array of URLs to options.src to enable playlist mode. The player advances automatically when each track ends. Use the useMagicPlayer composable to navigate between tracks manually.
<template>
<magic-player-provider
id="my-player"
:options="{
src: [
'https://example.com/track-1.mp4',
'https://example.com/track-2.mp4',
'https://example.com/track-3.mp4',
],
}"
>
<magic-player-video />
<magic-player-overlay />
<magic-player-video-controls />
</magic-player-provider>
</template>
<script lang="ts" setup>
import { useMagicPlayer } from '@maas/vue-equipment/plugins/MagicPlayer'
const { playlistIndex, playlistCount, next, prev, goTo } =
useMagicPlayer('my-player')
</script>
Playlist API
Errors
Examples
Audio Player
<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-base rounded-surface-sm flex flex-col gap-2 p-2"
>
<span
class="bg-surface-high 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

<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"
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

<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>Playlist
<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-playlist-demo"
:options="{
src: [
'https://stream.mux.com/kj7uNjRztuyNotBkAI55oUeVKSSN1C4ONrIYuYcRKxo/highest.mp4',
'https://stream.mux.com/kj7uNjRztuyNotBkAI55oUeVKSSN1C4ONrIYuYcRKxo/highest.mp4',
'https://stream.mux.com/kj7uNjRztuyNotBkAI55oUeVKSSN1C4ONrIYuYcRKxo/highest.mp4',
],
}"
>
<magic-player-video />
<magic-player-overlay />
<magic-player-video-controls />
</magic-player-provider>
</div>
<div class="flex items-center gap-4">
<m-button :disabled="playlistIndex <= 0" @click="prev()">Prev</m-button>
<span class="tabular-nums">
{{ playlistIndex + 1 }} / {{ playlistCount }}
</span>
<m-button :disabled="playlistIndex >= playlistCount - 1" @click="next()">
Next
</m-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { useMagicPlayer } from '@maas/vue-equipment/plugins/MagicPlayer'
const { playlistIndex, playlistCount, next, prev } = useMagicPlayer(
'magic-player-playlist-demo'
)
</script>
<style>
@import '@maas/vue-equipment/plugins/MagicPlayer/css/magic-player-video-controls.css';
</style>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>