MediaFoxFramework-Agnostic Media Player
A TypeScript-first Media Player library powered by Mediabunny. Full control over rendering and UI, zero opinions.
A TypeScript-first Media Player library powered by Mediabunny. Full control over rendering and UI, zero opinions.

bun add @mediafox/core mediabunnyMediaFox gives you full control over video playback without imposing any UI constraints. Handle multi-track media files with video, audio, and subtitle tracks. Perfect canvas-based rendering with hardware acceleration.
Learn more →import { MediaFox } from '@mediafox/core';
const player = new MediaFox({
renderTarget: document.querySelector('#canvas'),
volume: 0.8,
autoplay: false
});
// Load media from various sources
await player.load(videoFile);
await player.load('https://example.com/video.mp4');
await player.load(blob);
// Control playback
await player.play();
player.pause();
await player.seek(30);
// Multi-track support
const videoTracks = player.getVideoTracks();
const audioTracks = player.getAudioTracks();
await player.selectAudioTrack(audioTracks[1].id);// React to all state changes
player.subscribe(state => {
console.log('Current time:', state.currentTime);
console.log('Duration:', state.duration);
console.log('Playing:', state.playing);
console.log('Volume:', state.volume);
console.log('Selected tracks:', {
video: state.selectedVideoTrack,
audio: state.selectedAudioTrack,
subtitle: state.selectedSubtitleTrack
});
});
// Listen to specific events
player.on('loadedmetadata', (info) => {
console.log(`Format: ${info.format}`);
console.log(`Duration: ${info.duration}s`);
});
player.on('timeupdate', ({ currentTime }) => {
updateProgressBar(currentTime);
});Subscribe to state changes and handle events with a clean, type-safe API. Get real-time updates on playback progress, track changes, and media loading states.
Docs →Works seamlessly with React, Vue, Angular, Svelte, or vanilla JavaScript. No UI opinions means you can build exactly the interface you want with complete control over every pixel.
Framework guides →// Framework integration examples
// React
function VideoPlayer({ src }) {
const playerRef = useRef();
const [state, setState] = useState(null);
useEffect(() => {
const player = new MediaFox({ renderTarget: canvasRef.current });
const { unsubscribe } = player.subscribe(setState);
playerRef.current = player;
return () => { unsubscribe(); player.dispose(); };
}, []);
return <canvas ref={canvasRef} onClick={() => player.play()} />;
}
// Vue
const player = new MediaFox({ renderTarget: canvasRef.value });
const state = ref(null);
player.subscribe(newState => state.value = newState);
// Vanilla
const player = new MediaFox({ renderTarget: canvas });
player.subscribe(state => updateUI(state));import {
MediaFox,
PlayerStateData,
VideoTrackInfo,
AudioTrackInfo
} from '@mediafox/core';
const player = new MediaFox({
renderTarget: canvas,
volume: 0.8
});
// Full IntelliSense support
player.subscribe((state: PlayerStateData) => {
updateUI({
currentTime: state.currentTime, // number
duration: state.duration, // number
playing: state.playing, // boolean
tracks: state.videoTracks // VideoTrackInfo[]
});
});Built from scratch in TypeScript with complete type definitions. Tree-shakable architecture means you only include what you use. Zero dependencies beyond Mediabunny.
Type reference →Automatic selection of the best rendering backend for optimal performance. Seamlessly switches between WebGPU, WebGL, and Canvas2D based on availability and performance needs with automatic fallback.
Performance guide →// Auto-detect best renderer
const player = new MediaFox({
renderTarget: canvas
// Automatically uses WebGPU, WebGL, or Canvas2D
});
// Check available renderers
const supported = MediaFox.getSupportedRenderers();
console.log('Available:', supported);
// Output: ['webgpu', 'webgl', 'canvas2d']
// Manually switch renderers
await player.switchRenderer('webgl');
// Monitor renderer changes
player.on('rendererchange', (type) => {
console.log(`Using ${type} renderer`);
});
player.on('rendererfallback', ({ from, to }) => {
console.warn(`Fallback: ${from} → ${to}`);
});// Load multiple media files
await player.loadPlaylist([
{ mediaSource: 'video1.mp4', title: 'Episode 1' },
{ mediaSource: 'video2.mp4', title: 'Episode 2' },
{ mediaSource: 'audio.mp3', title: 'Podcast' }
]);
// Set playback mode
player.playlistMode = 'sequential'; // Auto-advance
// Other modes: 'manual', 'repeat', 'repeat-one', null
// Navigation
player.next(); // Next item
player.prev(); // Previous item
player.jumpTo(2); // Jump to index 2
// Position preservation
console.log(player.currentItem?.savedPosition);
// Returns to saved position when switching back
// Listen to playlist events
player.on('playlistitemchange', ({ item, index }) => {
console.log(`Now playing: ${item.title}`);
});Play multiple media files in sequence with automatic or manual navigation. Preserves playback position for each item, lazy-loads sources, and prefetches the next item for smooth transitions.
Playlist guide →