Sprite maps
Both flat and file-grouped maps are accepted. Times are milliseconds and
file is relative to audioBaseUrl, without an extension.
Flat maps use a cue name at the top level; grouped maps use an arbitrary group name, then the cue name. The two equivalent shapes below are both valid:
{
"drawer-open": {
"start_ms": 0,
"end_ms": 450,
"file": "ui/sprite"
}
}{
"ui/sprite": {
"drawer-open": {
"start_ms": 0,
"end_ms": 450,
"file": "ui/sprite"
}
}
}The default formats are webm and m4a. Invalid offsets, empty names,
duplicates, and malformed entries emit actionable warnings. Use strict: true
to reject the whole map instead. A missing map otherwise degrades to a no-op
resolver, which is useful when audio is optional.
An entry may override its file's codec preference list and request sprite
looping. Every entry pointing at the same file must use exactly the same
ordered formats list, because Howler chooses one codec for that file rather
than falling back after an HTTP error. loop: true becomes Howler's third
sprite tuple value and the resolver retains that sound ID across loop ends.
{
"burial-chamber-ambience": {
"start_ms": 0,
"end_ms": 32000,
"file": "music/burial-chamber",
"formats": ["wav", "ogg"],
"loop": true
}
}file must be a non-empty path inside audioBaseUrl, with no . or ..
segments or backslashes. A leading slash is ignored; it is not a cue namespace. For
audioBaseUrl: '/audio' and file: 'ui/sprite', Howler receives
/audio/ui/sprite.webm and /audio/ui/sprite.m4a. Supply at least two formats
that cover the browsers you support, and keep their cue offsets identical.
Several map files
Pass spriteMapUrls instead of spriteMapUrl to keep cues in separate files and
merge them at startup:
await initSpriteResolver({
spriteMapUrls: ['/audio/ui-map.json', '/audio/ambience-map.json'],
strict: true,
});Every URL is fetched, and flat and grouped maps may be mixed. Each cue name must
be defined once across all of them: under strict a repeat is an error naming
both maps, and otherwise the first definition (in array order) wins with a
console warning. The rule that cues sharing a file agree on formats applies
to the merged map. A failed request for any listed map fails initialization the
way a single missing map does.
Load only requested sheets
initSpriteResolver() preserves its eager default and asks Howler to preload
every declared sheet. Games with large maps can opt into on-demand sheet loads:
await initSpriteResolver({ preload: false, strict: true });This still fetches and validates sprite-map.json during initialization so
invalid maps fail at bootstrap in strict mode. It creates each sheet definition
without fetching or decoding its audio. The first playCue for a sheet queues
that cue and loads just that sheet through Howler's public API. It avoids unused
sheet fetches and decoding; it does not make a network or device-performance
guarantee.
Verify assets in build tooling
import { runVerifySpritesCli } from 'gesture-audio/build-tools';
await runVerifySpritesCli({
audioRoot: 'public/audio',
spriteBuses: ['ui', 'impact'],
flatGroups: [{ dir: 'music', keys: ['menu', 'gameplay'], required: true }],
maxTotalBytes: 12 * 1024 * 1024,
fast: process.argv.includes('--fast'),
});Full mode uses ffmpeg and ffprobe for duration and LUFS checks. fast
keeps structural and byte-budget checks only. The build-tools entry point is
Node-only and must never be imported from browser runtime code.
See API reference for the complete verifier option contract and integration guide for runtime strictness.
