@molecule/app-audio-howler
Provider bond · audio · App (browser) · v1.0.2 · Apache-2.0
State-only stub audio provider for @molecule/app-audio (NO sound output yet — satisfies the interface for tests/UI dev)
npm install @molecule/app-audio-howlernpm · Source on GitHub · Implements @molecule/app-audio
How it works
@molecule/app-audio-howler is a provider bond on the app (browser) side: it implements the audio core interface (@molecule/app-audio) with a concrete vendor or library behind it.
Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.
import { provider } from '@molecule/app-audio-howler'
import { setProvider } from '@molecule/app-audio'
setProvider(provider)Works with: @molecule/app-audio
Live demos
Running apps built with Molecule that install this package — open the app or study the template.
Reference
Howler.js audio provider for @molecule/app-audio — real, audible playback.
Bonds Howler.js (new Howl({ src: [...] })) behind the core AudioProvider
contract. Each player wraps a live Howl, so playback is genuinely audible
and every read reflects real Howler state: getDuration() returns the loaded
track's duration, getCurrentTime() reflects the real seek position,
isPlaying()/getVolume() read Howler directly, and onEnd/onProgress
are driven by Howler's own events.
Core AudioPlayerOptions map onto Howler's constructor (src normalized to
an array, plus loop/autoplay/volume); the provider-level HowlerConfig
supplies the default html5 backend and an optional global volume.
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Quick Start
import { provider } from '@molecule/app-audio-howler'
import { setProvider } from '@molecule/app-audio'
setProvider(provider)
Type
provider
Installation
npm install @molecule/app-audio-howler @molecule/app-audio howler
npm install -D @types/howler
API
Interfaces
HowlerConfig
Provider-specific configuration options.
interface HowlerConfig {
/**
* Use HTML5 Audio instead of the Web Audio API as the default backend for
* every player this provider creates (maps to Howler's `html5` option — best
* for large/streamed files). Defaults to `false`.
*/
html5?: boolean
/**
* Global volume applied to all sounds via Howler's global `Howler.volume(...)`
* when the provider is created (0.0 to 1.0). Left untouched when omitted.
*/
volume?: number
}
Functions
createHowlerPlayer(options, config)
Creates a real, audible audio player backed by a Howler Howl instance.
The core AudioPlayerOptions are mapped onto Howler's constructor options
(src normalized to an array, plus loop/autoplay/volume), and the
provider-level HowlerConfig supplies the default html5 backend.
Event subscriptions are wired through Howler's .on(...) API: onEnd fires
from the end event, and onProgress is driven by a requestAnimationFrame
loop that runs while the sound is playing (plus one emit on load, so the
real duration is reported as soon as metadata is available).
function createHowlerPlayer(options: AudioPlayerOptions, config?: HowlerConfig): AudioPlayerInstance
options— Core audio player configuration (source, callbacks, etc.).config— Provider-level Howler configuration.
Returns: An AudioPlayerInstance whose reads reflect live Howler state.
createProvider(config)
Creates a Howler-backed audio provider that plays real, audible audio.
config.volume, when provided, sets Howler's global volume for every sound;
config.html5 selects the HTML5 Audio backend (over Web Audio) as the
default for the players this provider creates. Each createPlayer() builds a
live Howl and returns an AudioPlayerInstance whose reads reflect real
Howler state (see createHowlerPlayer).
function createProvider(config?: HowlerConfig): AudioProvider
config— Optional provider configuration.
Returns: A configured AudioProvider backed by Howler.
Constants
provider
Default Howler audio provider instance.
const provider: AudioProvider
Core Interface
Implements @molecule/app-audio interface.
Bond Wiring
Setup function to register this provider with the core interface:
import { setProvider } from '@molecule/app-audio'
import { provider } from '@molecule/app-audio-howler'
export function setupAudioHowler(): void {
setProvider(provider)
}
Injection Notes
Requirements
Peer dependencies:
@molecule/app-audio^1.0.1
Runtime Dependencies
-
@molecule/app-audio -
howler -
Browsers block autoplay.
autoplay: trueorplay()outside a user gesture is ignored until the user interacts with the page — start playback from a click/tap handler. -
getDuration()is 0 until metadata loads. Read it inonProgress(it emits once on Howler'sloadevent) rather than synchronously right aftercreatePlayer. -
Call
destroy()on unmount. It stops the progress loop and callsHowl.unload()to release buffers and detach listeners.
E2E Tests
Playback verification — drive the real rendered UI (live preview, no mocks), adapt each item to this app's actual audio screens/controls, and check every box off one by one. This core is PLAYBACK ONLY (no recording); a box you can't check is an integration bug to fix — not a skip:
- Loading a track and pressing the play control actually plays: the current-time readout advances, the progress bar moves, and the UI shows the playing state (isPlaying() true, getCurrentTime() keeps climbing). Confirm sound is audible, not just that the state flipped — start it from a click/tap so autoplay policy does not silently block it.
- The pause control halts playback: current time freezes, the progress bar stops, and the control toggles back to "play"; pressing play resumes from the same position, not the start.
- Dragging/clicking the scrubber to a target position seeks there: getCurrentTime() jumps to that time and the displayed elapsed time matches.
- The volume/mute control changes output: raising/lowering the slider is audible and getVolume() reflects it; muting (volume 0) silences the audio without pausing it.
- Total duration and elapsed time render correctly once metadata loads (getDuration() > 0, read via onProgress), not "0:00 / 0:00" stuck on screen.
- Reaching the end fires the ended state: the onEnd callback runs and the UI resets to the start (or advances to the next track), not a silent hang.
- The audio source loads from the app's own origin (a bundled/served asset), not a broken external URL — no 404/CORS error in the console and sound actually reaches the output.