SC - Ascendant Items
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
XPorMilestone - 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-sheetand 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:
- Enable SC - Ascendant Items in your world.
- Make sure
lib-wrapperis also active. - Open a supported
dnd5eitem.
Compatibility:
- Foundry VTT
v13tov14 - system:
dnd5e - required dependency:
lib-wrapper - optional integrations:
tidy5e-sheet, SC - Simple Sockets, and SC - More Activities0.5.0or later
Enable Levels On An Item
The module is enabled per item, not globally.
To enable it:
- Open the item sheet.
- Go to Details.
- 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:
- Click Add Level.
- Edit the item into the state you want for that stage.
- Use Capture Level to save the current state into that level.
- Add more levels and repeat as needed.
- 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:
- progression data
- 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
systemfields 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>.usesstill come from the snapshot - rest recovery remains standard
dnd5ebehavior - 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:
Configure Settings > Module Settings > SC - Ascendant ItemsAvailable menus:
| Menu | What it does |
|---|---|
| Open documentation | Opens the SC - Ascendant Items wiki page. |
| Configure XP Bar | Opens the XP bar gradient and animation settings window. |
| Configure Permissions | Opens the role-based player permissions window for levels, snapshots, and progression. |
Player Permissions
All permission settings default to GM Only.
Configurable role thresholds:
GM OnlyAssistant 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:
FlowBreathingWavePulsePing-PongShimmerStepsDual-Layer FlowSpinNeon GlowSparkleScanlineLiquidRadial SweepNoise / 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:
| Operation | What happens | Additional configuration |
|---|---|---|
| Specific Level | Applies one configured destination by its stable level id. | Choose Destination Level. |
| Next Level | Advances one step from the active level. | No destination field is required. |
| Random Level > Uniform Random | Silently chooses one candidate with equal probability. | Choose whether Include Current Level is allowed. |
| Random Level > Roll 1dN | Opens 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 Formula | Rolls 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 Use | Shows 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
- Enable Levels on the item and configure its level snapshots.
- Add an activity and choose Ascendant Items > Change Ascendant Level.
- Choose an Operation and complete the fields for that operation.
- Optional: enable Chain an Activity under After Applying.
- Save and use the activity from the item as you would another
dnd5eactivity.
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:
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 | stringThe 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 | stringThe 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 | stringThe 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 | stringThe ascendant Item document or its UUID.
levelRefstring | number | objectA 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 | stringThe ascendant Item document or its UUID.
levelRefstring | number | objectThe destination level reference.
options.applySnapshotbooleandefault: trueSet false to change only the active level.
options.forcebooleandefault: falseReapplies the snapshot when the requested level is already active.
options.changeSourcestringdefault: apiValue 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 | stringThe ascendant Item document or its UUID.
deltanumber | numeric stringThe signed step count. The value is truncated to a safe integer.
options.applySnapshotbooleandefault: trueSet false to change only the active level.
options.forcebooleandefault: falseAllows reapplying a snapshot when the resolved level is already active.
options.clampbooleandefault: falseStops at the first or last level instead of failing beyond an endpoint.
options.changeSourcestringdefault: apiValue 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 | stringThe 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 | stringThe ascendant Item document or its UUID.
options.applySnapshotbooleandefault: trueSet false to change only the active level.
options.forcebooleandefault: falseAllows reapplying a snapshot when applicable.
options.clampbooleandefault: falseKeeps the item at the first level instead of returning at-first-level.
options.changeSourcestringdefault: apiValue 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 | stringThe ascendant Item document or its UUID.
valuenumber | numeric stringThe absolute XP value or relative delta. Results are limited to a minimum of 0.
options.relativebooleandefault: falseAdds 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 | stringThe 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 | stringThe ascendant Item document or its UUID.
valuebooleanA 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:
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:
{
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:
| Constant | Literal hook | When it fires |
|---|---|---|
HOOK_LEVEL_ADDED | sc-ascendant-items.levelAdded | A level is added. |
HOOK_LEVEL_SELECTED | sc-ascendant-items.levelSelected | The active level changes without restoring a snapshot. |
HOOK_CURRENT_XP_UPDATED | sc-ascendant-items.currentXpUpdated | Current XP changes. |
HOOK_LEVEL_ADVANCED | sc-ascendant-items.levelAdvanced | Advance Level, advanceLevel(), or the activity advances one position. |
HOOK_LEVEL_METADATA_UPDATED | sc-ascendant-items.levelMetadataUpdated | A level value, label, XP threshold, or milestone changes. |
HOOK_LEVEL_DELETED | sc-ascendant-items.levelDeleted | A level is deleted. |
HOOK_LEVEL_CAPTURED | sc-ascendant-items.levelCaptured | Capture Level replaces a snapshot. |
HOOK_LEVEL_APPLIED | sc-ascendant-items.levelApplied | Any workflow restores a snapshot. |
HOOK_MODE_CHANGED | sc-ascendant-items.modeChanged | Progression changes between XP and Milestone. |
HOOK_PRESERVE_ITEM_USES_CHANGED | sc-ascendant-items.preserveItemUsesChanged | Preserve 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:
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.equippedsystem.attunedsystem.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