Skip to content
3 Death Saves

Spell Loadouts

A spell loadout is a named snapshot of a character’s prepared spells for one spellcasting class. Applying a loadout restores that preparation set without stepping through the class tab spell by spell.

Loadouts are stored on the actor as flags. They persist across sessions and are scoped to the class they were created on.


A player opens the Player Spell Book, switches to the class tab whose loadouts they want to manage, and clicks the Loadouts toolbox icon in the sidebar.

The button opens a LoadoutSelector dialog scoped to the active tab’s class. The dialog title reads {class} Spell Loadouts, for example Wizard Spell Loadouts.

Right-clicking the same sidebar button opens a context menu listing every saved loadout for the active class. Clicking an entry applies that loadout using the same path as the dialog’s Apply action, and refreshes the class tab in place.

If no loadouts exist for the class, the menu shows a single non-interactive entry: “No loadouts saved. Prepare spells and click “Save Current Configuration” to create one.”

A left-click opens the full dialog.


Loadout Selector dialog

The dialog has two fieldsets: Create New Loadout and Saved Loadouts.

FieldRequiredPurpose
Loadout NameYesLabel shown in the list. Trimmed before saving.
Loadout DescriptionNoOptional note shown next to the loadout name.
Save Current Configuration buttonn/aCaptures the live checkbox state for the active class and stores it as a new loadout.

Validation:

  • Empty name: rejected with SPELLBOOK.Loadouts.NameRequired (“Loadout name is required.”).
  • Empty spell set: rejected with SPELLBOOK.Loadouts.NoSpellsPrepared (“No spells are prepared to save.”).

On success, the form resets and the new entry appears in the list.

Save does not read the actor’s persisted prep flag. It resolves the spell set to capture in this order:

  1. Live checkboxes in the rendered class tab, ticked but not yet saved to the sheet.
  2. Pending changes stored for a tab that was edited then switched away from without submitting.
  3. The actor’s prepared-spells flag, as a fallback if the tab is not loaded.

A player can build a loadout from an unsaved preparation state without ever committing it to the sheet.

Each loadout renders as a row with a name, an optional description, and a meta line showing the spell count and a relative “updated” time.

Each row has three actions:

IconActionBehavior
fa-checkApplyWrites the loadout’s spells as the class’s prepared set, refreshes the class tab, closes the dialog.
fa-sync-altOverwriteReplaces the loadout’s spell list with the currently-captured spell set. Name and description are preserved.
fa-trashDeleteConfirmation prompt, then removes the loadout.

Hovering a row previews every spell in the loadout, sorted by level then name, each with a thumbnail.

If no loadouts exist for the class, the list is replaced by a SPELLBOOK.Loadouts.NoLoadouts notice.

Clicking Delete opens a confirmation dialog; cancelling leaves the loadout untouched, and confirming removes the loadout from the actor flag. Loadouts are actor flags, not journal pages, so deleting one does not touch any custom spell list.


Applying a loadout combines the actor’s currently prepared spells with the loadout’s spell set:

  • Spells prepared before apply but not in the loadout become unprepared.
  • Spells in the loadout that were not previously prepared become prepared.
  • Spells in both sets stay prepared.
  • Spells in the loadout whose source item no longer resolves are skipped.

The same apply logic runs for both the dialog’s Apply button and the right-click quick-select entry, and both refresh the class tab afterward.

Applying a loadout fires a spell-book.loadoutApplied hook, passing the actor, class identifier, the applied spell UUIDs, and the loadout’s id and name.


A class’s loadout list includes every loadout saved under that class identifier, plus any legacy loadout with no class identifier attached. The dialog and quick-select menu only ever show loadouts for the active class, and applying one only touches that class’s prepared spells.


Loadouts live in an actor flag at:

actor.flags['spell-book']['spellLoadouts']['{loadoutId}']

Each loadout has this shape:

{
id: 'randomID',
name: 'Combat Prep',
description: 'AoE + control', // optional, may be empty
classIdentifier: 'wizard',
spellConfiguration: [
'Compendium.dnd5e.spells.Item.abc...',
'Compendium.dnd5e.spells.Item.def...'
],
createdAt: 1713532800000,
updatedAt: 1713532800000
}

The static methods on scripts/managers/loadouts.mjs handle loadout data with no DOM dependency, so they are safe to call from a macro or another module.

MethodSignatureReturnsNotes
Loadouts.getLoadouts(actor, classIdentifier = null)Array<Loadout>With a class id, filters to that class plus entries missing classIdentifier. With null, returns all.
Loadouts.getLoadout(actor, loadoutId)Loadout | nullReads the flag directly.
Loadouts.saveLoadout(actor, classIdentifier, name, description, spellConfig)Promise<string | null>Creates a new loadout with a generated id. Returns the id, or null if name is empty.
Loadouts.deleteLoadout(actor, loadoutId)Promise<boolean>Removes the loadout. Returns false if the id was not present.
Loadouts.invalidateCache(actor)voidDrops the cached flag for that actor.

There is no public apply helper on Loadouts. The apply path lives in LoadoutSelector.applySpellConfiguration, since it depends on SpellManager.saveClassSpecificPreparedSpells.