A Swift package providing reusable core logic for role-playing games. It is a work in progress — capabilities are added incrementally.
The short-term goal is to cover the key moving parts of a tabletop RPG character: species, class, background, ability scores, skills, spells, equipment, and the random-generation plumbing that ties them together. The architecture is designed to be flexible enough to support the SRD 5.2.1 and similar game systems, and to minimize upstream dependencies.
The library is a generic Swift Package. The included CharacterGenerator example app demonstrates iOS/macOS usage with a full SwiftUI character-builder workflow.
RolePlayingCore depends on SwiftDice, which provides the Rollable protocol, dice types (Dice, CompoundDice, …), and a dice-notation parser.
The source code is grouped into the following modules under Sources/RolePlayingCore:
| Group | What's inside |
|---|---|
| Common | Height, Weight, CharacterNames, Named & DisplayOrdered protocols |
| Configuration | GameData, GameDataFiles, GameDataError, Bundle+JSONFile |
| Creature | StatLine |
| Currency | UnitCurrency, Money, Currencies |
| Items | Item, Weapon, Armor, Gear, Tool, EquipmentOptions, InventoryEntry, damage types, weapon properties |
| Player | Player, Players, PlayerAppearance, AppearanceTraitKey, DescriptiveTraitKey, Ability, Alignment, ClassTraits/Classes, SpeciesTraits/Species, BackgroundTraits/Backgrounds, Skill/Skills, FeatTraits/Feats, SubclassTraits, UnarmoredDefense, CreatureSize, CreatureType, Initiative |
| Spellcasting | Spell/Spells, SpellcastingType, Spellbook |
| CharacterGenerator | CharacterGenerator, NameGenerator |
Examples/CharacterGenerator is a SwiftUI iOS/macOS app that demonstrates the full library. It loads all game data from JSON at launch via GameData and provides:
- A character builder — a step-by-step navigation flow for choosing species, class, background, ability scores, skills, and spells, finishing with a name
- A player list with a detail sheet showing abilities, skills, inventory, and spells
- Random character generation using
CharacterGenerator
All game content is stored in JSON files and decoded at launch by GameData. The configuration entry point is a manifest JSON (e.g. Configuration.json) that lists the file names to load for each content type:
{
"currencies": ["Currencies"],
"skills": ["Skills"],
"feats": ["Feats"],
"spells": ["Spells"],
"items": ["Items"],
"backgrounds": ["Backgrounds"],
"creature types": ["CreatureTypes"],
"species": ["Species"],
"classes": ["Classes"]
}Collection types (Backgrounds, Classes, Species) decode via Apple's CodableWithConfiguration protocol, which threads the partially-loaded GameData context through the decoder so nested types (equipment, skills, spells) can resolve cross-references during decoding.
Collections support an optional "display order" key in their JSON. When present, allByDisplayOrder returns elements in that order (with alphabetical fallback for unlisted names). This is exposed through the DisplayOrdered protocol, which Backgrounds, Classes, and Species all conform to.
Each class entry in Classes.json can carry an optional "default background" key. The character builder uses this to pre-select the most thematically appropriate background when a class is chosen.
Named— protocol requiringvar name: String. Adopted byBackgroundTraits,ClassTraits, andSpeciesTraits.DisplayOrdered— protocol for collections that have adisplayOrder: [String]and anall: [Element]array. Provides a defaultallByDisplayOrdercomputed property that sorts by the display order array and falls back alphabetically.Height/Weight— typealiases and string-parsing helpers built onFoundation.Measurement.CharacterNames— loads first and last name lists from JSON for use byNameGenerator.
GameData— the top-level loader. Initialized with a bundle and a manifest filename; loads all content types in dependency order. Content is accessed via properties such asgameData.classes,gameData.backgrounds,gameData.spells.GameDataFiles—Decodablemanifest struct describing which JSON files to load for each content type.GameDataError— typed errors thrown during loading (missing file, decode failure, etc.).
StatLine— a compact creature stat line as printed in an adventure key (armor class, hit dice, hit points, attacks per round, damage, and a catch-allspecialstring), with asummarycomputed property that reconstructs the printed line from its fields when no verbatimtextwas supplied. Used by downstream packages such as DungeonCore to describe monsters in keyed encounters.
-
UnitCurrency— a denomination's symbol, exchange rate (coefficient, relative to the base unit), singular/plural names, and whether it's the game system's default (base) currency. Equatable/Hashable by symbol. -
Currencies— a collection ofUnitCurrencyloaded from JSON, looked up by symbol (currencies["gp"]); exposes the configuredbaseUnit. -
Money— a wallet of coin counts per denomination ([UnitCurrency: Int]), with denomination-preserving+/-,add/spend, andtotalValue(converted to the base currency via each denomination's coefficient). Decodes from a keyed object ({"gp": 130}), a parsed string ("14 GP"), or a bare number (treated as the base unit). -
MoneyRoll— likeMoney, but each denomination holds a dice expression (AnyRollablefrom SwiftDice) instead of a fixed count, for rollable treasure such as "d6 gp each". Callroll()to produce a concreteMoney:let treasure = try decoder.decode(MoneyRoll.self, from: json, configuration: currencies) // treasure == "d10 gp 2d8 sp" let loot = treasure.roll() // a concrete Money, e.g. "7 gp 11 sp"
Item— base item with name, weight, value, and quantity.Weapon— adds damage roll, properties (finesse, thrown, …), range, and proficiency category.Armor— adds AC formula, weight category, and dexterity modifier rule.Gear/Tool— general equipment variants.EquipmentOptions— a list of item-choice alternatives (e.g. "Option A or Option B"), decoded from nested JSON arrays. Used for class and background starting equipment.InventoryEntry— pairs anItemwith a quantity and equipped flag; used byPlayer.WeaponProficiency— represents a proficiency by category (simple, martial) or specific weapon name.
Player— the main character class. Holds species, class, background, ability scores, skill proficiencies, inventory, aspellbookof prepared spells and expended spell slots, and physical appearance.baseHeightis the intrinsic height; the computedheightproperty is the hook for future spell effects (Enlarge/Reduce).sizeis derived fromheightviaCreatureSize. Can compute AC, HP, initiative, ability modifiers, and proficiency bonus.Players— aCodableWithConfigurationcollection ofPlayerinstances.PlayerAppearance— dictionary-backed cosmetic appearance struct (traits: [String: String]). Typed computed properties (hairColor,eyeColor,skinColor,age,birthdate,gender) wrap standard keys. Any additional trait can be stored and retrieved via a subscript keyed byAppearanceTraitKey. TheGenderenum is defined here. Codable via a single-value container that encodes the dictionary directly.AppearanceTraitKey— aHashablestruct wrapping a raw string key. Standard keys are defined as static constants; clients can add domain-specific keys via extension without modifying the library.allStandardKeysenumerates the library-defined keys for use in builder UIs.DescriptiveTraitKey—CaseIterableenum of narrative trait keys:personalityTrait,ideal,bond,flaw, andbackstory. Physical appearance traits are intentionally excluded — those belong toPlayerAppearance.CreatureSize— size category (tiny through gargantuan) derived from aPlayer's height. Provides space, squares occupied, and a random-height range per size.Ability— named ability (Strength, Dexterity, …) with ascoreModifierextension onIntthat computes the standard floor-divided modifier.AbilityScores— a keyed container for the six base scores with roll-4d6-drop-lowest support.CharacterAlignment— ethics × morals enumeration with associated display names.ClassTraits— describes a class: hit dice, primary ability, saving throws, skill and weapon proficiencies, armor training, starting equipment, spellcasting ability and type, spell slots, cantrips/spells known, subclass details, and an optional suggesteddefaultBackground.Classes—CodableWithConfiguration,DisplayOrderedcollection ofClassTraits. Supports an optional shared experience-points table and a"display order"array.SubclassTraits— describes a subclass with its own descriptive traits.SpeciesTraits— describes a species: lifespan, size, speed, darkvision, creature type, traits, and optional subspecies. TheparentNameproperty links subspecies to their parent.Species—CodableWithConfiguration,DisplayOrderedcollection. Custom decoder stitches subspecies into the flatallSpeciesdictionary; encoder writes only root species (with embedded subspecies).BackgroundTraits— describes a background: ability scores, feat, skill proficiencies, tool proficiency, and equipment options.Backgrounds—CodableWithConfiguration,DisplayOrderedcollection ofBackgroundTraits. Supports a"display order"array.Skill/Skills— named skill with associated ability.FeatTraits/Feats— feat with name and optional prerequisites.UnarmoredDefense— computes AC from a list of ability modifiers (e.g. Barbarian's CON bonus).CreatureType/CreatureTypes— creature type taxonomy (humanoid, beast, …).Initiative— computed initiative value with optional tiebreaker.
Spell/Spells— spell with school, level, casting time, range, components, duration, and class lists.SpellcastingType— how a class learns and uses spells:prepared,known, orpactMagic. Set onClassTraits.spellcastingType.Spellbook— a character's prepared/known spells and per-level expended spell slots (Player.spellbook).prepare(_:)/unprepare(_:)manage the spell list;expendSlot(at:)/slotsExpended(at:)/resetSlots()track usage againstClassTraits.spellSlots. Encodes spells by name via theGameDataconfiguration context, so JSON stores names rather than full spell definitions.
CharacterGenerator— generates randomisedPlayerinstances by sampling from the loadedGameData. UsesSwiftDicefor all die rolls.NameGenerator— produces random names by combining first and last names loaded fromCharacterNames.json.
DungeonCore is a Swift package built on top of RolePlayingCore that models tabletop dungeon maps — rooms, hallways, and doors, derived connectivity/reachability, and keyed module content such as encounters, treasure, and occupancy checks. Its Examples/DungeonMapBuilder app is a SwiftUI map viewer and room-content editor for iOS and Mac Catalyst.
To learn about the origin of the dice types that power random generation, see the three-part series on Medium:
For background on why Codable was applied across this repository:
The RolePlayingCore source code is licensed under the MIT License. The example game data in Examples/CharacterGenerator/CharacterGenerator/CharacterGenerator/Configuration includes material from the System Reference Document 5.2.1.
This work includes material from the System Reference Document 5.2.1 ("SRD 5.2.1") by Wizards of the Coast LLC, available at https://www.dndbeyond.com/srd. The SRD 5.2.1 is licensed under the Creative Commons Attribution 4.0 International License, available at https://creativecommons.org/licenses/by/4.0/legalcode.