Shattered Codex

Wiki

Modules/SC - Ascendant Items

SC - Ascendant Items

Foundry v13-v14System D&D 5ePremium

SC - Ascendant Items

Overview

SC - Ascendant Items adds a level-based progression workflow to supported D&D 5e item sheets.

Use it when one item should evolve across multiple stages instead of being split into separate item copies. Each level stores progression data and can also store a snapshot of the real item state for that stage.

Validated module scope:

  • a per-item Levels tab
  • progression by XP or Milestone
  • multiple saved levels on one item
  • per-level snapshots of supported item data
  • snapshot apply and level advance actions
  • configurable player permissions by role
  • configurable XP bar gradient and animation
  • integrations with tidy5e-sheet and SC - Simple Sockets
  • an optional Change Ascendant Level activity for SC - More Activities
  • an asynchronous public API for reading and changing levels, with level hooks

An ascendant item keeps the normal item-sheet workflow while adding staged progression and snapshot-based restores.

Installation

This module is premium.

Install access is handled through the Shattered Codex Download Hub.

See How to Download Premium Modules from the Download Hub for the full access and installation flow.

After installing:

  1. Enable SC - Ascendant Items in your world.
  2. Make sure lib-wrapper is also active.
  3. Open a supported dnd5e item.

Compatibility:

Enable Levels On An Item

The module is enabled per item, not globally.

To enable it:

  1. Open the item sheet.
  2. Go to Details.
  3. Enable Levels.

Enabling Levels adds the dedicated tab only for that item and starts storing the progression workflow in item flags.

Important behavior:

  • the Levels toggle is GM-only
  • if an item already has saved levels, the module still treats it as enabled
  • you can only disable Levels after removing all saved levels from that item

Build The Level Progression

After enabling Levels, open the new Levels tab.

The main workflow is:

  1. Click Add Level.
  2. Edit the item into the state you want for that stage.
  3. Use Capture Level to save the current state into that level.
  4. Add more levels and repeat as needed.
  5. Use Apply Level or Advance Level later to restore a saved stage.

Each level row stores progression metadata and can also show snapshot summary badges for activities, Active Effects, and sockets.

The Levels tab can show:

  • progression mode
  • current level
  • XP progress when the mode is XP
  • a list of configured levels
  • level labels, required XP, or milestone text
  • snapshot summary badges
  • actions such as Capture Level, Apply Level, and Delete

When you click Add Level, the module:

  • creates the next numeric level automatically
  • stores it on the item
  • creates an initial snapshot from the current item state
  • marks that level as active

Choose XP Or Milestone Progression

The module supports two progression modes.

XP Progression

In XP mode, the item tracks Current XP and each level can define its own XP Required threshold.

Behavior in XP mode:

  • the first level always keeps XP Required = 0
  • the XP bar measures progress toward the next configured level
  • when current XP reaches the next threshold, the item is ready to advance
  • if there is no next level, the bar shows Highest configured level

Milestone Progression

In Milestone mode, each level stores milestone text instead of numeric XP requirements.

Behavior in Milestone mode:

  • the XP bar is hidden
  • each level can store milestone text
  • progression is manual
  • the item can advance whenever a next level exists

Capture And Apply Snapshots

The module separates two kinds of data:

  1. progression data
  2. the real item snapshot for each level

Progression data includes:

  • progression mode
  • current XP
  • active level
  • last applied level
  • level labels
  • milestone text
  • required XP

The snapshot stores the real item state for a level.

Use Capture Level when you want to save the current item state into that level. Before capture, the module tries to submit pending sheet edits so the snapshot reflects the current sheet state.

Snapshot summary badges help confirm what is currently stored for each level.

A snapshot can include:

  • item name
  • item img
  • supported system fields
  • activities
  • embedded Active Effects
  • supported socket layout data
  • snapshot update time

Use Apply Level to restore a saved snapshot for a specific row.

Use Advance Level to move to the next configured level:

  • if the next level has a snapshot and the user may apply snapshots, that snapshot is applied
  • if the next level has no snapshot, the module only changes the active level

The camera button can also highlight when the current item no longer matches the comparison baseline, which is a practical sign that you may want to capture the level again.

Preserve Item Uses

Enable Preserve Item Uses when changing form should keep the item's current system.uses pool instead of restoring the value captured in the destination snapshot.

This GM-only toggle appears in Details > Levels after Levels is enabled. It applies to every snapshot restore path:

  • Apply Level
  • Advance Level when the next level has a snapshot
  • the Change Ascendant Level activity
  • public API calls that restore a snapshot

Capturing a level still records the current system.uses value. The toggle only changes what happens when that snapshot is restored, so turning it off later returns to the per-level uses value already stored in each snapshot.

Important limits:

  • activity-specific uses at system.activities.<id>.uses still come from the snapshot
  • rest recovery remains standard dnd5e behavior
  • if the live item has no system.uses, the snapshot value is restored normally
  • changes to the preserved item uses pool do not activate the uncaptured-change indicator

Module Settings And Permissions

Open:

code
Configure Settings > Module Settings > SC - Ascendant Items

Available menus:

MenuWhat it does
Open documentationOpens the SC - Ascendant Items wiki page.
Configure XP BarOpens the XP bar gradient and animation settings window.
Configure PermissionsOpens the role-based player permissions window for levels, snapshots, and progression.

Player Permissions

All permission settings default to GM Only.

Configurable role thresholds:

  • GM Only
  • Assistant GM+
  • Trusted Player+
  • All Players

Configurable permissions:

  • add levels
  • delete levels
  • edit level names
  • edit milestone names
  • edit required XP
  • capture snapshots
  • apply level snapshots
  • change progression mode

XP Bar Configuration

The XP bar settings support:

  • between 2 and 8 gradient colors
  • animation on or off
  • animation type
  • animation duration

Available animation types include:

  • Flow
  • Breathing
  • Wave
  • Pulse
  • Ping-Pong
  • Shimmer
  • Steps
  • Dual-Layer Flow
  • Spin
  • Neon Glow
  • Sparkle
  • Scanline
  • Liquid
  • Radial Sweep
  • Noise / Grain

Integrations

Tidy 5e Sheet

When tidy5e-sheet is active, the module:

  • registers the same Levels tab on the Tidy item sheet
  • adds the Levels toggle to the Tidy details area
  • keeps the same progression and snapshot workflow

SC - Simple Sockets

When SC - Simple Sockets is active, socket layout data becomes part of the snapshot workflow.

Current validated behavior:

  • socket layout is saved in the snapshot
  • extra slots can be removed when a restored level has fewer sockets
  • gem activities and effects can be removed and reapplied during restore
  • socket-related update data is merged into the item restore flow

Change Ascendant Level Activity

When SC - More Activities 0.5.0 or later is active, Ascendant Items registers Change Ascendant Level as an external activity type. It is available only on items that already have Levels enabled.

The activity is listed in the Ascendant Items group and can select a destination in several ways:

OperationWhat happensAdditional configuration
Specific LevelApplies one configured destination by its stable level id.Choose Destination Level.
Next LevelAdvances one step from the active level.No destination field is required.
Random Level > Uniform RandomSilently chooses one candidate with equal probability.Choose whether Include Current Level is allowed.
Random Level > Roll 1dNOpens the native dnd5e roll dialog and maps the total to the ordered candidates.The die size is based on the number of candidates.
Random Level > Custom FormulaRolls a Foundry formula and applies the candidate whose numeric level value exactly matches the total.Enter the Formula and choose whether the current level is a candidate.
Ask on UseShows one card per candidate using the name and image stored in its snapshot.The user chooses the destination when the activity is used.

Random and prompted selection exclude the current level by default. Closing a roll or level-choice dialog cancels the activity without changing the item.

Create And Use The Activity

  1. Enable Levels on the item and configure its level snapshots.
  2. Add an activity and choose Ascendant Items > Change Ascendant Level.
  3. Choose an Operation and complete the fields for that operation.
  4. Optional: enable Chain an Activity under After Applying.
  5. Save and use the activity from the item as you would another dnd5e activity.

The user must own the item, and restoring a snapshot respects Players Can Apply Level Snapshots. The activity itself is preserved when a level snapshot is applied, so changing form does not remove the control that triggered it.

Run An Activity From The New Form

Enable Chain an Activity to run another activity immediately after the new level is applied. Configure the follow-up separately for each destination level, because every snapshot owns its own activity ids.

  • the follow-up is resolved from the live item after the level changes
  • Suppress Chained Card runs it without creating its own activity card
  • a missing mapped activity does not undo the successful level change
  • the level activity cannot target itself, and nested level changes have a depth limit

Capture a level again after replacing or renaming its activities so the stored mapping continues to point to the intended id.

API And Hooks

The module publishes its level API during Foundry's ready hook:

js
const api = game.modules.get("sc-ascendant-items")?.api?.levels;

All methods are asynchronous and accept an Item document or Item UUID as the first argument. Read methods return null or an empty list when the Item cannot be resolved. Write methods return a result object instead of throwing expected workflow errors.

Ascendant level API methods and parameters

Expand a method to see what each parameter accepts, its default value, and the returned value.

getState(itemOrUuid)Reads the complete serialized Ascendant Items state stored on an item.
Parameters
itemOrUuidItem | string

The ascendant Item document or its UUID.

Returns

Promise<object | null>. The state includes progressionMode, currentXp, preserveItemUses, active and last-applied ids, and the serialized levels.

getLevels(itemOrUuid)Lists the configured levels in their serialized storage format.
Parameters
itemOrUuidItem | string

The ascendant Item document or its UUID.

Returns

Promise<Array<object>>. Returns an empty array when the item cannot be resolved.

getActiveLevel(itemOrUuid)Reads the level referenced by activeLevelId.
Parameters
itemOrUuidItem | string

The ascendant Item document or its UUID.

Returns

Promise<object | null>. Returns null for an unresolved item or missing active level.

resolveLevel(itemOrUuid, levelRef)Resolves a level reference without changing the item.
Parameters
itemOrUuidItem | string

The ascendant Item document or its UUID.

levelRefstring | number | object

A stable id, numeric value, label, { id }, { value }, { label }, or a supported keyword.

Returns

Promise<object | null>. Returns the matching serialized level or null.

Example
const next = await api.resolveLevel(item, "next");
setLevel(itemOrUuid, levelRef, options?)Selects a destination level and restores its snapshot by default.
Parameters
itemOrUuidItem | string

The ascendant Item document or its UUID.

levelRefstring | number | object

The destination level reference.

options.applySnapshotbooleandefault: true

Set false to change only the active level.

options.forcebooleandefault: false

Reapplies the snapshot when the requested level is already active.

options.changeSourcestringdefault: api

Value included in levelSelected or levelApplied hook payloads.

Returns

Promise<LevelOperationResult>. A successful selection without a snapshot uses reason missing-snapshot.

Example
await api.setLevel(item.uuid, "Ascendant");
stepLevel(itemOrUuid, delta, options?)Moves a signed number of positions through the ordered level list.
Parameters
itemOrUuidItem | string

The ascendant Item document or its UUID.

deltanumber | numeric string

The signed step count. The value is truncated to a safe integer.

options.applySnapshotbooleandefault: true

Set false to change only the active level.

options.forcebooleandefault: false

Allows reapplying a snapshot when the resolved level is already active.

options.clampbooleandefault: false

Stops at the first or last level instead of failing beyond an endpoint.

options.changeSourcestringdefault: api

Value included in the emitted selection or apply hook.

Returns

Promise<LevelOperationResult>.

Example
await api.stepLevel(item, -2, { clamp: true });
advanceLevel(itemOrUuid, options?)Mirrors the sheet's Advance Level action and emits levelAdvanced.
Parameters
itemOrUuidItem | string

The ascendant Item document or its UUID.

optionsobjectdefault: {}

Reserved options object. Unknown options are ignored.

Returns

Promise<LevelOperationResult>. Returns already-at-maximum when there is no next level.

regressLevel(itemOrUuid, options?)Moves back one level through stepLevel(itemOrUuid, -1, options).
Parameters
itemOrUuidItem | string

The ascendant Item document or its UUID.

options.applySnapshotbooleandefault: true

Set false to change only the active level.

options.forcebooleandefault: false

Allows reapplying a snapshot when applicable.

options.clampbooleandefault: false

Keeps the item at the first level instead of returning at-first-level.

options.changeSourcestringdefault: api

Value included in the emitted selection or apply hook.

Returns

Promise<LevelOperationResult>. Returns at-first-level at the lower endpoint.

setCurrentXp(itemOrUuid, value, options?)Replaces the current XP value or applies a relative XP change.
Parameters
itemOrUuidItem | string

The ascendant Item document or its UUID.

valuenumber | numeric string

The absolute XP value or relative delta. Results are limited to a minimum of 0.

options.relativebooleandefault: false

Adds value to the current XP instead of replacing it.

Returns

Promise<LevelOperationResult> with currentXp on successful validation.

Example
await api.setCurrentXp(item, 50, { relative: true });
setProgressionMode(itemOrUuid, mode)Changes the item between XP and milestone progression.
Parameters
itemOrUuidItem | string

The ascendant Item document or its UUID.

mode"xp" | "milestone"

The exact stored progression mode.

Returns

Promise<LevelOperationResult> with progressionMode on success.

setPreserveItemUses(itemOrUuid, value)Changes the GM-only Preserve Item Uses toggle.
Parameters
itemOrUuidItem | string

The ascendant Item document or its UUID.

valueboolean

A strict boolean. Strings and numbers are rejected.

Returns

Promise<LevelOperationResult> with preserveItemUses on success.

Level References

setLevel and resolveLevel accept a stable level id, a numeric level value, a case-insensitive label, or an object containing id, value, or label. They also accept the keywords first, last, next, previous, current, and active.

Keyword strings are reserved. Use the object form to address a level whose label is itself a keyword:

js
await api.setLevel(item, "next");            // next position
await api.setLevel(item, { label: "next" }); // level labeled "next"

Write Results And Permissions

All write methods return the same core shape:

js
{
  ok,
  changed,
  snapshotApplied,
  reason,
  item,
  itemUuid,
  level,
  previousLevel,
  state
}

Check ok before using the returned data and use snapshotApplied to determine whether item state was restored. missing-snapshot can accompany a successful level selection; unexpected failures use operation-failed and include the original error.

Every non-GM write requires Item ownership. Snapshot restoration also respects Players Can Apply Level Snapshots, progression mode changes respect Players Can Change Progression Mode, and setPreserveItemUses is GM-only. The public API does not expose a permission bypass.

Hooks

Use the constants exposed on api instead of hard-coding hook names:

ConstantLiteral hookWhen it fires
HOOK_LEVEL_ADDEDsc-ascendant-items.levelAddedA level is added.
HOOK_LEVEL_SELECTEDsc-ascendant-items.levelSelectedThe active level changes without restoring a snapshot.
HOOK_CURRENT_XP_UPDATEDsc-ascendant-items.currentXpUpdatedCurrent XP changes.
HOOK_LEVEL_ADVANCEDsc-ascendant-items.levelAdvancedAdvance Level, advanceLevel(), or the activity advances one position.
HOOK_LEVEL_METADATA_UPDATEDsc-ascendant-items.levelMetadataUpdatedA level value, label, XP threshold, or milestone changes.
HOOK_LEVEL_DELETEDsc-ascendant-items.levelDeletedA level is deleted.
HOOK_LEVEL_CAPTUREDsc-ascendant-items.levelCapturedCapture Level replaces a snapshot.
HOOK_LEVEL_APPLIEDsc-ascendant-items.levelAppliedAny workflow restores a snapshot.
HOOK_MODE_CHANGEDsc-ascendant-items.modeChangedProgression changes between XP and Milestone.
HOOK_PRESERVE_ITEM_USES_CHANGEDsc-ascendant-items.preserveItemUsesChangedPreserve Item Uses changes.

Every payload includes item, itemUuid, the state after the operation in state, and the state before it in previousState. Level-related hooks also include the relevant serialized level and previousLevel values.

levelApplied, levelSelected, and levelAdvanced identify the origin in changeSource: apply, advance, activity, api, or sheet.

Example:

js
const api = game.modules.get("sc-ascendant-items")?.api?.levels;
 
Hooks.on(api.HOOK_LEVEL_ADVANCED, ({ item, previousLevel, level, snapshotApplied }) => {
  console.log("Item advanced:", item?.name, {
    from: previousLevel?.value,
    to: level?.value,
    snapshotApplied,
  });
});

Limits And Safeguards

Explicitly unsupported fields:

  • system.advancement

Fields intentionally excluded from restoration:

  • system.equipped
  • system.attuned
  • system.attunement

That means Apply Level should not be treated as a way to restore equipped or attunement state.

Other important safeguards:

  • if an item already has stored levels, external flag changes should not accidentally disable the workflow
  • if Levels is enabled and levels already exist, the module tries to preserve flags.sc-ascendant-items.data
  • active level and last applied level are stored separately
  • if you change the item after capture and want that state saved, you must capture again