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.
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 anAudioWorkletfor low-latency playback. Both callbacks receive the currentSettingsand return the worker or aPromisefromaudioWorklet.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 aWorker.initializeAudioWorklet()โ runs inside the audio worklet. It registers theAudioWorkletProcessorfor synth output. Call it from a bundle loaded viaaudioWorklet.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โ
- Installation (other bundlers) โ the build setup for these entry points with esbuild, Rollup and Parcel.
Environmentโ every static on the class, includinginitializeMain,initializeWorker, andinitializeAudioWorklet.core.useWorkersโ the setting that toggles worker rendering off entirely when you want a synchronous main-thread pipeline instead.core.scriptFileโ the hosted alphaTab script that the classic<script>setup and Turbopack's Audio Worklet load.- Installation (Vite) and Installation (webpack, Rspack, Rsbuild) โ the shipped plugins that do this wiring for you.