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
- 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 - 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.
The settings hub is the entry point for socket rules, socketable item types, gem subtype setup, documentation, and support actions.
Main entries:
- Socket settings
- Configure Socketable Item Types
- Configure Gem Loot Subtypes
- Configure Custom Loot Subtypes
- Documentation
- Support the developer
The dedicated Socket settings window groups the main runtime behavior.
This window controls permissions, socket limits, gem removal behavior, and how the socket UI is presented.
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. |
| Gem damage layout in roll dialog | How extra gem damage is grouped in the dnd5e damage roll configuration dialog. |
| Socket tab layout | Whether the Sockets tab uses the default list layout or the grid layout. |
The gem damage layout setting currently supports four modes:
- Group by gem
- Group by damage type
- Group by gem type
- Group by damage type with badges
Socketable host item types are configured separately.
Socketability is controlled globally, so you decide once which item types can receive sockets.
By default, the module allows sockets on:
weaponequipment
Gem identification also starts from a global rule.
Loot items are treated as gems when their subtype matches the configured gem subtype list.
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 custom loot subtypes.
Custom loot subtypes let you extend the gem system without introducing a new Foundry item type.
If Enable Socket Tab on all items is disabled, an eligible item can still opt in from Details.
This per-item toggle matters 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
- 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 host restrictions are checked before insertion
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.
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. |
| `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 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- 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.
addSocketInteractive(options) currently accepts these top-level options:
| Option | Type | Default | What it does |
|---|---|---|---|
| `notifications` | `boolean` | `true` | Shows the selection prompt and the success, warning, or error notifications used by the interactive workflow. |
| `promptSlotConfig` | `boolean` | `false` | Opens the slot-configuration dialog before the socket is created. If it is disabled, the macro uses `slotConfig` as-is after validation. |
| `slotConfig` | `object` | `{}` | Preconfigures the new slot. Use this for default name, description, condition, color, visibility, or gem-removal behavior. |
| `cursorClass` | `string` | module default | Advanced override for the temporary CSS cursor class used while the macro waits for you to click an item. |
| `renderSheet` | `boolean` | `true` | Defined in the workflow defaults, but the current add-slot implementation does not read this field directly. No visible effect is confirmed in this path. |
options.slotConfig accepts these fields:
| Field | Type | Default | What it does |
|---|---|---|---|
| `name` | `string` | `""` | Sets the slot name. If left empty, the slot falls back to the module's normal empty-slot label. |
| `description` | `string` | `""` | Adds the empty-slot description shown before a gem is inserted. |
| `condition` | `string` | `""` | Adds the JavaScript slot condition used to decide whether a gem can enter that socket. |
| `color` | `string` | `""` | Applies a tint to the empty socket. Valid hex colors are normalized to uppercase `#RRGGBB`. |
| `hidden` | `boolean` | `false` | Marks the slot as hidden. This is accepted by the slot config object even though the interactive add-slot dialog does not currently expose a hidden toggle. |
| `deleteGemOnRemoval` | `boolean` | `false` | Makes this slot delete its gem when unsocketed, overriding the global removal behavior for that slot. |
Example: create a slot that always deletes its gem when the gem is removed:
await game.modules.get("sc-simple-sockets")?.api?.macro?.addSocketInteractive({
notifications: true,
slotConfig: {
deleteGemOnRemoval: true
}
});Because promptSlotConfig defaults to false, this version uses the provided
slotConfig directly after validation.
The module API lives at:
game.modules.get("sc-simple-sockets")?.apiCurrent API surfaces:
game.modules.get("sc-simple-sockets")?.api?.sockets?.getItemSlots(itemOrUuid)
game.modules.get("sc-simple-sockets")?.api?.sockets?.getItemGems(itemOrUuid)
game.modules.get("sc-simple-sockets")?.api?.sockets?.removeGem(itemOrUuid, slotIndex)
game.modules.get("sc-simple-sockets")?.api?.sockets?.removeGemKeepingItem(itemOrUuid, slotIndex)
game.modules.get("sc-simple-sockets")?.api?.macro?.addSocketInteractive(options)
game.modules.get("sc-simple-sockets")?.api?.macro?.extractGemInteractive(options)
game.modules.get("sc-simple-sockets")?.api?.macro?.selectItemForSocket(options)
game.modules.get("sc-simple-sockets")?.api?.macro?.removeGemWithoutDeleting(itemOrUuid, slotIndex)The socket API also exposes these hook names:
sc-simple-sockets.socketAdded
sc-simple-sockets.socketRemovedIf 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
- invalid slot-condition code blocks the gem and shows a warning instead of failing silently
- 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 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