SC - Simple Sockets
SC - Simple Sockets
Overview
SC - Simple Sockets adds a socket workflow to D&D 5e items in Foundry.
The module treats configured loot items as gems, lets compatible host items receive socket slots, and then transfers gem behavior into the host item when a gem is inserted.
What the module currently covers:
- drag-and-drop gem socketing
- configurable socketable host item types
- gem definitions based on loot subtypes
- automatic transfer of Active Effects
- automatic mirroring of Activities
- optional gem combat data in +Details
- optional named resources with current and maximum charges
- reusable gem tags for socket conditions
- activity consumption from one gem, one host item, or a character-wide socket pool
- per-slot descriptions, tint colors, visibility, and JavaScript conditions
- socket feedback on item sheets, actor inventories, activity lists, and the damage roll dialog
- support for the default dnd5e item sheet and Tidy5e Sheet
Compatibility and Installation
This module is free.
Install it through Foundry with this manifest URL:
https://github.com/Shattered-Codex/sc-simple-sockets/releases/latest/download/module.jsonCompatibility:
- Foundry VTT
v13andv14 - system:
dnd5e - recommended dependency:
libWrapper - recommended integration: SC More Activities
- optional sheet integration:
Tidy5e Sheet
After installing:
- Enable SC - Simple Sockets in your world.
- Open Configure Settings > Module Settings > SC - Simple Sockets.
- Configure socketable host item types.
- Configure which loot subtypes count as gems.
- Create or import a few test gems.
- Test the workflow on one host item before expanding your content library.
Settings and Setup
Most setup starts in Configure Settings > Module Settings > SC - Simple Sockets. Under Module configuration, select Open configuration.
The Simple Sockets — Configuration window replaces the older collection of separate settings dialogs. It keeps all module options in four sidebar tabs: Socket rules, Display, Item types, and Gem subtypes.
Changes are not applied until you select Save Changes. Reset defaults resets only the active tab, while the status pill marks unsaved or saved state.
Main rules and display settings:
| Setting | What it controls |
|---|---|
| Edit Socket Permission | The minimum Foundry role required to add or remove sockets. |
| Maximum Number of Sockets per Item | The socket limit for each item. Use `-1` for unlimited sockets. |
| Delete Gem on Removal | Whether unsocketing destroys the gem or returns it to inventory by default. |
| Enable Socket Tab on all items | Whether every socketable item shows the Sockets tab automatically. |
| Socket tab layout | Whether the Sockets tab uses the default list layout or the grid layout. |
| Gem damage layout in roll dialog | How extra gem damage is grouped in the dnd5e damage roll configuration dialog. |
| Gem damage in the sheet Formula column | Whether socketed gem damage is listed inline or grouped in the character-sheet Formula column. |
| Show gem image in the Formula breakdown | Whether the Formula breakdown identifies gems with a small image instead of their name. |
| Show gem badges in Favorites | Whether Favorites rows show badges for gems socketed into those items. |
The gem damage layout setting supports four modes:
- Group by gem
- Group by damage type
- Group by gem type
- Group by damage type with badges
By default, the module allows sockets on:
weaponequipment
By default, a gem is:
- an item of type
loot - with subtype
gem
If you want alternate gem families such as runes or shards, add them under Custom loot subtypes. New custom entries appear in the selectable subtype list immediately, but they are not committed until you save the configuration.
If Enable Socket Tab on all items is disabled, an eligible item can still opt in from Details.
Use Enable Socket Tab on that item's Details tab when you want sockets on selected items only instead of every valid host item.
Build Gems
Gem authoring uses normal dnd5e loot items plus the module's extra controls.
Each gem can define:
- its accepted loot subtype
- one or more descriptions
- Active Effects
- Activities
- +Details combat data
- a Socketed Resource with current and maximum charges
- reusable Gem Tags
- Allowed Item Types
Practical gem behavior:
- gem Active Effects are applied to the host item
- gem Activities are mirrored to the host item
- gem +Details data can add extra damage and attack modifiers
- gem resources can provide charges while the gem is socketed
- gem tags can be checked by slot conditions without depending on the gem name
- gem host restrictions are checked before insertion
Gem Tags and Socketed Charges
The module-added +Details tab is divided into three panes. A dot marks a configured Combat or Resource pane, while Tags shows its current tag count.
| Pane | Fields | Purpose |
|---|---|---|
| Combat | Critical Threshold, Critical Multiplier, Attack Bonus, Extra Damage | Adjusts attacks and adds one or more damage entries while the gem is socketed. |
| Resource | Resource Key, Current, Maximum, Recharges on, Recovery, Destroy when out of charges | Stores limited charges on the gem and defines how they recover or expire. |
| Tags | Gem Tags | Stores normalized identifiers for slot conditions, macros, and integrations. |
All three panes are optional. Existing gems continue to work without combat overrides, tags, or a socketed resource.
Add charges to a gem
A gem can carry a named resource such as energy, battery, or magic. The
current and maximum values remain on that gem instead of being copied to the host
item or actor.
- Open the gem item.
- Open +Details.
- Under Socketed Resource, enter a short Resource Key such as
battery. - Set Current and Maximum.
- Choose Recharges on and Recovery if the gem should recover or lose charges automatically. Leave the period at Never (manual only) for a manually managed resource.
- Optionally enable Destroy when out of charges if consumption should destroy and remove the gem when its last charge is spent.
The resource is available only while the gem is socketed. If the gem is removed
and returned to inventory, it keeps its remaining charges. Setting the current
value to 0 manually does not trigger Destroy when out of charges; that option
applies when activity consumption drains the gem to zero.
Organize gems with tags
Tags provide stable categories for socket rules. This lets differently named gems
share a tag such as fire, poison, healing, or dynamo-battery.
- Open the gem's +Details tab.
- Add one or more values under Gem Tags.
- Open a socket's settings and reference the tag in Slot condition.
Tags are normalized automatically: uppercase becomes lowercase, accents are
removed, and spaces become hyphens. For example, Dynamo Battery becomes
dynamo-battery.
To accept only gems tagged fire, use:
return hasGemTag("fire");Socket Items
Once your world has valid gems and valid host items, the main socketing workflow is straightforward:
- Open a compatible host item.
- Open the Sockets tab.
- Add one or more empty slots.
- Drag a gem into an empty slot.
At insertion time, the module validates:
- whether the dropped item is a configured gem
- whether the host item type is socketable
- whether the gem allows that host item type or subtype
- whether the slot's custom condition accepts the gem
When a gem is removed, the result depends on the active removal mode:
- if gem deletion is enabled, the gem is destroyed
- otherwise the gem is extracted back into inventory
That behavior can come from the global Delete Gem on Removal setting or from a per-slot override.
Holding Shift while removing a gem or deleting a slot skips the confirmation prompt.
Spend Socketed Charges
Activities can use the Socketed Charges consumption type to spend a gem's resource. In the activity's consumption settings, choose where the charges come from:
| From | What it spends |
|---|---|
| Source gem (this activity) | Charges from the gem that provided the activity. |
| Any gem with resource | The named resource from compatible socketed gems, in slot order. |
| Specific slot | Charges from one socket position on the activity's item. |
| Gem by name | Charges from socketed gems with that exact name. |
| Gem name matches | Charges from gems found by a simple name pattern such as `Fire*`. |
For compatible target modes, Pool scope controls which host items contribute:
| Pool scope | Included hosts |
|---|---|
| Sockets on this item | Only the item that owns the activity. |
| Equipped sockets on this character | Socketed items on the same actor whose equipped state is active. |
| All sockets on this character | Every socketed item on the same actor, including unequipped items. |
Character pools are calculated from the socketed gems; they are not a second balance stored on the actor. Consumption checks the activity's item first, then the actor's other eligible items and their sockets in order. If the complete pool cannot pay the cost, the activity is blocked instead of partially spending it.
The optional SC More Activities integration also provides socket activities for inserting and extracting gems, recharging one gem, or recharging a shared resource pool.
Filled resource gems add a summary table below the slots. Current charges remain on each gem, even when several gems share the same resource key.
Open a filled slot's settings to edit that gem's current charges or recovery configuration. The maximum still comes from the gem's +Details > Resource pane.
Filter host items in a character pool
Host item filter is an optional JavaScript condition on a socket consumption target. It is separate from Slot condition: the slot condition decides whether a gem may be inserted, while the host item filter decides which socketed items may contribute to an activity's charge pool.
The filter receives these useful values:
| Variable | What it represents |
|---|---|
| `item` or `hostItem` | The candidate socketed host item. |
| `sourceItem` | The item that owns the activity. |
| `actor` | The actor that owns the source item and candidate hosts. |
| `activity` | The activity performing the consumption. |
| `user` and `game` | The current Foundry user and game context. |
| `getProperty` and `hasProperty` | Helpers for safely checking nested data paths. |
A truthy result includes the candidate host; a falsy result excludes it. Both an
expression and a block with return are accepted. Invalid code or a runtime error
blocks the entire consumption so charges are not taken from an unintended item.
Host Item Filter Examples
Choose a starting point, then adapt the checked item paths to your world's data.
Use only weapon hosts
Restrict a character pool to socketed weapons and ignore armor or other supported host types.
return item?.type === "weapon";Exclude the activity's own item
Draw from other eligible socketed items on the actor without using charges from the item that owns the activity.
return item?.id !== sourceItem?.id;Match a custom pool group
Use this when both source and host items already carry the same campaign-defined world flag.
const group = getProperty(sourceItem, "flags.world.socketPool");
return Boolean(group)
&& getProperty(item, "flags.world.socketPool") === group;Match the source item's SC Setforge set
With Equipped sockets on this character, include only equipped socket hosts that belong to the same SC Setforge set as the source item.
const sourceSet = getProperty(sourceItem, "flags.sc-setforge.setId");
return Boolean(sourceSet)
&& getProperty(item, "flags.sc-setforge.setId") === sourceSet;Socket Formulas and Native Item Uses
SC - Simple Sockets adds two different formula families to dnd5e roll data.
Keep them separate: @sockets... reads named charges stored on gems, while
@sc.sockets... counts slots and inserted gems.
Bind Limited Uses to a named gem resource
For a resource named Soul Harvest, use its normalized key
soul-harvest in Details > Usage > Limited Uses > Max:
| Formula | Maximum capacity |
|---|---|
| `@sockets.soul-harvest.item` | That resource on the current item only. |
| `@sockets.soul-harvest.total` | That resource across all items owned by the actor, including unequipped items. |
Use one of these exact formulas to bind native Item Uses to the gem pool. The module derives Spent from the gems and deducts the activity's Item Uses cost from them in a stable order. If the activity also has an explicit Socketed Charges target, that target owns the deduction so the cost is not charged twice.
Native dnd5e Limited Uses recovery does not recharge the underlying gems.
Recharge those gems through their resource controls or a socket recharge
activity; the derived Spent value then updates automatically.
Count slots and socketed gems
Socket counts are live formula values:
| Formula | Value |
|---|---|
| `@sc.sockets.total` | All slots on this item. |
| `@sc.sockets.gems` | Filled slots on this item. |
| `@sc.sockets.empty` | Empty slots on this item. |
| `@sc.sockets.actor.total` | All slots across the actor's items. |
| `@sc.sockets.actor.gems` | Filled slots across the actor's items. |
| `@sc.sockets.actor.empty` | Empty slots across the actor's items. |
Setting Limited Uses Max to exactly @sc.sockets.gems or
@sc.sockets.total makes the item's native Item Uses capacity follow that
count. Configure recovery on the item, not on the consuming activity. The
module keeps the remaining uses stable when capacity changes, clamping only
when the new maximum is smaller; newly added capacity starts empty until it is
recovered.
The same paths can be used in an Active Effect change value. For example,
system.attributes.ac.bonus with mode Add and value
@sc.sockets.gems grants +1 AC per filled socket on the item carrying the
effect. Arithmetic such as @sc.sockets.gems * 2 is supported. Effects placed
directly on an actor have no item scope, so use an .actor.* path there.
Slot Settings and Slot Conditions
Each socket can carry its own configuration instead of behaving like every other slot on the item.
Per-slot settings currently include:
| Setting | What it does | Notes |
|---|---|---|
| Slot name | Overrides the visible slot name. | If left blank, the slot falls back to `Empty` while empty or the gem name while filled. |
| Hide slot | Hides the slot from non-GM users. | The empty-slot description is also GM-only while the slot is hidden. |
| Delete gem on removal | Overrides the normal gem-removal behavior for that slot. | If enabled, removing a gem from that slot deletes it even when the global setting would normally return it. |
| Slot condition | Runs an extra JavaScript rule before a gem can be inserted. | An empty condition means there is no extra slot-specific restriction. |
| Slot description | Shows custom text for that slot while it is empty. | Once a gem is inserted, the gem's own socket description takes over. |
| Slot color | Applies a custom tint to the empty socket frame. | This is visual only and affects the empty socket state, not the inserted gem. |
Slot Condition
Slot condition is the advanced rule field for deciding whether a specific gem can enter a specific socket.
If the field is empty, the slot accepts any gem that already passed the module's normal checks.
If the field contains code:
- a truthy result allows the gem
- a falsy result blocks the gem
- invalid code or runtime errors also block the gem and show a warning
Both styles work:
gem?.name?.toLowerCase().includes("ruby")return gem?.name?.toLowerCase().includes("ruby");Available variables:
| Variable | Use it for | Notes |
|---|---|---|
| `gem` or `gemItem` | Checking the gem being inserted. | Use this for name, rarity, flags, or subtype checks. |
| `gemTags` | Reading all normalized tags on the gem. | This is an array such as `["fire", "legendary"]`. |
| `hasGemTag(tag)` | Checking one normalized gem tag. | Prefer this helper when a rule needs a single stable category. |
| `hostItem` or `item` | Checking the receiving item. | Useful when the same gem should behave differently on weapons, armor, or other host items. |
| `actor` | Checking the owning actor. | This is most useful when the host item belongs to an actor instead of a world item. |
| `user` | Checking the current Foundry user. | Advanced use only. Most socket rules should not depend on the user. |
| `slot` | Inspecting the current slot data. | This is a slot snapshot, not the gem document itself. |
| `slotConfig` | Reading the slot's own configured fields. | Useful when your logic depends on the slot name, description, color, or flags already stored there. |
| `slotIndex` | Checking which slot is being targeted. | This is zero-based, so the first slot is `0`. |
| `source` | Inspecting workflow source data when provided. | Advanced use only. This may be `null` depending on how the insertion started. |
| `getProperty` and `hasProperty` | Safely reading deep data paths. | Use these when the field may not exist on every gem. |
| `deepClone` | Cloning context data before changing it in custom logic. | Most conditions do not need this helper. |
Basic Condition Examples
These examples all assume the slot already passed the module's normal checks for gem identity, host compatibility, and socketability.
Example Filters
Search within this example list without affecting the rest of the page.
Require a name fragment
Use this when a slot should accept only gems whose name contains a specific word such as Ruby, Rune, Frost, or Bloodstone.
return gem?.name?.includes("Ruby");Require a gem tag
Use a stable category instead of tying the socket rule to a gem's visible name.
return hasGemTag("fire");Require a specific rarity
Use this when the slot should reserve itself for stronger gems and reject common or uncommon ones.
return getProperty(gem, "system.rarity") === "rare";Require minimum Intelligence
Use this when a gem should only be socketed by an actor with enough Intelligence to handle arcane or technical gems.
return (actor?.system?.abilities?.int?.value ?? 0) >= 16;Require both rarity and name
Use this for curated signature gems where the slot should only accept a named gem family at a specific power tier.
return gem?.name?.includes("Ruby") && getProperty(gem, "system.rarity") === "rare";Require an active effect on the actor
Use this when socketing should only work while the actor is under a specific buff, blessing, stance, or temporary state.
return actor?.effects?.some?.((effect) => effect.name === "Arcane Focus" && !effect.disabled);Require another gem already socketed
Use this when a slot should only unlock after the host item already contains a prerequisite gem.
const sockets = getProperty(hostItem, "flags.sc-simple-sockets.sockets") ?? [];
return sockets.some((entry) => (entry?.gem?.name ?? entry?._gemData?.name) === "Ruby");Writing Tips
- Start with the simplest rule that solves the slot restriction.
- Prefer
getProperty(...)when a field may not exist on every gem. - Use
slotIndexfor position-based rules andgemfor gem-data rules. - If a condition becomes hard to read, split the logic into several named checks inside the code block before returning the final result.
- If the code is invalid or throws an error at runtime, the module blocks the gem and shows a warning instead of failing silently.
UI Feedback
The module surfaces socket state outside the Sockets tab as well.
This feedback appears on:
- the standard
dnd5eitem sheet Tidy5e Sheetitem tabs and descriptions- the host item's Sockets tab and Socket Descriptions block, including charge values
- actor inventory rows
- item activity lists
- the damage roll configuration dialog
API and Included Content
The module ships with included content and an exposed API.
Included from module.json:
- one item compendium with socket-ready gem content
- one macro compendium for socket workflows
Create Slots with the Included Macro
If you want to add sockets without opening each item sheet first, import a macro from the SC - Simple Sockets Macro compendium.
Current included macro examples include:
- Add Socket Slot to Item
- Add Conditional Socket Slot to Item
The standard add-slot workflow uses the same interactive helper exposed by the module API:
- Run Add Socket Slot to Item from your hotbar or macro directory.
- Click a supported item anywhere in the Foundry UI.
- Confirm the prompt to add the new socket.
The workflow shows Click an item to add a socket. Press Esc to cancel. while selection is active.
Use Add Conditional Socket Slot to Item when you want the new slot to start with predefined rules such as a name, description, color, or slot condition.
Public API reference
The module registers its public API during Foundry's ready hook. Call it from
a macro or integration after the world is ready:
const api = game.modules.get("sc-simple-sockets")?.api;
const sockets = api?.sockets;
const macroApi = api?.macro;Every socket API method is asynchronous. itemOrUuid accepts an Item document
or an Item UUID. Slot indexes are zero-based: 0 is the first socket.
Socket API methods and parameters
Expand a method to see what each parameter accepts, its default value, and the returned value.
getItemSlots(itemOrUuid, options?)Lists every socket on an item, including empty slots.
Parameters
itemOrUuidItem | stringThe host Item document or its UUID.
options.includeSnapshotsbooleandefault: falseWhen true, keeps the internal _gemData snapshot inside each returned slot. Leave false unless an integration needs the stored gem data.
Returns
Promise<Array<{ slotIndex, hasGem, slot }>>. Returns an empty array when the item cannot be resolved.
getItemGems(itemOrUuid, options?)Lists only the gems currently inserted into the host item.
Parameters
itemOrUuidItem | stringThe host Item document or its UUID.
options.includeSnapshotsbooleandefault: falseIncludes the stored _gemData snapshot inside each returned slot when true.
Returns
Promise<Array<{ slotIndex, name, img, tags, uuid, sourceUuid, slot }>>. Tags are normalized; uuid and sourceUuid are currently null.
hasItemGemTag(itemOrUuid, tag)Checks whether at least one inserted gem has a matching normalized tag.
Parameters
itemOrUuidItem | stringThe host Item document or its UUID.
tagstringThe tag to search for. The module normalizes spaces and casing, so Dynamo Battery matches dynamo-battery.
Returns
Promise<boolean>. Returns false for an unresolved item or an empty tag.
canEditSockets(itemOrUuid, options?)Checks whether a user is allowed to modify sockets on an item.
Parameters
itemOrUuidItem | stringThe host Item document or its UUID.
options.userIdstring | nulldefault: nullThe Foundry user ID to check. When omitted, checks the current user.
Returns
Promise<boolean>. GM status, the module permission setting, and Item ownership are considered.
addSlot(itemOrUuid, options?)Creates one empty socket at the end of the host item's socket list.
Parameters
itemOrUuidItem | stringThe socketable host Item document or its UUID.
options.slotConfigobjectdefault: {}Configures name, description, condition, color, hidden, and deleteGemOnRemoval for the new slot.
options.bypassPermissionbooleandefault: falseBypasses the module edit-permission check. Use only in trusted automation.
options.bypassWorldSocketLimitbooleandefault: falseAllows this call to exceed Maximum Number of Sockets per Item.
options.ignoreMaxSocketsbooleandefault: falseAlias for bypassWorldSocketLimit.
options.notifybooleandefault: trueSet false to suppress module notifications.
Returns
Promise<Result>. On success, data contains the zero-based slotIndex and the new totalSlots.
Example
const result = await sockets.addSlot(item, { slotConfig: { name: 'Ruby Socket', color: '#9f1239' } });removeSlot(itemOrUuid, slotIndex, options?)Low-level removal for a socket that the caller has already confirmed is empty.
Parameters
itemOrUuidItem | stringThe host Item document or its UUID.
slotIndexnumberZero-based index of an empty socket.
options.bypassPermissionbooleandefault: falseBypasses the module edit-permission check.
Returns
Promise<Result>. Success data contains slotIndex and totalSlots. This method does not clean up a filled slot; use removeSlotWithContents whenever contents may exist.
removeSlotWithContents(itemOrUuid, slotIndex, options?)Removes a socket and first cleans up its inserted gem, effects, and activities.
Parameters
itemOrUuidItem | stringThe host Item document or its UUID.
slotIndexnumberZero-based index of the socket to remove.
options.modestringdefault: defaultGem removal mode: default follows settings, keep returns the gem, and delete destroys it.
options.bypassPermissionbooleandefault: falseBypasses the module edit-permission check.
options.notifybooleandefault: trueSet false to suppress the gem-removal notification when a filled slot is cleaned up.
Returns
Promise<Result>. The gem follows the selected removal mode before the socket is deleted.
addGem(itemOrUuid, gemOrUuid, slotIndex?, options?)Inserts a compatible gem and transfers its supported behavior to the host item.
Parameters
itemOrUuidItem | stringThe host Item document or its UUID.
gemOrUuidItem | stringThe gem Item document or its UUID. It must be recognized as a configured gem.
slotIndexnumber | nulldefault: nullZero-based target slot. When omitted, the first empty slot is used; the API does not skip a conditionally rejected first empty slot.
options.notifybooleandefault: trueControls module notifications.
options.bypassPermissionbooleandefault: falseBypasses the module edit-permission check.
Returns
Promise<Result>. Compatibility, allowed-item-type, and slot-condition checks still apply; successful data contains slotIndex.
Example
const result = await sockets.addGem(item, gem); // first empty slotremoveGem(itemOrUuid, slotIndex, options?)Extracts a gem from a filled socket and removes its transferred behavior.
Parameters
itemOrUuidItem | stringThe host Item document or its UUID.
slotIndexnumberZero-based index of a filled socket.
options.modestringdefault: defaultUse default for slot/world settings, keep to return the gem, or delete to destroy it.
options.notifybooleandefault: trueSet false to suppress the unsocketed notification.
options.bypassPermissionbooleandefault: falseBypasses the module edit-permission check. Use only for trusted automation.
Returns
Promise<Result>. Success reason is gem-removed.
removeGemKeepingItem(itemOrUuid, slotIndex, options?)The explicit keep variant of removeGem.
Parameters
itemOrUuidItem | stringThe host Item document or its UUID.
slotIndexnumberZero-based index of a filled socket.
optionsobjectdefault: {}Additional removal options. The method always overrides mode to keep.
Returns
Promise<Result>. The gem is returned to the actor inventory instead of being deleted.
updateSlotConfig(itemOrUuid, slotIndex, config?, options?)Updates one existing socket without replacing its inserted gem.
Parameters
itemOrUuidItem | stringThe host Item document or its UUID.
slotIndexnumberZero-based index of the socket to update.
configobjectdefault: {}Fields are name, description, condition, color, hidden, and deleteGemOnRemoval. Hex colors normalize to uppercase #RRGGBB.
options.bypassPermissionbooleandefault: falseBypasses the module edit-permission check.
Returns
Promise<Result>. Success reason is slot-config-updated.
Use removeSlot only after confirming the target slot is empty. It removes the
stored slot directly and does not perform gem, effect, or activity cleanup.
removeSlotWithContents is the safe general-purpose choice when the slot may be
filled.
Mutation methods return this stable shape:
{
success: true,
changed: true,
reason: "slot-added",
data: { slotIndex: 0, totalSlots: 1 }
}Common reason values include slot-added, slot-removed,
slot-not-removed, gem-added, gem-removed, slot-config-updated,
slot-config-not-updated, item-not-found, invalid-slot-index, empty-slot,
no-available-slot, cannot-resolve-item, host-not-socketable, not-a-gem,
gem-incompatible, socket-condition-failed, socket-condition-error,
permission-denied, and max-sockets-reached. Check success before using
data.
Common mutation options are:
| Option | Type and default | Effect |
|---|---|---|
| `bypassPermission` | `boolean`, `false` | Bypasses the module's socket-edit permission check. Use only for trusted automation. |
| `bypassWorldSocketLimit` | `boolean`, `false` | Allows `addSlot` to ignore the configured maximum. |
| `ignoreMaxSockets` | `boolean`, `false` | Alias accepted by the module for bypassing the configured maximum. |
| `notify` | `boolean`, default enabled | Set to `false` to suppress notifications on methods that emit them. |
| `mode` | `"default"`, `"keep"`, or `"delete"` | Controls gem removal. `default` follows slot and world settings. |
| `slotConfig` | `object`, `{}` | Used by `addSlot`; fields are `name`, `description`, `condition`, `color`, `hidden`, and `deleteGemOnRemoval`. |
Slot colors accept three- or six-digit hexadecimal values and are normalized to
uppercase #RRGGBB. Slot conditions are JavaScript expressions evaluated by the
module; invalid code blocks the operation.
API examples
Add a configured socket and inspect the result:
const sockets = game.modules.get("sc-simple-sockets")?.api?.sockets;
const result = await sockets?.addSlot(item, {
slotConfig: {
name: "Ruby Socket",
description: "Accepts one adornment ruby.",
condition: "return hasGemTag('adornment-ruby');",
color: "#9f1239",
deleteGemOnRemoval: false
}
});
if (!result?.success) {
ui.notifications.warn(`Could not add socket: ${result?.reason}`);
}Insert a gem into the first empty slot, or choose slot 1 explicitly:
const automatic = await sockets.addGem(item, gem);
const selected = await sockets.addGem(item.uuid, gem.uuid, 1);
console.log(automatic.data?.slotIndex, selected.data?.slotIndex);Remove a gem while always returning it to the actor's inventory:
const result = await sockets.removeGemKeepingItem(item.uuid, 0);
if (result.success) console.log("Gem removed and kept.");Check a normalized gem tag in a conditional activity:
const sockets = game.modules.get("sc-simple-sockets")?.api?.sockets;
return sockets && await sockets.hasItemGemTag(item, "Dynamo Battery");Interactive macro API
The macro API is intended for workflows that ask the user to select an item or socket in the Foundry interface:
Interactive macro API parameters
Expand a method to see what each parameter accepts, its default value, and the returned value.
addSocketInteractive(options?)Waits for the user to click a supported item, then adds a socket after confirmation.
Parameters
options.notificationsbooleandefault: trueShows the selection, success, warning, and error notifications.
options.promptSlotConfigbooleandefault: falseOpens the slot configuration dialog before creating the socket.
options.slotConfigobjectdefault: {}Default name, description, condition, color, visibility, and removal behavior for the new slot.
options.cursorClassstringOptional CSS cursor class used during item selection.
options.cursorUrlstringdefault: ""Optional image URL used as the selection cursor.
options.bypassWorldSocketLimitbooleandefault: falseAllows the interactive workflow to exceed the configured maximum.
options.ignoreMaxSocketsbooleandefault: falseAlias for bypassWorldSocketLimit.
options.targetValidatorfunctiondefault: nullOptional async validator. Return false or { ok: false } to reject the selected item.
Returns
Promise<{ success, reason, item? }>. Cancellation returns reason cancelled; a successful workflow returns reason added.
Example
await macroApi.addSocketInteractive({ promptSlotConfig: true });extractGemInteractive(options?)Lets the user click a filled socket and extracts its gem without deleting it.
Parameters
options.notificationsbooleandefault: trueShows selection, cancellation, success, and error notifications.
Returns
Promise<{ success, reason, item?, slotIndex?, gemName? }>. The extracted gem is always kept.
selectItemForSocket(options?)Activates the item-selection cursor used by interactive socket workflows.
Parameters
options.notificationsbooleandefault: trueShows the selection prompt.
options.cursorClassstringOptional CSS cursor class.
options.cursorUrlstringdefault: ""Optional cursor image URL.
options.messageKeystringOptional localization key for the selection prompt.
options.messageFallbackstringOptional fallback prompt when messageKey is not localized.
Returns
Promise<Item | null>. Resolves the clicked Item document, or null when the selection is cancelled.
removeGemWithoutDeleting(itemOrUuid, slotIndex, options?)Removes a gem by API coordinates while forcing the keep behavior.
Parameters
itemOrUuidItem | stringThe host Item document or its UUID.
slotIndexnumberZero-based index of the filled socket.
optionsobjectdefault: {}Additional removal options. mode is always overridden to keep.
Returns
Promise<Result>. The gem is returned to the actor inventory.
Example:
await game.modules.get("sc-simple-sockets")?.api?.macro?.addSocketInteractive({
notifications: true,
promptSlotConfig: true,
slotConfig: {
name: "Runeword Socket",
description: "Accepts one curated rune.",
color: "#C44D24"
}
});The hook constants are also exposed through api.sockets:
const sockets = game.modules.get("sc-simple-sockets")?.api?.sockets;
console.log(sockets.HOOK_SOCKET_ADDED); // "sc-simple-sockets.socketAdded"
console.log(sockets.HOOK_SOCKET_REMOVED); // "sc-simple-sockets.socketRemoved"Both hooks receive an object with item, itemId, itemUuid, actor,
actorId, slotIndex, slot, totalSlots, and userId. The slot value is
a cloned socket snapshot from before removal or after creation.
Use the same names with Foundry's Hooks.on:
Hooks.on("sc-simple-sockets.socketAdded", ({ item, slotIndex, totalSlots }) => {
console.log(`Socket ${slotIndex} added to ${item?.name}; total: ${totalSlots}`);
});
Hooks.on("sc-simple-sockets.socketRemoved", ({ item, slotIndex, totalSlots }) => {
console.log(`Socket ${slotIndex} removed from ${item?.name}; total: ${totalSlots}`);
});If you want ready-made expansion content instead of building every gem by hand, see SC - More Gems.
Troubleshooting and Notes
Useful current behaviors and limits:
- gems are still normal
lootitems, so gem identity starts from loot subtype rules instead of a new item type containeris intentionally excluded from the socketable item-type picker- if global socket-tab visibility is disabled, items that already have sockets keep their local socket-tab access
- gems with the same resource key contribute to one calculated pool; the host item and actor do not store a duplicate charge balance
- manually setting a gem to zero charges does not trigger Destroy when out of charges
- Source gem and Specific slot consumption stay on the activity's own item even when a character-wide scope is selected
- invalid slot-condition code blocks the gem and shows a warning instead of failing silently
- invalid Host item filter code blocks the entire consumption instead of falling back to a broader pool
- replacing a gem removes the previous gem's transferred effects and mirrored activities before applying the new one
Troubleshooting checks:
- if an item cannot receive sockets, verify its type is enabled in Configure Socketable Item Types
- if an item is not recognized as a gem, verify its
lootsubtype is included in Configure Gem Loot Subtypes - if the Sockets tab is missing, check the global Enable Socket Tab on all items setting and then the per-item Enable Socket Tab toggle in Details
- if a gem is rejected by one slot only, inspect that slot's Slot condition
- if a gem does not contribute charges, verify that Resource Key is not blank and that the activity uses the same key
- if a character pool misses an item, verify the selected Pool scope; the equipped scope only includes items currently marked as equipped
- if filtered consumption finds no charges, check Host item filter separately from the socket's Slot condition
- if gem damage looks confusing in the roll dialog, change Gem damage layout in roll dialog and compare the four layouts
- if you need deeper debugging, enable Debug trace logging in module settings and inspect the browser console
Client-side notes:
- the module can show an automatic What's New popup after updates
- Hide automatic What's New popup until next update controls whether that popup stays hidden after you acknowledge it