API Reference
The API is published as the global MINSTREL and at game.modules.get('minstrel').api. Both point to the same object.
Mood and cue playback runs on one client. moods.apply, moods.stop, and cues.refresh return early unless the calling client is the active GM, so a call from a player client does nothing. Ducking and file-backed soundboard pads are broadcast and take effect on every client.
The API object is built during Foundry’s ready hook, before minstrel.ready fires. Register sections from that hook.
| Method | Returns | Description |
|---|---|---|
MINSTREL.moods.list() | object[] | Every saved mood. |
MINSTREL.moods.apply(id) | Promise<void> | Starts a mood. Accepts a mood id or a mood object. |
MINSTREL.moods.stop(id) | Promise<void> | Stops a mood. Called with no argument, stops the active mood. |
MINSTREL.moods.active() | string | null | The id of the mood currently applied. |
soundboard
Section titled “soundboard”| Method | Returns | Description |
|---|---|---|
MINSTREL.soundboard.list() | object[] | Every saved pad. |
MINSTREL.soundboard.play(id) | Promise<Sound | void> | Plays a pad. A file-backed pad plays on every client. |
A pad record is { id, label, src, icon, color, volume, duck }. A pad wired to Syrinscape carries syrinscapeId and syrinscapeKind instead of playing src.
| Method | Returns | Description |
|---|---|---|
MINSTREL.cues.read(doc, context) | object | null | The cue stored on a document for a context key. |
MINSTREL.cues.write(doc, context, cue) | Promise | Stores a cue, then re-resolves playback. A cue with neither moodId nor playlistId clears the assignment. |
MINSTREL.cues.active() | object | null | The winning cue candidate. |
MINSTREL.cues.refresh() | Promise<void> | Re-runs cue resolution, for when a predicate would now answer differently. |
MINSTREL.cues.suppress(context, on) | Promise<void> | Adds or removes a context key from the suppressed set. on defaults to true. |
MINSTREL.cues.isSuppressed(context) | boolean | Whether a context key is suppressed. |
read and write take a Scene, Actor, or Token document.
active() returns the resolved candidate, not the raw cue:
| Field | Type | Description |
|---|---|---|
context | string | The context key that won. |
doc | Document | The document the cue came from. |
type | string | The document type: Scene, Actor, Token, or DefaultMusic. |
cue | object | The stored cue. |
priority | number | The priority used for sorting. |
Suppression is a world-scoped set of context keys covering the built-in area and combat contexts and any registered section’s context key. Changing it re-runs cue resolution.
MINSTREL.duck('music', 0.3, 4000);Dips an audio channel, holds it, then ramps it back. The call is emitted over the socket, so every client ducks.
| Parameter | Type | Description |
|---|---|---|
channel | string | music, environment, or interface. Defaults to music. |
factor | number | Multiplier applied to the channel’s configured volume, clamped to 0 through 1. Defaults to 0.3. |
holdMs | number | How long to hold the dip before restoring. Defaults to 4000. |
The ramp duration comes from the Ducking Fade setting rather than from the call. See Settings.
openConsole
Section titled “openConsole”MINSTREL.openConsole() toggles the console window. It opens when closed and closes when open.
syrinscape
Section titled “syrinscape”The MINSTREL.syrinscape namespace wraps the Syrinscape Online frontend API using the token stored in settings.
| Method | Returns | Description |
|---|---|---|
syrinscapeEnabled() | boolean | True when the integration is enabled and a token is set. |
listSoundsets() | Promise<object[]> | Soundsets as { uuid, name }. |
listMoods(uuid) | Promise<object[]> | Moods in a soundset as { id, name }. |
listElements(uuid) | Promise<object[]> | Elements in a soundset as { id, name }. |
playMood(id), stopMood(id) | Promise<void> | Starts or stops a Syrinscape mood. |
playElement(id), stopElement(id) | Promise<void> | Starts or stops a Syrinscape element. |
stopAll() | Promise<void> | Stops all Syrinscape playback. |
play(trigger), stop(trigger) | Promise<void> | Routes { kind, id } to the mood or element call. kind is mood or element. |
Every request runs from the calling client. play and stop do nothing while the integration is disabled or the trigger has no id. The list helpers return an empty array when no token is set, and a failed request is logged rather than thrown.
registerSection
Section titled “registerSection”const handle = MINSTREL.registerSection({ id: 'my-module.weather', label: 'MYMODULE.WeatherMusic', priority: 10, types: ['Scene'], predicate: () => game.myModule.isStormy, contextKey: 'weather'});Registers a cue section. A registered section gets its own group on the console’s Other tab, with rows for the documents of each type it covers, and competes in the same priority ordering as the built-in sections. The Other tab stays hidden while no section is registered.
| Property | Type | Description |
|---|---|---|
id | string | Required. Unique registry id. |
label | string | Localization key for the group heading. Used verbatim when it resolves to nothing. |
priority | number | Default sort priority for the section’s cues. Defaults to 0. |
types | string[] | Document type names the section applies to: Scene, Actor, Token, DefaultMusic. Defaults to an empty array. |
predicate | Function | Activation test, called with no arguments once per cue resolution. A falsy return keeps the section silent. |
contextKey | string | Context key used for flags, suppression, and playback. Defaults to the id. |
hint | string | Localization key describing when the section plays, shown as the tooltip on each row’s name. |
Registration is validated. It is rejected, logged, and returns null when:
idis missing or not a string.idis already registered.typesis not an array, or contains a name outsideScene,Actor,Token,DefaultMusic.predicateis defined but not a function.- The context key is
areaorcombat, or is already claimed by another registered section.
A successful call returns a handle:
| Member | Description |
|---|---|
id | The registered id. |
contextKey | The resolved context key. |
unregister() | Removes the section and refreshes cues. |
refresh() | Re-runs cue resolution. |
A predicate that throws is logged and disables its section for that resolution pass.
MINSTREL.unregisterSection(id) removes a section by id and returns true when one was removed. MINSTREL.getRegisteredSections() returns every registered definition. Neither one refreshes cues on its own.
Built-in section priorities
Section titled “Built-in section priorities”| Section | Priority |
|---|---|
| Token combat | 5 |
| Actor combat | 0 |
| Global combat | -5 |
| Scene combat | -10 |
| Scene area | -20 |
A cue’s own priority overrides the section default.
Cue data
Section titled “Cue data”A cue is a small object stored per context key. It names either a mood or a playlist.
| Field | Type | Description |
|---|---|---|
moodId | string | Id of a saved mood. |
playlistId | string | Id of a Playlist document. |
soundId | string | Optional. Id of a PlaylistSound in that playlist, to start one track instead of the whole playlist. |
priority | number | Optional. Overrides the section’s default priority. |
Cues live at flags.minstrel.cues.<context> on Scene, Actor, and Token documents. The Global row is stored in a world setting instead of on a document.
read falls back to legacy data when the document carries no Minstrel cue. On a Scene it reads flags.minstrel.moodId for a non-combat context and flags.minstrel.combatMoodId for the combat context. It then reads a flags.vgmusic.music.<context> entry, mapping its playlist, initialTrack, and priority onto the cue shape.
| Hook | Payload | Description |
|---|---|---|
minstrel.ready | api | Fires once the API object is published. |
minstrel.moodApplied | mood | Fires on the active GM when a mood starts. |
minstrel.moodStopped | mood | Fires on the active GM when a mood stops. |
minstrel.padPlayed | pad | Fires on the client that triggered a soundboard pad. |
minstrel.cueChanged | { cue, mood } | Fires on the active GM when cue resolution settles on a different mood. Both fields are null when nothing wins. |
minstrel.suppressionChanged | Set<string> | Fires on the client that changed suppression, with the new set of suppressed context keys. |
Hooks.on('minstrel.cueChanged', ({ cue, mood }) => {});Minstrel also listens for one inbound hook. Calling Hooks.call('minstrel.openConsole') toggles the console, the same as MINSTREL.openConsole().
Pack authors can ship these flags on documents inside a compendium.
Playlist
Section titled “Playlist”| Flag | Type | Description |
|---|---|---|
flags.minstrel.art | string | Path to the cover image shown on the album tile and in the mini player. |
flags.minstrel.color | string | Accent color. Falls back to a color derived from the playlist id when unset. |
flags.minstrel.favorite | boolean | Pins the playlist to the top of the library. |
flags.minstrel.crossfade | boolean | Runs the playlist through the crossfade conductor. |
flags.minstrel.level | number | Playlist fader level applied on top of each track’s own volume. Treated as 1 when unset. |
flags.minstrel.packSource | string | Links a world playlist to the compendium playlist it was imported from. A later pad import from the same origin reuses that playlist instead of creating a second one. |
PlaylistSound
Section titled “PlaylistSound”| Flag | Type | Description |
|---|---|---|
flags.minstrel.artist | string | Artist credit shown for the playing track. |
flags.minstrel.source | string | Source credit shown for the playing track. |
flags.minstrel.pad | object | Soundboard pad preset. label, icon, color, volume, and duck seed the pad created from this track. |
Scene, Actor, and Token
Section titled “Scene, Actor, and Token”| Flag | Type | Description |
|---|---|---|
flags.minstrel.cues | object | Cues keyed by context, using the shape above. |