WaveformPanel

Panel that wraps WaveSurfer to provide audio playback, a canvas-based region lane (showing speaker segments), a minimap, a time ruler, and a zoom system. Communicates back to the workspace via onRegionHover, onRegionSelect, and onRegionActivate callbacks.

Constructor

new WaveformPanel(workspace, callbacks)

Parameters:
NameTypeDescription
workspaceobjectthe Workspace controller instance
callbacksobjectcallback functions for region interactions
Properties
NameTypeAttributesDescription
onRegionHoverfunctioncalled with region index when a region is hovered
onRegionSelectfunctioncalled with region index when a region is selected
onRegionActivatefunctioncalled with region index when the playhead enters a region
onWordActivatefunction<optional>
called with word index when the playhead enters a word

Classes

WaveformPanel

Methods

(async) _pollEffectsReady(server, projectId)

Polls /effects/ready until the server reports true.
Parameters:
NameTypeDescription
serverobjectServer instance used to check readiness.
projectIdstringProject ID to poll.

_setWaveformColorMode(white)

Switches WaveSurfer's waveform bars to white (when effects are active) or back to theme colours (when cleared). Must only be called when the effects state changes — not on every frame — because setOptions triggers a full redraw.
Parameters:
NameTypeDescription
whitebooleanTrue to force white bars; false to restore theme colours.

_updateEffectButtons()

Shows or hides the clear/rerender effects buttons based on whether effects exist and the project is editable.

applyZoom(newZoom, anchorFracopt)

Applies a new zoom level to the WaveSurfer instance, updates the zoom label, and redraws the time ruler, minimap, and regions.
Parameters:
NameTypeAttributesDefaultDescription
newZoomnumberdesired zoom level (clamped to MIN_ZOOM..#maxZoom())
anchorFracnumber | null<optional>
nullif provided, the scroll position will be restored to this left-edge time fraction after the zoom re-renders

attachScrollListener()

Attaches the scroll handler to WaveSurfer's scroll container. Must be called after WaveSurfer finishes loading (in onReady).

basePxPerSec() → {number}

Computes the number of pixels per second that makes the entire track fit exactly in the waveform container at zoom level 1.
Returns:
pixels per second
Type: 
number

clearWaveformPanel()

Destroys the WaveSurfer instance and resets all audio and UI state to defaults.

clientXToTime(clientX) → {number}

Converts a clientX coordinate over the region lane to a time in seconds.
Parameters:
NameTypeDescription
clientXnumberviewport X coordinate
Returns:
time in seconds
Type: 
number

doZoom(newZoom)

Zooms to `newZoom` while keeping a fixed time point under the cursor or transport position. In cursor-anchor mode, computes the time fraction under the mouse and restores it after zoom so that pixel stays in place.
Parameters:
NameTypeDescription
newZoomnumberdesired zoom level

drawMinimap()

Redraws the minimap canvas, coloring bars by played/unplayed and viewport/non-viewport states, and positions the thumb overlay div.

drawMuteWaveformOverlay()

Draws the waveform colour overlay when muted ranges are active. Replicates WaveSurfer's played/unplayed split in theme colours, then overpaints muted sections in red. Called every frame from drawRegions().

drawRegions()

Redraws all waveform overlays and speaker region lanes for the active project.

getScrollEl() → {HTMLElement|null}

Returns the scrollable container element that WaveSurfer renders into. this is the parent of WaveSurfer's internal wrapper div. Returns null if no WaveSurfer instance exists yet.
Returns:
Type: 
HTMLElement | null

(async) initAudio(file)

Entry point for loading an audio file into the player. Validates the file, updates all relevant UI and AppState, then delegates the actual data work to loadAudioFile. Once loading completes, initialises WaveSurfer with the pre-computed peaks for fast zoom.
Parameters:
NameTypeDescription
fileFilemust have type starting with "audio/"

initWaveSurfer()

Creates (or re-creates) the WaveSurfer instance and registers all event handlers. Called both on initial file load and when switching projects. The old instance must be destroyed before calling this (resetWorkspace does it).

loadAudioFile(file)

Loads a local audio file: reads it as an ArrayBuffer, decodes it via the Web Audio API to extract sample rate and multi-channel buffers, then offloads peak extraction to an inline Web Worker so the UI stays responsive during processing. When the worker finishes, WaveSurfer is initialised with the pre-computed peaks for fast zoom.
Parameters:
NameTypeDescription
fileFilemust have type starting with "audio/"

loadFromProject(project)

Loads waveform data from the given project and draws regions.
Parameters:
NameTypeDescription
projectProjectthe project to load waveform data from

(async) loadWaveform(root0opt)

Initialises WaveSurfer and loads the waveform URL from the active project. For server files without pre-computed peaks, checks the remote file size via a HEAD request and — if the file is large — extracts peaks in chunks using HTTP Range requests before handing off to WaveSurfer, preventing the tab from running out of memory on long recordings. Logs a warning if the waveform URL is not defined.
Parameters:
NameTypeAttributesDefaultDescription
root0object<optional>
{}Options object.
Properties
NameTypeAttributesDefaultDescription
cacheBustboolean<optional>
falseAppend a timestamp query param to bypass the browser cache.

onFinish()

WaveSurfer 'finish' handler — playback reached the end naturally.

onLoading(percent)

WaveSurfer 'loading' handler — fires periodically during remote audio fetch.
Parameters:
NameTypeDescription
percentnumberloading progress 0–100

onPause()

WaveSurfer 'pause' handler — updates button icon and status indicators.

onPlay()

WaveSurfer 'play' handler — updates button icon and status indicators.

onReady()

WaveSurfer 'ready' handler — fires once the audio is fully decoded and ready. Two-pass peak extraction strategy: 1. First ready (no cachedWaveformPeaks): extract peaks from the decoded buffer and reload the file with them. this enables fast zooming without re-decode. 2. Second ready (_peaksInjected = true): skip extraction and finish normal setup. For server-streamed files, peaks weren't pre-computed before loading, so this path always runs. For local drag-drop, peaks are pre-computed in the Worker inside this.loadAudioFile(), so cachedWaveformPeaks is already set and the first pass is skipped.

onTimeUpdate(t)

WaveSurfer 'audioprocess' handler — fires frequently during playback. Coalesces updates via requestAnimationFrame to avoid redundant DOM writes. Handles: timecode display, playback-progress fraction, minimap, region highlight, transcript highlight, and follow-playhead auto-scroll.
Parameters:
NameTypeDescription
tnumbercurrent playback time in seconds

onWaveformScroll()

Scroll handler attached to WaveSurfer's internal scroll container. If a pendingScrollFrac is set (from applyZoom), applies the stored scroll position immediately and clears it; otherwise defers redraw to the next frame.

positionSectionBreakLines()

Updates the left position of each section-break line div based on the current scroll and zoom. Called from drawRegions() on every redraw.

regionIndexAtTime(time) → {number}

Returns the index of the region at the given time
Parameters:
NameTypeDescription
timenumbertime in seconds to look up
Returns:
the segment index at the given time, or -1 if none
Type: 
number

regionIndexAtX(clientX) → {number}

Given a mouse clientX coordinate over the region lane, returns the index of the transcript segment whose time range covers that position.
Parameters:
NameTypeDescription
clientXnumbermouse X in viewport coordinates
Returns:
segment index, or -1 if no segment at that position
Type: 
number

renderSectionBreakLines()

Creates or recreates the section-break line divs inside #waveformWrap to match the current set of section breaks. Call when the set of breaks changes (add, remove, undo, redo, project load/clear).

resetZoom()

Resets the zoom level to 1× (fit entire track in visible width).

resizeMinimap()

Sizes the minimap canvas to the wrapper's current CSS dimensions × dpr. Called on resize and after WaveSurfer reports 'ready'.

setEffectsRendering(isRendering, serveropt, projectIdopt)

Puts the play button into a "Rendering Effects" spinner state and polls the server until the effects audio is ready. Pass isRendering=false to clear the state immediately (e.g. when all effects are removed).
Parameters:
NameTypeAttributesDescription
isRenderingbooleanTrue to enter the rendering state; false to clear it.
serverobject<optional>
Server instance (required when isRendering=true)
projectIdstring<optional>
project id (required when isRendering=true)

setHoveredRegion(regionIdx)

Updates the hovered region index and redraws the region canvas.
Parameters:
NameTypeDescription
regionIdxnumbersegment index, or -1 to clear

setSelectedRegion(regionIdx)

Seeks the playhead to the start of the selected segment and redraws.
Parameters:
NameTypeDescription
regionIdxnumbersegment index, or -1 to clear

setStatus(left, rightopt)

Updates the status bar text. If `right` is omitted, only the left side changes.
Parameters:
NameTypeAttributesDescription
leftstringe.g. 'PLAYING', 'READY'
rightstring<optional>
e.g. '42.3%'

setWaveformHeight(h)

Sets the waveform panel height (clamped to 40–400px), updates the CSS variable, and redraws the minimap and regions.
Parameters:
NameTypeDescription
hnumberdesired height in pixels

setupHandleDrag(el, side)

Registers a mousedown listener on a minimap edge handle that initiates a resize drag (changes zoom level by adjusting the visible fraction).
Parameters:
NameTypeDescription
elHTMLElementthe handle element
side'left' | 'right'which edge is being dragged

skipN(skipSeconds)

Seeks the playhead forward or backward by skipSeconds.
Parameters:
NameTypeDescription
skipSecondsnumberseconds to skip (negative = backward)

skipToParagraph(direction)

Seeks to the start of the previous or next paragraph relative to the current playhead. Same restart-threshold logic as skipToSegment: if within 0.5s of the current paragraph's start, jumps to the previous one instead.
Parameters:
NameTypeDescription
directionnumber-1 for previous, 1 for next

skipToSegment(direction)

Seeks to the start of the previous or next segment relative to the current playhead. For direction -1 (prev): seeks to the current segment's start, or to the previous segment's start if already near the beginning of the current one. For direction 1 (next): seeks to the start of the next segment. Falls back to skipN(±5) if no transcript is loaded.
Parameters:
NameTypeDescription
directionnumber-1 for previous, 1 for next

timeToClientX(time) → {number}

Converts a time (seconds) to a clientX coordinate over the region lane.
Parameters:
NameTypeDescription
timenumberseconds
Returns:
clientX in viewport pixels
Type: 
number

togglePlay()

Toggles WaveSurfer playback.

updateSegNavButtons(time)

Updates the enabled/disabled state of the segment and paragraph nav buttons for the given playhead time.
Parameters:
NameTypeDescription
timenumbercurrent playhead position in seconds

updateTimeRuler()

Rebuilds the time ruler tick marks to match the current zoom level and scroll position. Tick interval is chosen from a set of "nice" values so there are approximately 8 visible ticks at any zoom. At very high zoom (≤10s visible) timestamps include decimal seconds.

updateTransportLabel()

Repositions the yellow transport line label to match the current playback position. Hides the label when the transport cursor is scrolled out of view.

zoomIn(amount)

Increases the zoom level by multiplying by amount.
Parameters:
NameTypeDescription
amountnumbermultiplier (e.g. 1.25)

zoomOut(amount)

Decreases the zoom level by dividing by amount.
Parameters:
NameTypeDescription
amountnumberdivisor (e.g. 1.25)

zoomToParagraph(paragraphIdx)

Zooms the waveform to the time range of the paragraph at the given index.
Parameters:
NameTypeDescription
paragraphIdxnumberindex of the paragraph to zoom to

zoomToRegion(regionIdx)

Zooms the waveform so the specified segment occupies ~50% of the visible width, then scrolls to center it. Uses two nested rAF calls to wait for WaveSurfer to finish re-rendering at the new zoom level before scrolling.
Parameters:
NameTypeDescription
regionIdxnumbersegment index to zoom to