Omakase Player is an open source JavaScript player for building frame accurate video experiences.
Omakase Player is constructed from the following main components:
For versions prior to v1.0.0 please refer to v0.25.4 API documentation
Omakase Player can be loaded as ES6 module inside HTML page. If loaded as ES6 module it requires hls.js loaded before Omakase Player:
<script type="importmap">
{
"imports": {
"hls.js": "https://cdn.jsdelivr.net/npm/hls.js@latest/dist/hls.mjs",
"@omakase-player": "https://cdn.jsdelivr.net/npm/@byomakase/omakase-player@latest/dist/omakase-player.es.min.js"
}
}
</script>
Later on use regular object imports in JavaScript code.
import {OmakasePlayer} from '@omakase-player';
let omakasePlayer = new OmakasePlayer();
Omakase Player can be used as ES module in TypeScript projects as follows.
If used with modern Typescript / Javascript frameworks (such as Angular, React or Vue), it is recommended to simply install Omakase Player as dependency into package.json:
npm install @byomakase/omakase-player
Optionally, you can include default Omakase Player CSS stylesheet or import and use omakase-player.scss SCSS stylesheet.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@byomakase/omakase-player@latest/dist/style.min.css" />
Stylesheet references default player overlay icons, help menu icons and default styles for video safe zones. All of which can be overridden.
Omakase Player requires div as a placeholder for HTML5 player.
<div id="omakase-player"></div>
Initialize the player by providing div id in player configuration. If used as UMD module, Omakase Player objects are available in global omakase namespace:
// Create new OmakasePlayer instance
let omakasePlayer = new omakase.OmakasePlayer({
playerHTMLElementId: 'omakase-player',
});
Once player is initialized we can load main media by providing URL:
omakasePlayer.loadMainMedia('https://my-server.com/myvideo.m3u8').subscribe({
next: (mainMedia) => {
console.log(`Main media loaded. Duration: ${mainMedia.duration}`);
},
});
Player chroming can be configured with the chroming property. This property allows selection of a chroming theme, watermark, thumbnail url or selection function and other theme-specific configuration. Some code examples are shown below:
let omakasePlayer = new OmakasePlayer({
chroming: {
theme: ChromingTheme.Default,
thumbnailUrl: 'https://my-server.com/thumbs.vtt',
watermark: 'DEMO_SAMPLE',
themeConfig: {
controlBarVisibility: ControlBarVisibility.Enabled,
controlBar: [DefaultThemeControl.Play, DefaultThemeControl.Scrubber, DefaultThemeControl.Volume, DefaultThemeControl.Trackselector, DefaultThemeControl.Fullscreen],
trackSelectorAutoClose: false,
},
},
});
let omakasePlayer = new OmakasePlayer({
chroming: {
theme: ChromingTheme.Default,
themeConfig: {
controlBarVisibility: ControlBarVisibility.Disabled,
floatingControls: [DefaultThemeFloatingControl.PlaybackControls],
},
},
});
let omakasePlayer = new OmakasePlayer({
chroming: {
theme: PlayerChromingTheme.Chromeless,
},
});
/* Custom template js */
let omakasePlayer = new OmakasePlayer({
chroming: {
theme: ChromingTheme.Custom,
themeConfig: {
htmlTemplateId: 'custom-template',
},
},
});
/** Custom template HTML
<template id="custom-template">
<media-control-bar>
<omakase-marker-bars></omakase-marker-bars>
<omakase-time-range></omakase-time-range>
</media-control-bar>
</template>
*/
More information about Player Chroming customization and specific theme configurations is available in Player Chroming manual.
Complete list of Player API methods is available in API Reference Docs
Playback control is achieved through Player API.
// plays video
omakasePlayer.player.play();
// plays video and notifies user on successful play action
omakasePlayer.player.play().subscribe(() => {
console.log(`Play started`);
});
// pauses video
omakasePlayer.player.pause();
// seeks to timestamp
omakasePlayer.player.seekTo(123.45).subscribe({
next: (result) => {
if (result) {
console.log(`Seek to timestamp success`);
}
},
});
// seeks to frame
omakasePlayer.video.seekTo(123, omakase.MediaTemporalFormat.FRAME_COUNT).subscribe({
next: (result) => {
if (result) {
console.log(`Seek to frame success`);
}
},
});
Before or after loading media, we can observe various events. All events are emitted through the joint onEvent$ observable
// Subscribe to Observable
omakasePlayer.player.onEvent$.subscribe({
next: (event) => {
if (event.type === omakase.PlayerEventType.PLAYER_MAIN_MEDIA_LOADED) {
let mainMediaState = event.data.mainMediaState;
console.log(`Media loaded. Duration: ${mainMediaState.duration}`);
}
},
});
Video playback events subscription examples:
omakasePlayer.player.onEvent$.pipe(rxjs.filter((event) => event.type === omakase.PlayerEventType.PLAYER_PLAY)).subscribe({
next: (event) => {
console.log(`Media play. Timestamp: ${event.data.currentTime}`);
},
});
omakasePlayer.player.onEvent$.pipe(rxjs.filter((event) => event.type === omakase.PlayerEventType.PLAYER_PAUSE)).subscribe({
next: (event) => {
console.log(`Media pause. Timestamp: ${event.data.currentTime}`);
},
});
omakasePlayer.player.onEvent$.pipe(rxjs.filter((event) => event.type === omakase.PlayerEventType.PLAYER_SEEKED)).subscribe({
next: (event) => {
console.log(`Media seeked. Timestamp: ${event.data.currentTime}`);
},
});
omakasePlayer.player.onEvent$.pipe(rxjs.filter((event) => event.type === omakase.PlayerEventType.PLAYER_PLAYBACK_PROGRESS)).subscribe({
next: (event) => {
console.log(`Media time change. Timestamp: ${event.data.currentTime}`);
},
});
To enable full media detaching in Omakase Player we need to instantiate a detached instance of Omakase Player on same host, and tell our local instance where to find it.
Local player instance configuration on https://my-server.com/omp-player:
// local-omakase-player.js
// Local OmakasePlayer instance configuration on https://my-server.com/omp-player
let omakasePlayer = new omakase.OmakasePlayer({
playerHTMLElementId: 'omakase-player',
detachedPlayerUrlFn: (mainMedia) => 'https://my-server.com/player/omp-player-detached',
});
Detached player instance configuration on https://my-server.com/omp-player-detached:
// detached-omakase-player.js
// Detached OmakasePlayer instance configuration on https://my-server.com/omp-player-detached
let omakasePlayer = new omakase.OmakasePlayerDetached({
playerHTMLElementId: 'omakase-player',
});
We can now load main media, detach it to independent browser window and play it!:
// local-omakase-player.js
omakasePlayer.loadMainMedia('https://my-server.com/myvideo.m3u8').subscribe({
next: (mainMedia) => {
console.log(`Main media loaded`);
omakasePlayer.detachPlayer().subscribe(() => {
console.log(`Main media detached`);
omakasePlayer.player.play();
});
},
});
Due to security and usability policies, most modern browsers require a user interaction before allowing certain actions, such as video autoplay or fullscreen initiation. It could be that one-time-only user interaction (such as clicking on play button in detached player) is needed before video playback or switching to fullscreen playback after video detaching.
We can get the playback engines used for the main media. If HLS media is loaded, then hls.js instance can be fetched.
// Get hls.js instance and hook onto hls.js events
let hlsPlaybackEngine = omakasePlayer.player.getPlaybackEngine(MainMediaType.HLS);
hlsPlaybackEngine.hls.on('hlsManifestParsed', (event, data) => {
console.log(`HLS manifest parsed`, data);
});
// adds safe zone 10% from all player edges
omakasePlayer.chroming.addSafeZone({
topRightBottomLeftPercent: [10, 10, 10, 10],
});
// toggles fullscreen
omakasePlayer.player.toggleFullscreen();
Complete list of Audio API methods is available in API Reference Docs.
There are two types of audio: Main audio and Sidecar audio. Main audio refers to audio source attached to main media track. Main audio tracks are embedded audio tracks loaded with main media and only single Main audio track can be active (playing) at same time. Sidecar audio tracks are loaded manually and they are independent of main media load and Main audio. Sidecar audio tracks playback is synced with main media (Main audio) playback and there can be multiple Sidecar audio tracks active (playing) at same time.
Few common usages of Audio API:
// retrieves all available audio tracks
let audioTracks = omakasePlayer.player.audio.getTracks();
// detect audio tracks switching
omakasePlayer.player.audio.onEvent$.pipe(filter((event) => event.type === omakase.PlayerAudioEventType.PLAYER_AUDIO_TRACK_SWITCHED)).subscribe({
next: (event) => {
console.log(`Audio switched`, event);
},
});
// sets another audio track as active
omakasePlayer.player.audio.switchTrack(audioTracks[1].id, true);
Enables routing between audio inputs and outputs.
// creates Main audio router configured for routing between 2 inputs and 4 outputs
omakasePlayer.player.audio
.getHandler(PlayerAudioType.MAIN)
.createAudioRouter(2, 4)
.subscribe(() => {
// connects 1st input with 2nd output
// disconnects 2nd input and 2nd output
omakasePlayer.player.audio.getHandler(PlayerAudioType.MAIN).router.updateConnections([
{
path: {input: 0, output: 1},
connected: true,
},
{
path: {input: 1, output: 1},
connected: false,
},
]);
});
Enables audio peak processing for analyzing audio and creating audio peaks visualizations such as VU meter.
// creates Main audio peak sample processor
omakasePlayer.player.audio.getHandler(PlayerAudioType.MAIN).createMainAudioPeakProcessor();
// listens for peak processor messages
omakasePlayer.audio.getHandler(PlayerAudioType.MAIN).onPeakProcessorEvent$.subscribe({
next: (event) => {
// peak processor message can be input to audio peak visualization component
console.log(`Peak processor message`, event);
},
});
// listens for SidecarAudioCreateEvent events
omakasePlayer.player.audio.onEvent$.pipe(rxjs.filter((event) => event.type === PlayerAudioEventType.PLAYER_AUDIO_TRACK_LOADED)).subscribe({
next: (event) => {
console.log(`Just created Sidecar audio track: `, event.data.playerAudioTrack);
},
});
// listens for SidecarAudioRemoveEvent events
omakasePlayer.player.audio.onEvent$.pipe(rxjs.filter((event) => event.type === PlayerAudioEventType.PLAYER_AUDIO_TRACK_UNLOADED)).subscribe({
next: (event) => {
console.log(`Just removed Sidecar audio track: `, event.data.playerAudioTrack);
},
});
// creates new Sidecar audio track
omakasePlayer.player
.loadSidecarTrack(sidecarAudioUrl, {
trackType: omakase.TrackType.AUDIO,
})
.subscribe({
next: (sidecarAudioTrackState) => {
console.log(`Created new Sidecar audio track with id:`, sidecarAudioTrackState.id);
},
});
// activates Sidecar audio tracks
omakasePlayer.player.audio.switchTrack('sidecarAudioTrackId1', true);
// deactivates Sidecar audio tracks
omakasePlayer.player.audio.switchTrack('sidecarAudioTrackId1', false);
// removes Sidecar audio tracks
omakasePlayer.player.removeSidecarTrack('sidecarAudioTrackId1');
// listens for SidecarAudioChangeEvent events, event is triggered ie. when Sidecar audio router changes
// once the router is created you can subscribe to its event through `audioHandler.router.onEvent$`
omakasePlayer.player.audio
.getHandler(PlayerAudioType.SIDECAR, 'sidecarAudioTrackId1')
.onEvent$.pipe(rxjs.filter((event) => event.type === AudioHandlerEventType.AUDIO_HANDLER_CHANGE))
.subscribe({
next: (event) => {
console.log(`Just changed Sidecar audio track: `, event.changedSidecarAudioState);
},
});
// creates Sidecar audio router configured for routing between 2 inputs and 4 outputs
omakasePlayer.player.audio.getHandler(PlayerAudioType.SIDECAR, 'sidecarAudioTrackId1').createAudioRouter(2, 4);
// connects 1st output with 2nd output
omakasePlayer.player.audio.getHandler(PlayerAudioType.SIDECAR, 'sidecarAudioTrackId1').router.updateConnections([
{
path: {input: 0, output: 1},
connected: true,
},
]);
// disconnects 2nd input and 2nd output
omakasePlayer.player.audio.getHandler(PlayerAudioType.SIDECAR, 'sidecarAudioTrackId1').router.updateConnections([
{
path: {input: 1, output: 1},
connected: false,
},
]);
Enables audio peak processing for analyzing audio and creating audio peaks visualizations such as VU meter.
// creates Sidecar audio peak sample processor
omakasePlayer.player.audio.getHandler(PlayerAudioType.SIDECAR, 'sidecarAudioTrackId1').createPeakProcessor();
// listens for peak processor messages on all Sidecar audios and filters them for single Sidecar audio track
omakasePlayer.player.audio.getHandler(PlayerAudioType.SIDECAR, 'sidecarAudioTrackId1').onPeakProcessorEvent$.subscribe({
next: (event) => {
// peak processor message can be input to audio peak visualization component
console.log(`Peak processor message`, event);
},
});
Initializes the audio router visualization component. It will create the main audio router or sidecar audio routers if they are not already created.
Parameters:
routerVisualizationHTMLElementId: optional, id of the HTML element inside which to render the router visualization component (defaults to 'omakase-audio-router')size: optional, component size ('small', 'medium' or 'large', defaults to 'medium')outputNumber: optional, number of outputs to display (defaults to the number of detected outputs from the AudioContext)outputLabels: optional, labels to display for outputs (if not provided, default labels will be shown)visualizationTracks: optional, array of router visualization tracks
name: optional, label to show for the main trackmaxInputNumber: required, number of inputs for main audio routerinputNumber: optional, number of inputs to visualize (defaults to maxInputNumber)inputLabels: optional, labels to display for main track inputs (if not provided, default labels will be shown)trackId: optional, id of the sidecar audio track, if not provided the visualization track will be treated as main trackUsage example:
<div id="omakase-audio-router"></div>
// creates a router visualization component with one main track and one sidecar track
let routerVisualizationComponent = new RouterVisualization(
{
routerVisualizationHTMLElementId: 'omakase-audio-router',
size: 'medium',
outputNumber: 6,
outputLabels: ['L', 'R', 'C', 'LFE', 'Ls', 'Rs'],
visualizationTracks: [
{
name: '5.1 English',
inputNumber: 6,
maxInputNumber: 6,
inputLabels: ['L', 'R', 'C', 'LFE', 'Ls', 'Rs'],
},
{
trackId: '<sidecar_track_id>',
name: 'Stereo',
inputNumber: 2,
maxInputNumber: 6,
inputLabels: ['L', 'R', 'C', 'LFE', 'Ls', 'Rs'],
},
],
},
omakasePlayer
);
Omakase Player supports applying audio effects on main, sidecar, and output audio handlers. Effects are added using AudioEffectDef interface that Omakase Player instantiates into corresponding specific AudioEffect and includes it into the handlers audio chain. To use effects not provided by Omakase Player, you need to register the factory functions that will convert effect definitions to concrete effect objects. User never creates specific effects, only their definitions.
Omakase Player supports three predefined effect chain slots: source, router and destination in different audio chain locations. These slots are independent and can host audio effect chains simultaneously. Each audio handler has independent slots.
The audio chains samples for main media and one audio sidecar are shown in the image below:

Adding effects to router slot can be further granulated with routing path that can select specific connections and apply effects on specified connections only.
Usage example:
let mainEchoEffectDef = AudioEffectGraphDef.create(
GainEffect.createDef('gain1', 1).outputTo({effectId: 'delay1'}),
DelayEffect.createDef('delay1', 0.2).outputTo('feedbackGain', 'gain2'),
GainEffect.createDef('feedbackGain', 0.5).outputTo('delay1'),
GainEffect.createDef('gain2', 1)
);
let sidecarBalanceEffectDef = AudioEffectGraphDef.create(GainEffect.createDef('gain', 1));
// create echo effect graph on the main audio track at source slot
omakasePlayer.player.audio.getHandler(PlayerAudioType.MAIN).effects.setEffectGraph(mainEchoEffectDef, {slot: 'source'});
// create sidecar audio router
omakasePlayer.player.audio
.getHandler(PlayerAudioType.SIDECAR, 'sidecarAudioTrackId1')
.createAudioRouter()
.subscribe(() => {
// creates echo effect graph on the sidecar audio track at router slot on all routing paths
omakasePlayer.player.audio.getHandler(PlayerAudioType.SIDECAR, 'sidecarAudioTrackId1').effects.setEffectGraph(sidecarBalanceEffectDef, {slot: 'router'});
});
Omakase Player supports changing effects parameters once the effects are created.
Usage example:
// changes gain parameter of gain effect with id "gain" on routing paths terminating on output 0 inside the router slot
omakasePlayer.player.audio
.getHandler(PlayerAudioType.SIDECAR, 'sidecarAudioTrackId1')
.effects.setEffectsParams(new AudioEffectGainParam(0.8), {slot: 'router', routingPath: {output: 0}}, {id: 'gain'});
// changes gain parameter of gain effect with id "gain" on routing paths terminating on output 1 inside the router slot
omakasePlayer.player.audio
.getHandler(PlayerAudioType.SIDECAR, 'sidecarAudioTrackId1')
.effects.setEffectsParams(new AudioEffectGainParam(1.2), {slot: 'router', routingPath: {output: 1}}, {id: 'gain'});
While Omakase Player supports custom audio effects as long as they conform to AudioEffect interface, Omakase Player provides some audio effects to make more common use cases (for example audio balancing) easier.
GainEffect implements gain effect. Supported parameters are the same as web audio's GainNode.
To make usage easier Omakase Player provides AudioEffectGainParam wrapper around the gain parameter.
To create effect definition use GainEffect.createDef static method.
Code sample:
let graphDef = AudioEffectGraphDef.create(GainEffect.createDef('gain', 0.5));
omakasePlayer.player.audio.getHandler(PlayerAudioType.MAIN).effects.setEffectGraph(graphDef, {slot: 'source'});
DelayEffect implements delay effect. Supported parameters are the same as web audio's DelayNode.
To make usage easier Omakase Player provides AudioEffectDelayTimeParam wrapper around the delayTime parameter.
To create effect definition use DelayEffect.createDef static method.
Code sample:
let graphDef = AudioEffectsGraphDef.create(DelayEffect.createDef('delay', 0.2));
omakasePlayer.player.audio.getHandler(PlayerAudioType.MAIN).effects.setEffectGraph(graphDef, {slot: 'destination'});
Omakase Player elements (including media chrome elements) can be styled with CSS/SCSS. The CSS structure is shown below.
The player's dimensions can be controlled with three CSS custom properties set on the player's container element or any ancestor:
| CSS Variable | Description |
|---|---|
--omakase-player-width |
Sets the width of the player. Accepts any valid CSS length value (e.g. 800px, 100%). |
--omakase-player-height |
Sets the height of the player. Accepts any valid CSS length value (e.g. 450px, 50vh). |
--omakase-player-aspect-ratio |
Sets the aspect ratio of the player (e.g. 16 / 9, 4 / 3). When not specified, the aspect ratio is derived automatically from the loaded media. |
#omakase-player {
--omakase-player-width: 100%;
--omakase-player-aspect-ratio: 16 / 9;
}
Note: These CSS variables have no effect when the Stamp chroming theme is active. In the Stamp theme, player takes the width/height of the container.
Complete list of Text API methods is available in API Reference Docs. Omakase Player automatically identifies all available text tracks from main media and makes them available through Text API.
omakasePlayer.player.onEvent$.pipe(rxjs.filter((event) => event.type === PlayerEventType.PLAYER_MAIN_MEDIA_LOADED)).subscribe({
next: (event) => {
// retrieves all subtitles VTT tracks
let textTracks = omakasePlayer.player.text.getTracks();
// shows first available VTT track
omakasePlayer.player.text.switchTrack(textTracks[0].id, true);
},
});
Subtitles can be imported from external VTT file:
// import subtitles from VTT file
omakasePlayer.player
.loadSidecarTrack('https://example.com/myTextTrack.vtt', {
trackType: TrackType.TEXT_TRACK,
args: {
id: '0',
label: 'English (US)',
default: true,
srcLang: 'EN'
},
})
.subscribe({
next: (textTrackState) => {
console.log(`Subtitles successfully created`);
},
});
A marker track is a type of timed items track — a track that holds a collection of time-anchored data points called timed items. Each timed item has a temporal position (a moment or a time span) and an arbitrary data payload. The marker track specialises this concept for timeline annotations: each timed item is a marker that can represent either a single point in time (a moment marker) or a duration (a spanning marker).
Marker data is typically loaded from a WebVTT file, where each cue becomes one marker. When a cue covers an instant it becomes a MOMENT_MARKER; when it covers a range it becomes a SPANNING_MARKER.
MarkerTrack accepts an optional configuration object with the following fields:
| Argument | Type | Description |
|---|---|---|
id |
string |
Optional pre-assigned UUID. A new UUID is generated automatically when omitted. |
source |
UrlSource |
URL source that points to a VTT file containing marker data. Takes precedence over url. |
label |
string |
Human-readable label for this track. |
timedItemsLocked |
boolean |
When true, the track is locked — markers cannot be added, deleted, or updated after the track loads. Defaults to false. |
timedItemHooks |
TimedItemHooks |
Lifecycle hooks called during marker creation. See Timed item hooks below. |
Loading markers from a VTT file via source:
import { MarkerTrack, UrlSource, TrackType } from '@byomakase/omakase-player';
const track = omakasePlayer.track.add(
new MarkerTrack({
source: UrlSource.of('https://example.com/data/markers.vtt'),
})
);
omakasePlayer.track.load(TrackSource.fromTrack(track), {
trackType: TrackType.MARKER_TRACK,
});
Every timed items track has a locked flag (timedItemsLocked) that controls whether its collection of timed items is mutable after the initial load.
addTimedItems, deleteTimedItems, and updateTimedItem. This is useful when you want to programmatically build or edit the marker collection at runtime.addTimedItems, deleteTimedItems, or updateTimedItem throws an error. Use this when the marker data comes from a canonical source and must not be altered.// Locked — markers cannot be mutated after load
const track = omakasePlayer.track.add(
new MarkerTrack({
source: UrlSource.of('https://example.com/data/markers.vtt'),
timedItemsLocked: true,
})
);
// Unlocked — add markers programmatically
const editableTrack = omakasePlayer.track.add(new MarkerTrack());
editableTrack.addTimedItems(
new DefaultMarker({
temporal: { type: TimedItemTemporalType.MOMENT, time: '42' },
label: 'Scene cut',
})
);
The locked state can also be toggled at runtime:
track.areTimedItemsLocked = false; // unlock
track.areTimedItemsLocked = true; // lock again
timedItemHooks lets you run callbacks at specific points in a marker's lifecycle. Both hooks receive the timed item instance as their argument.
| Hook | When it fires |
|---|---|
beforeCreate |
Immediately before the marker is inserted into the track's internal collection. Use this to apply styles or perform setup that must happen before the item is visible. |
afterCreate |
Immediately after the marker has been inserted and the track has emitted its update events. Use this for post-creation side effects. |
const track = omakasePlayer.track.add(
new MarkerTrack({
source: UrlSource.of('https://example.com/data/markers.vtt'),
timedItemsLocked: true,
timedItemHooks: {
beforeCreate: (timedItem) => {
// Assign a random colour to each marker before it is rendered
omakasePlayer.ui.updateStyleRule({
id: timedItem.id,
style: { color: ColorUtil.randomHexColor() },
});
},
afterCreate: (timedItem) => {
console.log('Marker created:', timedItem.id);
},
},
})
);
The following methods are available on any TimedItemsTrack, including MarkerTrack.
timedItems — Returns the full array of timed items in insertion order.
const all = track.timedItems;
timedItemsSorted — Returns the timed items sorted ascending by their start time. Items without a start time (e.g. SPAN_END temporals) appear first.
const sorted = track.timedItemsSorted;
areTimedItemsLocked — true when the track is locked and its items cannot be mutated. Can be read and set.
if (!track.areTimedItemsLocked) {
track.addTimedItems(newMarker);
}
getTimedItem(id) — Returns the timed item with the given UUID, or undefined if not found.
const marker = track.getTimedItem('some-uuid');
addTimedItems(timedItems) — Adds one or more timed items to the track. Throws if the track is locked. Fires beforeCreate and afterCreate hooks for each item.
track.addTimedItems(marker);
track.addTimedItems([markerA, markerB]);
deleteTimedItems(id) — Removes one or more timed items by their UUID. Throws if the track is locked.
track.deleteTimedItems('some-uuid');
track.deleteTimedItems(['uuid-1', 'uuid-2']);
updateTimedItem(id, attrs) — Updates mutable attributes (temporal, data, label for markers) of the item with the given UUID. Throws if the track is locked.
track.updateTimedItem('some-uuid', {
label: 'Updated label',
temporal: { type: TimedItemTemporalType.MOMENT, time: '60' },
});
findTimedItemsAtTime(time) — Returns all timed items whose temporal range covers the given time (in seconds).
MOMENT — matches when time === temporal.timeSPAN — matches when temporal.start <= time <= temporal.endSPAN_START — matches when temporal.start <= timeSPAN_END — matches when temporal.end >= timeconst active = track.findTimedItemsAtTime(30);
findFirstTimedItemAtTime(time) — Like findTimedItemsAtTime but returns only the first match (by sorted order), or undefined if none.
const first = track.findFirstTimedItemAtTime(30);
findTimedItemsInRange(start, end) — Returns all timed items that fall fully within the [start, end] range. Items that merely overlap the range boundaries are excluded (except SPAN_START items, which are included when their start falls in range).
const inRange = track.findTimedItemsInRange(10, 60);
findNearestTimedItem(time) — Returns the timed item whose start time is closest to time. When two items are equidistant, the one before time wins. Returns undefined if the track is empty.
const nearest = track.findNearestTimedItem(45);
The timeline is an interactive canvas-based interface. It renders a playhead, a scrubber, optional thumbnails, and any number of timeline lanes that visualise track data.
Call createTimeline on the player instance. It returns an Observable<TimelineApi> that emits once the timeline canvas has been mounted.
import { OmakasePlayer } from '@byomakase/omakase-player';
omakasePlayer
.createTimeline({
style: {
stageMinWidth: 700,
backgroundFill: '#E4E5E5',
headerBackgroundFill: '#EDEFEE',
footerBackgroundFill: '#EDEFEE',
playheadVisible: true,
playheadFill: '#000000',
playheadLineWidth: 2,
playheadPlayProgressFill: '#008cbc',
playheadPlayProgressOpacity: 0.5,
playheadBufferedFill: '#a2a2a2',
playheadBufferedOpacity: 1,
scrubberSouthLineOpacity: 0.2,
},
})
.subscribe((timeline) => {
// timeline is a TimelineApi instance
});
The created timeline is also accessible at omakasePlayer.timeline after creation.
// Add a single lane
timeline.addTimelineLane(lane);
// Add a lane at a specific index
timeline.addTimelineLaneAtIndex(lane, 0);
// Add multiple lanes at once
timeline.addTimelineLanes([laneA, laneB, laneC]);
// Remove by id
timeline.removeTimelineLane(lane.id);
timeline.removeTimelineLanes([laneA.id, laneB.id]);
timeline.removeAllTimelineLanes();
// Retrieve lanes
const all = timeline.getTimelineLanes();
const single = timeline.getTimelineLane<MarkerTrackLane>('some-id');
const scrubber = timeline.getScrubberLane();
Every lane type extends TimelineLaneConfig and TimelineLaneStyle.
TimelineLaneConfig
| Field | Type | Description |
|---|---|---|
description |
string |
Text shown in the left description pane. When omitted, the associated track's label is used automatically. |
minimized |
boolean |
Start the lane in its collapsed (zero-height) state. Defaults to false. |
layoutEasingDuration |
number |
Easing duration in milliseconds for minimize/maximize animations. |
Every lane exposes minimize(), maximize(), and toggleMinimizeMaximize(). All three accept an optional TimelineLaneMinimizeMaximizeArgs object:
| Field | Type | Description |
|---|---|---|
easing |
boolean |
Animate the height change. Defaults to false. |
duration |
number |
Animation duration in milliseconds. Defaults to the timeline easing duration. |
complete |
Observable<void> |
Set by the method. Completes when the operation finishes. Subscribe after calling the method. |
const args: TimelineLaneMinimizeMaximizeArgs = { easing: true };
lane.minimize(args);
args.complete!.subscribe({ complete: () => console.log('minimize done') });
The scrubber lane is created automatically when a timeline is instantiated and cannot be removed. It renders timecode ticks along the time axis and drives the hover scrubber. Retrieve the instance with timeline.getScrubberLane().
A MarkerTrackLane is a multi-track lane — it can hold one or more MarkerTrack instances simultaneously. Each marker appears as a symbol (moment markers) or a shaded region (spanning markers). After adding the lane to the timeline, call addTrack to bind a track. Each track can carry its own per-track style.
import { MarkerTrackLane } from '@byomakase/omakase-player';
const markerLane = new MarkerTrackLane({
description: 'Scene cuts',
});
timeline.addTimelineLane(markerLane);
markerLane.addTrack(markerTrack);
Adding multiple tracks to one lane:
// Two tracks rendered in the same lane with different colors
markerLane.addTrack(dialogTrack, {
style: { markerColor: '#2196f3' },
});
markerLane.addTrack(blackSegmentsTrack, {
style: {
markerColor: '#4caf50',
markerRenderType: 'spanning-over-all-lanes',
},
});
Per-track config fields (passed as second argument to addTrack)
| Field | Type | Description |
|---|---|---|
trackOrderIndex |
number |
Zero-based index at which to insert the track. Appended at the end when omitted. |
style.markerColor |
string |
Colour applied to all markers from this track. |
style.markerRenderType |
string |
Render mode: 'default', 'spanning', or 'spanning-over-all-lanes'. |
Events — emitted via markerLane.onEvent$
| Event type | Payload | Description |
|---|---|---|
TIMELINE_MARKER_TRACK_LANE_ITEM_CLICK |
{ item: MarkerState } |
A marker was clicked. |
TIMELINE_MARKER_TRACK_LANE_ITEM_MOUSE_ENTER |
{ item: MarkerState } |
The pointer entered a marker. |
TIMELINE_MARKER_TRACK_LANE_ITEM_MOUSE_LEAVE |
{ item: MarkerState } |
The pointer left a marker. |
import { MarkerTrackLaneEventType } from '@byomakase/omakase-player';
markerLane.onEvent$.subscribe((event) => {
if (event.type === MarkerTrackLaneEventType.TIMELINE_MARKER_TRACK_LANE_ITEM_CLICK) {
console.log('Clicked marker:', event.data.item.id);
}
});
Marker view style — individual marker appearance can be customised at runtime:
// Apply a style to specific markers by their IDs
markerLane.setMarkerViewStyle(
{ markerColor: '#ff0000', markerRenderType: 'default' },
[markerId1, markerId2]
);
// Apply a style to all markers in the lane
markerLane.setMarkerViewStyle({ markerColor: '#00ff00' });
A ThumbnailTrackLane renders a ThumbnailTrack as a filmstrip of images across the timeline. After adding the lane, call setTrack to bind it to a loaded ThumbnailTrack. To also enable the timeline-wide thumbnail hover preview, call timeline.setThumbnailTrack(track).
import { ThumbnailTrackLane } from '@byomakase/omakase-player';
const thumbnailLane = new ThumbnailTrackLane();
timeline.setThumbnailTrack(thumbnailTrack); // enables hover preview on Scrubber lane
thumbnailLane.setTrack(thumbnailTrack);
timeline.addTimelineLane(thumbnailLane);
Events — emitted via thumbnailLane.onEvent$
| Event type | Payload | Description |
|---|---|---|
TIMELINE_THUMBNAIL_TRACK_LANE_THUMBNAIL_CLICK |
{ thumbnailTrackImg: ThumbnailTrackImgState } |
A thumbnail was clicked. |
TIMELINE_THUMBNAIL_TRACK_LANE_THUMBNAIL_MOUSE_ENTER |
{ thumbnailTrackImg: ThumbnailTrackImgState } |
The pointer entered a thumbnail. |
TIMELINE_THUMBNAIL_TRACK_LANE_THUMBNAIL_MOUSE_LEAVE |
{ thumbnailTrackImg: ThumbnailTrackImgState } |
The pointer left a thumbnail. |
import { ThumbnailTrackLaneEventType, TimedItemTemporalUtil } from '@byomakase/omakase-player';
thumbnailLane.onEvent$.subscribe((event) => {
if (event.type === ThumbnailTrackLaneEventType.TIMELINE_THUMBNAIL_TRACK_LANE_THUMBNAIL_CLICK) {
const startTime = TimedItemTemporalUtil.extractStartTime(
event.data.thumbnailTrackImg.thumbnail.temporal
);
omakasePlayer.player.seekTo(Number(startTime));
}
});
A TextTrackLane renders a TextTrack (subtitles or captions) as coloured blocks whose width represents each cue's duration. Adjacent cues separated by less than half a pixel are merged into a single block. After adding the lane, call setTrack to bind it to a loaded TextTrack.
import { TextTrackLane } from '@byomakase/omakase-player';
const textLane = new TextTrackLane({
description: 'Subtitles',
});
textLane.setTrack(textTrack);
timeline.addTimelineLane(textLane);
Events — emitted via textLane.onEvent$
| Event type | Payload | Description |
|---|---|---|
TIMELINE_TEXT_TRACK_LANE_ITEM_CLICK |
{ cues: TextCue[] } |
A cue block was clicked. The array contains all cues merged into that block. |
TIMELINE_TEXT_TRACK_LANE_ITEM_MOUSE_ENTER |
{ cues: TextCue[] } |
The pointer entered a cue block. |
TIMELINE_TEXT_TRACK_LANE_ITEM_MOUSE_LEAVE |
{ cues: TextCue[] } |
The pointer left a cue block. |
import { TextTrackLaneEventType } from '@byomakase/omakase-player';
textLane.onEvent$.subscribe((event) => {
if (event.type === TextTrackLaneEventType.TIMELINE_TEXT_TRACK_LANE_ITEM_CLICK) {
console.log('Cue text:', event.data.cues.map((c) => c.text));
}
});
A LabelLane renders a static text string in the timeline. It has no associated track and is useful for grouping or annotating other lanes visually. The text field is required.
import { LabelLane } from '@byomakase/omakase-player';
const labelLane = new LabelLane({
text: 'Audio tracks',
style: {
height: 24,
textFill: '#444444',
textFontSize: 12,
},
});
timeline.addTimelineLane(labelLane);
A BarChartLane is a multi-track lane that renders time-series observation data as vertical bars. Each track is added via addTrack with its own scale, interpolation settings, and per-measurement visual style.
import { BarChartLane } from '@byomakase/omakase-player';
const lane = new BarChartLane({
description: 'Loudness',
style: { height: 80 },
});
timeline.addTimelineLane(lane);
lane.addTrack(observationTrack, {
scale: { min: -1, max: 1 },
scaleBaseline: 0,
interpolationStrategy: 'avg',
interpolationWidth: 5,
style: {
measurements: [
{
measurement: 'max',
fill: '#2196f3',
cornerRadius: [2, 2, 0, 0],
paddingX: 1,
},
{
measurement: 'min',
fill: '#2196f3',
cornerRadius: [0, 0, 2, 2],
paddingX: 1,
},
],
},
});
Per-track config fields (passed as second argument to addTrack)
| Field | Type | Description |
|---|---|---|
scale |
{ min, max } |
Value domain. Auto-derived from data when omitted. |
scaleBaseline |
number |
Value that maps to the bar baseline (zero-crossing). Defaults to 0. |
interpolationStrategy |
'avg' | 'max' | 'min' |
Aggregation strategy when multiple samples fall in one bucket. |
interpolationWidth |
number |
Width in pixels of one interpolation bucket. |
style.measurements |
Partial<BarChartLaneTrackMeasurementStyle>[] |
Per-measurement visual overrides. |
Per-measurement style fields (BarChartLaneTrackMeasurementStyle)
| Field | Type | Description |
|---|---|---|
measurement |
string |
Measurement to match (e.g. 'max', 'min', 'value'). |
barType |
'default' | 'og' |
'default' draws rectangles; 'og' draws a column of stacked circles. |
fill |
string |
Solid fill color. |
fillLinearGradientColorStops |
(number | string)[] |
Gradient color stops (Konva format). Used when fill is not set. |
opacity |
number |
Bar opacity (0–1). |
cornerRadius |
number | [number, number, number, number] |
Corner radius for 'default' bars. |
paddingX |
number | [number, number] |
Horizontal padding inside the bar's width. Single value = symmetric; tuple = [left, right]. |
OG bar type example:
lane.addTrack(observationTrack, {
scale: { min: -1, max: 1 },
scaleBaseline: 0,
style: {
measurements: [
{
measurement: 'value',
barType: 'og',
fill: '#40ff00',
paddingX: 1,
},
],
},
});
A LineChartLane is a multi-track lane that renders time-series observation data as a polyline connecting interpolated data points. Each track is added via addTrack with its own scale, interpolation settings, and per-measurement visual style. Area fills above and below the line are optional.
import { LineChartLane } from '@byomakase/omakase-player';
const lane = new LineChartLane({
description: 'Waveform',
style: { height: 100 },
});
timeline.addTimelineLane(lane);
lane.addTrack(observationTrack, {
scale: { min: -1, max: 1 },
scaleBaseline: 0,
interpolationStrategy: 'avg',
interpolationWidth: 5,
style: {
measurements: [
{
measurement: 'value',
lineStroke: '#4caf50',
lineStrokeWidth: 2,
pointFill: '#4caf50',
pointRadius: 3,
},
],
},
});
Per-track config fields — same as BarChartLane (scale, scaleBaseline, interpolationStrategy, interpolationWidth, style.measurements).
Per-measurement style fields (LineChartLaneTrackMeasurementStyle)
| Field | Type | Description |
|---|---|---|
measurement |
string |
Measurement to match. |
lineStroke |
string |
Polyline color. |
lineStrokeWidth |
number |
Polyline width in pixels. |
lineDash |
number[] |
Dash pattern (Konva format). |
lineOpacity |
number |
Polyline opacity (0–1). |
pointRadius |
number |
Data-point circle radius in pixels. |
pointFill |
string |
Data-point fill color. |
pointOpacity |
number |
Data-point opacity (0–1). |
fillBelow |
string |
Solid fill for the area below the line. |
fillBelowLinearGradientColorStops |
(number | string)[] |
Gradient color stops for the area below the line (top→bottom). |
fillAbove |
string |
Solid fill for the area above the line. |
fillAboveLinearGradientColorStops |
(number | string)[] |
Gradient color stops for the area above the line (bottom→top). |
Area fill example:
lane.addTrack(observationTrack, {
scale: { min: -1, max: 1 },
scaleBaseline: 0,
style: {
measurements: [
{
measurement: 'value',
lineStroke: '#085b9c',
fillBelowLinearGradientColorStops: [0, '#ffffff', 0.5, '#00a696', 1, '#005ba6'],
fillAboveLinearGradientColorStops: [0, '#005ba6', 1, '#000000'],
},
],
},
});
Multiple tracks in one lane:
lane.addTrack(leftChannelTrack, {
style: { measurements: [{ measurement: 'value', lineStroke: '#2196f3', lineStrokeWidth: 1.5 }] },
});
lane.addTrack(rightChannelTrack, {
style: { measurements: [{ measurement: 'value', lineStroke: '#f67944', lineStrokeWidth: 1.5 }] },
});
A ScrollbarLane renders a horizontal scrollbar that lets users pan and zoom the timeline. It has no associated track. The scrollbar handle reflects the current scroll position and its width reflects the current zoom level — dragging it scrolls the timeline, and pinching or scrolling on it zooms in/out.
import { ScrollbarLane } from '@byomakase/omakase-player';
const scrollbarLane = new ScrollbarLane({
style: {
height: 40,
scrollbarHeight: 14,
scrollbarWidth: '100%',
scrollbarBackgroundFill: '#000000',
scrollbarBackgroundFillOpacity: 0.3,
scrollbarHandleBarFill: '#01a6f0',
scrollbarHandleBarOpacity: 1,
scrollbarHandleOpacity: 1,
scrollbarJustify: 'center',
},
});
timeline.addTimelineLane(scrollbarLane);
ScrollbarLaneStyle
| Field | Type | Description |
|---|---|---|
scrollbarWidth |
number | string |
Width of the scrollbar track. Accepts a pixel value or '100%' to fill the lane. Defaults to '100%'. |
scrollbarHeight |
number | undefined |
Height of the scrollbar handle bar in pixels. When omitted, fills the full lane height. |
scrollbarBackgroundFill |
Color |
Fill color of the scrollbar track background. |
scrollbarBackgroundFillOpacity |
number |
Opacity of the track background (0–1). |
scrollbarHandleBarFill |
Color |
Fill color of the draggable handle bar. |
scrollbarHandleBarOpacity |
number |
Opacity of the handle bar (0–1). |
scrollbarHandleOpacity |
number |
Opacity of the entire scrollbar handle (0–1). |
scrollbarJustify |
'start' | 'center' | 'end' |
Vertical alignment of the scrollbar within the lane. Defaults to 'center'. |
Marker list is initialized by defining a div placeholder and creating a MarkerList instance with optional configuration.
The marker list web component will be added into an html element with id defined in markerListHTMLElementId. If this parameter is not provided, it will default to omakase-marker-list. Following code will instantiate an empty marker list.
<div id="marker-list"></div>
import {MarkerList} from '@byomakase/omakase-player';
const markerList = new MarkerList({
markerListHTMLElementId: 'marker-list',
}, omakasePlayer);
A marker list can be loaded from a VTT file by providing a URL via the markerTrack property. This action will automatically register marker track in the track repository and load timed items from assigned VTT file.
The loadingHTMLElementId parameter can specify HTML content to render while the file is loading.
<div id="marker-list"></div>
<template id="loading-template">
<!-- content to render while the VTT file is loading -->
</template>
const markerList = new MarkerList({
markerListHTMLElementId: 'marker-list',
loadingHTMLElementId: 'loading-template',
markerTrack: {source: UrlSource.of('https://example.com/data/markers.vtt')},
}, omakasePlayer);
Marker list can be linked to one or more MarkerTrack instances. If linked in this way, the markers from the track(s) will appear on the marker list and stay in sync regardless of whether markers are added to the marker list or to the underlying tracks.
import {MarkerList, TrackSource} from '@byomakase/omakase-player';
const markerList = new MarkerList({
markerListHTMLElementId: 'marker-list',
markerTrack: [
{source: TrackSource.fromTrack(markerTrack1)},
{source: TrackSource.fromTrack(markerTrack2)},
],
}, omakasePlayer);
A thumbnail track can be provided using the thumbnailTrack property. If provided, it will be used to automatically set the thumbnail to the closest VTT cue based on the marker start time.
const markerList = new MarkerList({
markerListHTMLElementId: 'marker-list',
thumbnailTrack: {source: UrlSource.of('https://example.com/data/thumbnails.vtt')},
}, omakasePlayer);
The following methods are available on the marker list. Usage examples are shown below.
addMarkerupdateMarkerremoveMarkerremoveAllMarkersimport {DefaultMarker, TimedItemTemporalType} from '@byomakase/omakase-player';
// create a marker instance
const marker = new DefaultMarker({
label: 'Marker',
temporal: {type: TimedItemTemporalType.SPAN, start: '100', end: '200'},
});
// add marker (track argument required when more than one track is linked)
markerList.addMarker(marker);
// update marker
markerList.updateMarker(marker.id, {temporal: {type: TimedItemTemporalType.SPAN, start: '100', end: '300'}});
// remove marker
markerList.removeMarker(marker.id);
// remove all markers
markerList.removeAllMarkers();
Marker list HTML and style can be customised by passing a css file url and template element ids.
A template for the marker list row can include slots to render data or trigger actions. The following slots are predefined:
color (from marker style)thumbnail (from thumbnailTrack, if provided)name (marker label property)track (label of the linked marker track, if applicable)start (start time from marker temporal)end (end time from marker temporal)duration (difference between end and start)remove (triggers marker removal)Beside predefined slots, dynamic slots can be used to display custom data or trigger custom actions. Custom data slots must be prefixed with data- and custom action slots must be prefixed with action-.
The parameter styleUrl can be an array to provide multiple css files.
<template id="row-template">
<div slot="color"></div>
<div slot="name"></div>
<div slot="start"></div>
<div slot="end"></div>
<div class="actions">
<span slot="action-edit"></span>
<span slot="remove"></span>
</div>
</template>
<template id="header-template">
<!-- header content -->
</template>
<template id="empty-template">
<!-- content to render if marker list is empty -->
</template>
const markerList = new MarkerList({
markerListHTMLElementId: 'marker-list',
templateHTMLElementId: 'row-template',
headerHTMLElementId: 'header-template',
emptyHTMLElementId: 'empty-template',
styleUrl: './style.css',
}, omakasePlayer);
All events are emitted via the onEvent$ observable. The following event types are available:
MarkerListEventType.MARKER_LIST_ITEM_CLICK (triggered when the marker row is clicked)MarkerListEventType.MARKER_LIST_ITEM_ACTION (triggered when a custom element provided with an action-<name> slot is clicked)MarkerListEventType.MARKER_LIST_ITEM_DELETE (triggered when a marker is deleted via the remove slot)MarkerListEventType.MARKER_LIST_TRACKS_LOADED (triggered when all tracks supplied to the markerTracks config parameter are loaded)MarkerListEventType.MARKER_LIST_ITEM_MOUSE_ENTERMarkerListEventType.MARKER_LIST_ITEM_MOUSE_LEAVESome usage examples are shown below:
import {MarkerListEventType} from '@byomakase/omakase-player';
markerList.onEvent$.subscribe((event) => {
if (event.type === MarkerListEventType.MARKER_LIST_ITEM_CLICK) {
console.log(event.data.item);
}
if (event.type === MarkerListEventType.MARKER_LIST_ITEM_ACTION) {
console.log(event.data.action, event.data.item);
}
});
Marker list can be destroyed with the destroy() method. This cleans up the marker list resources and removes it from the DOM.
The VuMeter class provides a self-contained audio level visualization component. It connects to an audio source — either automatically from the player's peak processor or manually via setSource — and renders live dB levels as a bar or LED meter.
Pass player and audioType directly. The VU Meter creates and manages the peak processor internally.
<div id="omakase-vu-meter"></div>
import {VuMeter, PlayerAudioType} from '@byomakase/omakase-player';
const vuMeter = new VuMeter({
player: omakasePlayer,
audioType: PlayerAudioType.MAIN,
config: {
htmlElementId: 'omakase-vu-meter',
},
});
setSourceConstruct the VU Meter with only layout config, then wire it to a PeakProcessorAudioLevelSource created from a sidecar audio track.
<div id="omakase-vu-meter"></div>
import {VuMeter, PeakProcessorAudioLevelSource, PlayerAudioType} from '@byomakase/omakase-player';
const vuMeter = new VuMeter({
config: {
htmlElementId: 'omakase-vu-meter',
channels: 2,
},
});
// Create a source from a sidecar audio track
const source = new PeakProcessorAudioLevelSource(omakasePlayer, PlayerAudioType.SIDECAR, 'sidecarTrackId');
vuMeter.setSource(source);
VuMeter is constructed with a VuMeterArgs object.
| Field | Type | Description |
|---|---|---|
player |
OmakasePlayerApi |
Player instance. Required when using audioType or trackId. |
audioType |
PlayerAudioType |
Audio source type for peak-processor-based sources: MAIN or OUTPUT. Not needed when using trackId. |
trackId |
string |
ID of a sidecar audio track or observation track. When provided with player, the source type is resolved automatically from the track type. |
source |
AudioLevelSourceApi |
Pre-built audio level source. Takes precedence over player/audioType/trackId. |
config |
Partial<VuMeterConfig> |
VU Meter configuration. See VuMeterConfig below. |
VuMeterConfig| Field | Type | Default | Description |
|---|---|---|---|
htmlElementId |
string |
'omakase-vu-meter' |
ID of the HTML element where the VU Meter will be rendered. |
htmlElement |
HTMLElement |
— | HTML element to render into. Takes precedence over htmlElementId when both are provided. |
theme |
VuMeterTheme |
DEFAULT |
DEFAULT renders filled bars; LED renders a column of discrete segments. |
orientation |
VuMeterOrientation |
VERTICAL |
VERTICAL stacks bars top-to-bottom; HORIZONTAL renders bars left-to-right. |
channels |
number |
auto-detected | Number of channels to display (Can be 1, 2 or 6). Auto-detected from the source when omitted. |
scale |
VuMeterScale |
DEFAULT |
DEFAULT: As configured with other parameters. NORDIC: fixed 3 dB steps, 12 dB offset. NONE: no scale. |
rangeMinDb |
number |
-54 |
Minimum dB value at the bottom of the scale. |
scaleStepDb |
number |
6 |
Interval in dB between scale tick marks. Ignored when scale is NORDIC. |
scaleOffsetDb |
number |
0 |
Offset applied to all scale label values. Ignored when scale is NORDIC. |
levelHoldDuration |
number |
0 |
Milliseconds the peak-hold indicator stays visible after a peak. 0 disables peak hold. |
labels |
string[] |
['L','R','C','LFE','Ls','Rs'] |
Channel labels displayed beneath each bar. |
style |
Partial<VuMeterStyle> |
See below | Visual style overrides. See VuMeterStyle. |
VuMeterStyle| Field | Type | Default | Description |
|---|---|---|---|
showScaleLabels |
boolean |
true |
Show dB value labels along the scale. |
showScaleMarks |
boolean |
true |
Show tick marks along the scale. |
showChannelLabels |
boolean |
true |
Show channel labels beneath each bar. |
levelColors |
VuMeterColor[] |
See below | Color thresholds for the level bar. Applied in ascending maxValueDb. |
levelBackground |
string |
transparent |
Background color of the level bar or LED segments. |
Default levelColors:
maxValueDb |
color |
holdColor |
|---|---|---|
-20 |
#04E400 |
#04E40088 |
-10 |
#F27100 |
#F2710088 |
0 |
#BB0000 |
#BB000088 |
VuMeterColor| Field | Description | Type |
|---|---|---|
maxValueDb |
Upper bound of the color segment in dB | number |
color |
Level segment color | string |
holdColor |
Hold level segment color | string |
The VU Meter component exposes the following CSS variables for visual customization:
| CSS Variable | Default | Description |
|---|---|---|
--omakase-vu-meter-font-size |
12px |
Font size for channel labels and scale text |
--omakase-vu-meter-padding |
5px |
Padding around the entire VU meter component |
--omakase-vu-meter-background-color |
transparent |
Background color of the entire VU meter component |
--omakase-vu-meter-label-background-color |
transparent |
Background color of the area behind channel labels |
--omakase-vu-meter-label-color |
#333 |
Text color of the channel labels |
--omakase-vu-meter-label-gap |
5px |
Gap between each channel label and its level bar |
--omakase-vu-meter-label-width |
20px |
Width of the channel label area (horizontal orientation only) |
--omakase-vu-meter-label-height |
20px |
Height of the channel label area (vertical orientation only) |
--omakase-vu-meter-bar-size |
16px |
Bar width in vertical orientation; bar height in horizontal orientation |
--omakase-vu-meter-bar-gap |
5px |
Gap between adjacent channel bars |
--omakase-vu-meter-bars-padding |
0px |
Padding around the bar area |
--omakase-vu-meter-scale-color |
#333 |
Color of scale tick marks and label text |
--omakase-vu-meter-scale-background-color |
transparent |
Background color of the scale area |
--omakase-vu-meter-scale-padding |
0px |
Padding inside the scale container |
--omakase-vu-meter-scale-size |
16px |
Width of the tick column in vertical orientation; height of the tick row in horizontal orientation |
--omakase-vu-meter-scale-gap |
4px |
Gap between the scale label column and the scale tick column |
--omakase-vu-meter-scale-margin |
5px |
Margin between the scale and the bar area |
--omakase-vu-meter-scale-thickness |
1px |
Thickness of main scale division tick marks |
--omakase-vu-meter-scale-label-width |
20px |
Width of the scale label column (vertical orientation only) |
--omakase-vu-meter-transition |
0.2s |
Duration of bar fill and clip-path transition animations |
Player build & build watch
npm install ci
npm run dev
npm install ci
npm run prod
Production artifacts that need to be published to NPM are created in /dist folder