Bounds lookup
Live annotations pinned above a beat, a lasso selector across a phrase, a live-comment marker that follows the notation through re-layouts โ any UI that has to line up with the rendered score reads from the same lookup. After every render, api.boundsLookup exposes a hierarchical index of the rendered geometry โ staff systems, master bars, bars, beats, notes โ with pixel-accurate rectangles at every level. Use it to hit-test a mouse position, place an overlay on a beat, or draw a custom marker on top of the notation.
The hierarchyโ
boundsLookup.staffSystems is the root. Each level below narrows the region:
staffSystemsโ the rows of staves flowing down the page.bars(1)โ a master bar across every track's staves.bars(2)โ a single track's slice of that master bar.beatsโ the beats inside that bar.notesโ the individual note heads or tab numbers. Only populated whencore.includeNoteBoundsistrue.
Every level exposes two rectangles: visualBounds (the inked area) and realBounds (the inked area plus surrounding whitespace up to neighboring elements). Note bounds additionally carry noteHeadBounds.
Look up a positionโ
getBeatAtPos(x, y) returns the beat under a screen coordinate. getNoteAtPos(beat, x, y) narrows it to the note head or tab number when per-note bounds are enabled. findBeat(beat) goes the other direction โ give it a Beat, get its rectangle back.
Draw an overlayโ
Wait for postRenderFinished, read boundsLookup, find the target beat, and place an absolutely positioned element on top of the render container.
import * as alphaTab from '@coderline/alphatab';
const container = getAlphaTabContainer();
const api = new alphaTab.AlphaTabApi(container, {
core: { file: '/scores/song.gp' },
});
api.postRenderFinished.on(() => {
const lookup = api.boundsLookup;
if (!lookup) {
return;
}
const firstBeat = api.score.tracks[0].staves[0].bars[0].voices[0].beats[0];
const bounds = lookup.findBeat(firstBeat);
if (!bounds) {
return;
}
const marker = document.createElement('div');
marker.style.position = 'absolute';
marker.style.left = `${bounds.visualBounds.x}px`;
marker.style.top = `${bounds.visualBounds.y}px`;
marker.style.width = `${bounds.visualBounds.w}px`;
marker.style.height = `${bounds.visualBounds.h}px`;
marker.style.background = 'rgba(66, 109, 157, 0.25)';
marker.style.pointerEvents = 'none';
container.appendChild(marker);
});
getAlphaTabContainer() is a placeholder for the platform-specific step of obtaining the render target. Every other line runs unchanged on all three runtimes.
Where to look nextโ
- Beat visibility and note bounds โ opt into per-note precision and check whether a beat is on-screen.
- Reacting to beat and note clicks โ the same lookup powers the built-in click events.
boundsLookupandpostRenderFinishedin the API reference.BoundsLookup,BeatBounds,MasterBarBounds, andBoundsin the types reference.