Skip to main content

Worker and worklet initialization

Hosting alphaTab inside an app with a custom bundler means understanding the worker/worklet split: rendering and synthesis run off the main thread in a Web Worker, and the audio output runs in an Audio Worklet inside the page's audio graph. The webpack and Vite plugins wire both for you, and alphaTab detects Turbopack. Anywhere else you tell alphaTab how to construct them via the three Environment statics on this page.

00:00
00:00

This site builds with Rspack and @coderline/alphatab-webpack: the render engine runs in a Web Worker, the synthesizer output in an Audio Worklet, and all three share one alphaTab core chunk. Press play and watch the network panel to see the worker and the worklet start.

The three staticsโ€‹

alphaTab.Environment exposes three initialization entry points. Each script bundle you emit calls exactly one of them at load time.

  • initializeMain(createWebWorker, createAudioWorklet) โ€” runs in the page. It registers two factory callbacks that alphaTab invokes when it needs a Web Worker for rendering / synthesis or an AudioWorklet for low-latency playback. Both callbacks receive the current Settings and return the worker or a Promise from audioWorklet.addModule(...).
  • initializeWorker() โ€” runs inside the worker script. It wires up the renderer and synth message loops. Call it from a dedicated bundle whose only job is to load and run inside a Worker.
  • initializeAudioWorklet() โ€” runs inside the audio worklet. It registers the AudioWorkletProcessor for synth output. Call it from a bundle loaded via audioWorklet.addModule(...).

The default @coderline/alphatab entry (alphaTab.mjs) already dispatches to the right static based on the current global scope. You reach for these APIs when you build your own entry points, for example for a bundler without an alphaTab plugin. Then import @coderline/alphatab/core instead, which exports the same API but calls none of the three statics on its own.

Show it in codeโ€‹

Your main-thread bundle instantiates a worker and hands alphaTab a factory:

import * as alphaTab from '@coderline/alphatab/core';

alphaTab.Environment.initializeMain(
(settings, nameHint) => new Worker(
new URL('./alphaTab.worker.js', import.meta.url),
{ type: 'module', name: nameHint },
),
(context, settings) => context.audioWorklet.addModule(
new URL('./alphaTab.worklet.js', import.meta.url),
),
);

const container = getAlphaTabContainer();
const api = new alphaTab.AlphaTabApi(container, {
core: { file: '/scores/song.gp' },
});

The worker bundle is a one-liner. @coderline/alphatab/worker imports the core and calls initializeWorker:

import '@coderline/alphatab/worker';

The worklet bundle mirrors it with @coderline/alphatab/worklet, which calls initializeAudioWorklet:

import '@coderline/alphatab/worklet';

Both are equivalent to importing @coderline/alphatab/core and calling the static yourself:

import * as alphaTab from '@coderline/alphatab/core';
alphaTab.Environment.initializeWorker();

Emit all three bundles in one build with a shared ES module chunk, so the page, the worker and the worklet load alphaTab's core once. Installation (other bundlers) shows the build for esbuild, Rollup and Parcel.

getAlphaTabContainer() is a placeholder for the platform-specific step of obtaining the render target โ€” a <div> on Web is the only relevant target for this page.

Where to look nextโ€‹