playlist-data-engine 1.7.3 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +14 -0
  2. package/bin/cli.cjs +85 -0
  3. package/dist/gateway-CDMPqFEH.js +1320 -0
  4. package/dist/gateway-DKa45Uz6.cjs +6 -0
  5. package/dist/gateway.d.ts +1 -0
  6. package/dist/gateway.d.ts.map +1 -1
  7. package/dist/gateway.js +1 -1
  8. package/dist/gateway.mjs +22 -19
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/playlist-data-engine.js +4 -4
  12. package/dist/playlist-data-engine.mjs +30 -27
  13. package/dist/utils/engineDocs.d.ts +33 -0
  14. package/dist/utils/engineDocs.d.ts.map +1 -0
  15. package/docs/DATA_ENGINE_REFERENCE.md +6660 -0
  16. package/docs/USAGE_IN_OTHER_PROJECTS.md +587 -0
  17. package/docs/features/AUDIO_ANALYSIS.md +610 -0
  18. package/docs/features/BEAT_DETECTION.md +5250 -0
  19. package/docs/features/COMBAT_SYSTEM.md +1632 -0
  20. package/docs/features/CONTENT_PACKS.md +464 -0
  21. package/docs/features/CUSTOM_CONTENT.md +603 -0
  22. package/docs/features/ENEMY_GENERATION.md +1711 -0
  23. package/docs/features/EQUIPMENT_SYSTEM.md +2279 -0
  24. package/docs/features/EXTENSIBILITY_GUIDE.md +1106 -0
  25. package/docs/features/GATEWAY_RESOLUTION.md +725 -0
  26. package/docs/features/IRL_SENSORS.md +360 -0
  27. package/docs/features/PLAYLIST_PARSING.md +446 -0
  28. package/docs/features/PREREQUISITES.md +571 -0
  29. package/docs/features/ROLLS_AND_SEEDS.md +687 -0
  30. package/docs/features/XP_AND_STATS.md +1221 -0
  31. package/llms.txt +33 -0
  32. package/package.json +9 -2
  33. package/skills/playlist-data-engine/SKILL.md +69 -0
  34. package/dist/gateway-C_p9Ku3O.js +0 -1211
  35. package/dist/gateway-Ceg-5xug.cjs +0 -1
@@ -0,0 +1,603 @@
1
+ # Custom Content Reference
2
+
3
+ Complete guide to custom races, custom classes, and spawn rate control in the Playlist Data Engine.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Custom Races](#custom-races)
10
+ - [Race Type](#race-type)
11
+ - [RaceDataEntry](#racedataentry)
12
+ - [Registering Custom Races](#registering-custom-races)
13
+ - [Race Validation](#race-validation)
14
+ - [getRaceData() Helper](#getracedata-helper)
15
+ - [Controlling Race Spawn Rates](#controlling-race-spawn-rates)
16
+ 2. [Subrace Support](#subrace-support)
17
+ - [Subrace Property](#subrace-property)
18
+ - [RacialTrait with Subrace](#racialtrait-with-subrace)
19
+ - [Subrace Validation](#subrace-validation)
20
+ - [Subrace Filtering](#subrace-filtering)
21
+ - [Complete Subrace Registration Example](#complete-subrace-registration-example)
22
+ - [Feature with Subrace Prerequisite](#feature-with-subrace-prerequisite)
23
+ 3. [Custom Classes](#custom-classes)
24
+ - [Overview](#overview)
25
+ - [Class Type Extensibility](#class-type-extensibility)
26
+ - [ClassDataEntry](#classdataentry)
27
+ - [getClassData() Helper](#getclassdata-helper)
28
+ - [Class-Specific Data Helpers](#class-specific-data-helpers)
29
+ - [Registering Custom Classes](#registering-custom-classes)
30
+ - [Controlling Class Spawn Rates](#controlling-class-spawn-rates)
31
+ - [Overriding Audio Preferences for Default Classes](#overriding-audio-preferences-for-default-classes)
32
+ - [Example: Complete Custom Class (from scratch)](#example-complete-custom-class-from-scratch)
33
+ - [Common Patterns](#common-patterns)
34
+ - [Custom Class Validation](#custom-class-validation)
35
+ - [ClassSuggester Custom Class Support](#classsuggester-custom-class-support)
36
+
37
+ ---
38
+
39
+ ## Custom Races
40
+
41
+ The engine supports custom races through the ExtensionManager.
42
+
43
+ ### Race Type
44
+
45
+ **Location:** [src/core/types/Character.ts](../src/core/types/Character.ts)
46
+
47
+ *Also known as: Playable race, character race*
48
+
49
+ For the complete list of default D&D 5e races and type definitions, see [DATA_ENGINE_REFERENCE.md](../DATA_ENGINE_REFERENCE.md#data-types).
50
+
51
+ **Helper Functions:**
52
+
53
+ | Function | Description |
54
+ |----------|-------------|
55
+ | `asRace(value: string)` | Convert a string to the Race type |
56
+ | `isValidRace(value: string)` | Type guard for valid race names |
57
+
58
+ **Usage:**
59
+
60
+ ```typescript
61
+ import { asRace, isValidRace } from 'playlist-data-engine';
62
+
63
+ const raceName = 'Dragonkin';
64
+ if (isValidRace(raceName)) {
65
+ const race: Race = asRace(raceName);
66
+ // Safe to use
67
+ }
68
+ ```
69
+
70
+ ### RaceDataEntry
71
+
72
+ **Location:** [src/utils/constants.ts](../src/utils/constants.ts)
73
+
74
+ For complete type definitions, see [DATA_ENGINE_REFERENCE.md](../DATA_ENGINE_REFERENCE.md#data-types).
75
+
76
+ | Property | Type | Description |
77
+ |----------|------|-------------|
78
+ | `race` | string | Race identifier |
79
+ | `ability_bonuses` | `Partial<Record<Ability, number>>` | Ability score bonuses |
80
+ | `speed` | number | Base speed in feet |
81
+ | `traits` | string[] | Array of trait IDs for this race |
82
+ | `subraces?` | string[] | Optional available subraces |
83
+ | `icon?` | string | Optional icon URL for small UI display |
84
+ | `image?` | string | Optional image URL for larger display |
85
+
86
+ ### Registering Custom Races
87
+
88
+ ```typescript
89
+ import { ExtensionManager } from 'playlist-data-engine';
90
+
91
+ const manager = ExtensionManager.getInstance();
92
+
93
+ // Step 1: Register custom race data
94
+ manager.register('races.data', [{
95
+ race: 'Dragonkin',
96
+ ability_bonuses: { STR: 2, CON: 1, CHA: 1 },
97
+ speed: 30,
98
+ traits: ['Draconic Ancestry', 'Darkvision'],
99
+ subraces: ['Fire Dragonkin', 'Ice Dragonkin', 'Lightning Dragonkin'],
100
+ icon: '/icons/races/dragonkin.png',
101
+ image: '/images/races/dragonkin-full.png'
102
+ }]);
103
+
104
+ // Step 2: Register the race name (enables validation)
105
+ manager.register('races', ['Dragonkin']);
106
+
107
+ // Step 3: Register custom racial traits (optional)
108
+ manager.register('racialTraits', [{
109
+ id: 'dragonkin_draconic_ancestry',
110
+ name: 'Draconic Ancestry',
111
+ race: 'Dragonkin',
112
+ description: 'You have draconic heritage',
113
+ effects: [
114
+ { type: 'ability_unlock', target: 'damage_resistance', value: 'elemental' }
115
+ ],
116
+ source: 'custom'
117
+ }]);
118
+ ```
119
+
120
+ ### Race Validation
121
+
122
+ The ExtensionManager validates races in this order:
123
+
124
+ 1. Check if it's a default race (Human, Elf, etc.)
125
+ 2. Check if it's been registered as a custom race name
126
+ 3. Check if it has data registered via 'races.data'
127
+ 4. If validation is disabled via `{ validate: false }`, allow any race
128
+
129
+ ### getRaceData() Helper
130
+
131
+ The `getRaceData()` function retrieves race data from both default and custom races. For complete API reference, see [DATA_ENGINE_REFERENCE.md](../DATA_ENGINE_REFERENCE.md#helper-functions).
132
+
133
+ ```typescript
134
+ import { getRaceData } from 'playlist-data-engine';
135
+
136
+ const dragonkinData = getRaceData('Dragonkin');
137
+ // Returns: { ability_bonuses: { STR: 2, CON: 1, CHA: 1 }, speed: 30, traits: [...] }
138
+ ```
139
+
140
+ ### Controlling Race Spawn Rates
141
+
142
+ Adjust how frequently custom (or default) races appear during character generation:
143
+
144
+ ```typescript
145
+ import { ExtensionManager, CharacterGenerator } from 'playlist-data-engine';
146
+
147
+ const manager = ExtensionManager.getInstance();
148
+
149
+ // Register custom races
150
+ manager.register('races', ['Dragonkin', 'Fairy', 'Elemental']);
151
+
152
+ // Set spawn rates (relative weights)
153
+ manager.setWeights('races', {
154
+ 'Dragonkin': 0.3, // Rare (30% of default weight)
155
+ 'Fairy': 0.5, // Uncommon (50% of default weight)
156
+ 'Human': 2.0 // Common (2x default weight)
157
+ });
158
+
159
+ // Now custom races will be selected during character generation
160
+ const character = CharacterGenerator.generate('my-seed', audioProfile, track);
161
+ // character.race could be 'Dragonkin', 'Fairy', or any default race
162
+ ```
163
+
164
+ ---
165
+
166
+ ## Subrace Support
167
+
168
+ Characters can have subraces, and features/traits can require specific subraces.
169
+
170
+ ### Subrace Property
171
+
172
+ **Location:** [src/core/types/Character.ts](../src/core/types/Character.ts)
173
+
174
+ | Property | Type | Description |
175
+ |----------|------|-------------|
176
+ | `subrace?` | string | Optional subrace (e.g., 'High Elf', 'Hill Dwarf', 'Wood Elf') |
177
+
178
+ ### RacialTrait with Subrace
179
+
180
+ **Location:** [src/core/features/FeatureTypes.ts](../src/core/features/FeatureTypes.ts)
181
+
182
+ | Property | Type | Description |
183
+ |----------|------|-------------|
184
+ | `id` | string | Unique trait identifier |
185
+ | `name` | string | Trait name |
186
+ | `race` | Race | Parent race |
187
+ | `subrace?` | string | Optional subrace requirement |
188
+ | `prerequisites?` | `FeaturePrerequisite` | Additional requirements |
189
+ | `effects?` | `FeatureEffect[]` | Effects when applied |
190
+ | `source` | `'default' \| 'custom'` | Data source |
191
+
192
+ ### Subrace Validation
193
+
194
+ Features with subrace requirements validate that the character has the specified subrace before applying effects.
195
+
196
+ ### Subrace Filtering
197
+
198
+ FeatureQuery provides `getRacialTraitsForSubrace()`:
199
+
200
+ ```typescript
201
+ const query = FeatureQuery.getInstance();
202
+
203
+ // Get traits specific to High Elf subrace
204
+ const highElfTraits = query.getRacialTraitsForSubrace('Elf', 'High Elf');
205
+ ```
206
+
207
+ ### Complete Subrace Registration Example
208
+
209
+ ```typescript
210
+ import { ExtensionManager, CharacterGenerator } from 'playlist-data-engine';
211
+
212
+ const manager = ExtensionManager.getInstance();
213
+
214
+ // ===== REGISTER CUSTOM RACE WITH SUBRACES =====
215
+ // Step 1: Register the race name
216
+ manager.register('races', ['Dragonkin'], { validate: true });
217
+
218
+ // Step 2: Register the race data (ability bonuses, speed, traits, subraces)
219
+ manager.register('races.data', [{
220
+ race: 'Dragonkin',
221
+ ability_bonuses: { STR: 2, CON: 1, CHA: 1 },
222
+ speed: 30,
223
+ traits: ['Draconic Ancestry', 'Darkvision'],
224
+ subraces: ['Fire Dragonkin', 'Ice Dragonkin', 'Lightning Dragonkin'],
225
+ icon: '/icons/races/dragonkin.png',
226
+ image: '/images/races/dragonkin-full.png'
227
+ }]);
228
+
229
+ // ===== REGISTER SUBRACE-SPECIFIC TRAITS =====
230
+ // Fire Dragonkin only
231
+ manager.register('racialTraits', [{
232
+ id: 'fire_dragonkin_resistance',
233
+ name: 'Fire Resistance',
234
+ description: 'Resistance to fire damage',
235
+ race: 'Dragonkin',
236
+ subrace: 'Fire Dragonkin', // Only for this subrace
237
+ effects: [
238
+ { type: 'passive_modifier', target: 'fire_resistance', value: true }
239
+ ],
240
+ source: 'custom'
241
+ }]);
242
+
243
+ // Ice Dragonkin only
244
+ manager.register('racialTraits', [{
245
+ id: 'ice_dragonkin_resistance',
246
+ name: 'Cold Resistance',
247
+ description: 'Resistance to cold damage',
248
+ race: 'Dragonkin',
249
+ subrace: 'Ice Dragonkin',
250
+ effects: [
251
+ { type: 'passive_modifier', target: 'cold_resistance', value: true }
252
+ ],
253
+ source: 'custom'
254
+ }]);
255
+
256
+ // ===== GENERATE CHARACTER WITH SUBRACE =====
257
+ const character = CharacterGenerator.generate(seed, audioProfile, track, {
258
+ forceRace: 'Dragonkin',
259
+ subrace: 'Fire Dragonkin'
260
+ });
261
+
262
+ // Character will have:
263
+ // - Base Dragonkin traits (Draconic Ancestry, Darkvision)
264
+ // - Subrace-specific traits (Fire Resistance)
265
+ // - Correct ability bonuses (STR+2, CON+1, CHA+1)
266
+ ```
267
+
268
+ ### Feature with Subrace Prerequisite
269
+
270
+ Traits can require a specific subrace via prerequisites:
271
+
272
+ ```typescript
273
+ import { ExtensionManager } from 'playlist-data-engine';
274
+
275
+ const manager = ExtensionManager.getInstance();
276
+
277
+ // Trait that requires a specific subrace
278
+ manager.register('racialTraits', [{
279
+ id: 'inferno_breath',
280
+ name: 'Inferno Breath',
281
+ description: 'Breathe fire like a true red dragon',
282
+ race: 'Dragonkin',
283
+ subrace: 'Fire Dragonkin',
284
+ prerequisites: {
285
+ subrace: 'Fire Dragonkin', // Must be Fire Dragonkin
286
+ level: 5
287
+ },
288
+ effects: [
289
+ { type: 'active_ability', target: 'fire_breath', value: '6d6' }
290
+ ],
291
+ source: 'custom'
292
+ }]);
293
+ ```
294
+
295
+ ---
296
+
297
+ ## Custom Classes
298
+
299
+ The engine supports template-based custom classes through the ExtensionManager. Custom classes can extend (inherit from) existing D&D 5e base classes or be defined completely from scratch.
300
+
301
+ ### Overview
302
+
303
+ The Template Class System enables creating new classes that extend existing D&D 5e base classes without duplicating all properties. For example, a "Necromancer" class can extend "Wizard" and only override the properties that differ.
304
+
305
+ **Key Features:**
306
+ - **Template inheritance**: Custom classes can inherit from base classes via `baseClass` property
307
+ - **Complete customization**: Classes can be defined from scratch without `baseClass`
308
+ - **Skill lists**: Custom skill lists (including custom skills)
309
+ - **Spell casting**: Custom spell lists and slot progressions
310
+ - **Equipment**: Custom starting equipment
311
+ - **Features**: Custom class features with prerequisites
312
+ - **Audio preferences**: Optional audio affinity for class suggestion
313
+
314
+ ### Class Type Extensibility
315
+
316
+ **Location:** [src/core/types/Character.ts](../src/core/types/Character.ts)
317
+
318
+ *Also known as: Class name type, branded class type*
319
+
320
+ For the complete list of default D&D 5e classes and type definitions, see [DATA_ENGINE_REFERENCE.md](../DATA_ENGINE_REFERENCE.md#data-types).
321
+
322
+ **Helper Functions:**
323
+
324
+ | Function | Description |
325
+ |----------|-------------|
326
+ | `asClass(value: string)` | Convert a string to the Class type |
327
+ | `isValidClass(value: string)` | Type guard for valid class names |
328
+
329
+ ### ClassDataEntry
330
+
331
+ **Location:** [src/utils/constants.ts](../src/utils/constants.ts)
332
+
333
+ For complete type definitions, see [DATA_ENGINE_REFERENCE.md](../DATA_ENGINE_REFERENCE.md#data-types).
334
+
335
+ | Property | Type | Required | Description |
336
+ |----------|------|----------|-------------|
337
+ | `name` | string | Yes | Unique class name |
338
+ | `baseClass?` | Class | No | Base class to inherit from (template system) |
339
+ | `primary_ability` | Ability | Yes* | Primary ability score |
340
+ | `hit_die` | number | Yes* | Hit die size (6, 8, 10, 12) |
341
+ | `saving_throws` | Ability[] | Yes* | Two saving throw abilities |
342
+ | `is_spellcaster` | boolean | Yes* | Can this class cast spells |
343
+ | `skill_count` | number | Yes* | Number of skill proficiencies |
344
+ | `available_skills` | string[] | Yes* | Array of skill IDs |
345
+ | `has_expertise` | boolean | Yes* | Has expertise feature |
346
+ | `expertise_count?` | number | No | Number of expertise choices |
347
+ | `audio_preferences?` | object | No | Audio affinity for class suggestion |
348
+ | `icon?` | string | No | Optional icon URL for small UI display |
349
+ | `image?` | string | No | Optional image URL for larger display |
350
+
351
+ *Required only if `baseClass` is not specified.
352
+
353
+ **Audio Preferences:**
354
+
355
+ | Property | Type | Description |
356
+ |----------|------|-------------|
357
+ | `primary` | `'bass' \| 'treble' \| 'mid' \| 'amplitude' \| 'chaos'` | Primary audio trait |
358
+ | `secondary?` | audio trait | Secondary preference |
359
+ | `tertiary?` | audio trait | Tertiary preference |
360
+ | `bass?`, `treble?`, `mid?`, `amplitude?` | number | Optional weight values |
361
+
362
+ See also: [DATA_ENGINE_REFERENCE.md - Audio Preferences](../DATA_ENGINE_REFERENCE.md#data-types)
363
+
364
+ ### getClassData() Helper
365
+
366
+ **Location:** [src/utils/constants.ts](../src/utils/constants.ts)
367
+
368
+ Retrieves class data from default CLASS_DATA or ExtensionManager. For template-based classes, merges base class data with custom data (custom properties override).
369
+
370
+ For complete API reference, see [DATA_ENGINE_REFERENCE.md - Helper Functions](../DATA_ENGINE_REFERENCE.md#helper-functions).
371
+
372
+ **Property Override Behavior:**
373
+
374
+ | Property | Behavior | Example |
375
+ |----------|----------|---------|
376
+ | `primary_ability` | Inherited unless specified | `baseClass: 'Wizard'` → inherits `INT` |
377
+ | `hit_die` | Inherited unless specified | `baseClass: 'Wizard'` → inherits `8` |
378
+ | `saving_throws` | Inherited unless specified | `baseClass: 'Wizard'` → inherits `['INT', 'WIS']` |
379
+ | `is_spellcaster` | Inherited unless specified | `baseClass: 'Wizard'` → inherits `true` |
380
+ | `skill_count` | Inherited unless specified | `baseClass: 'Wizard'` → inherits `2` |
381
+ | `available_skills` | **Replaced** (not merged) | Custom list replaces base entirely |
382
+ | `has_expertise` | Inherited unless specified | `baseClass: 'Wizard'` → inherits `false` |
383
+ | `audio_preferences` | Inherited unless specified | Can override for custom audio affinity |
384
+
385
+ ### Class-Specific Data Helpers
386
+
387
+ **Location:** [src/utils/constants.ts](../src/utils/constants.ts)
388
+
389
+ For complete API reference, see [DATA_ENGINE_REFERENCE.md - Helper Functions](../DATA_ENGINE_REFERENCE.md#helper-functions).
390
+
391
+ | Function | Description |
392
+ |----------|-------------|
393
+ | `getClassSpellList(className: string)` | Get spell list for a class |
394
+ | `getSpellSlotsForClass(className: string, level: number)` | Get spell slots at a level |
395
+ | `getClassStartingEquipment(className: string)` | Get starting equipment |
396
+
397
+ ### Registering Custom Classes
398
+
399
+ **Via ExtensionManager:**
400
+
401
+ ```typescript
402
+ import { ExtensionManager } from 'playlist-data-engine';
403
+ import { asClass } from 'playlist-data-engine';
404
+
405
+ const manager = ExtensionManager.getInstance();
406
+
407
+ // Step 1: Register custom class data
408
+ manager.register('classes.data', [{
409
+ name: 'Necromancer',
410
+ baseClass: 'Wizard', // Inherits from Wizard
411
+ // Only override what's different:
412
+ available_skills: ['arcana', 'medicine', 'religion', 'necromancy'],
413
+ icon: '/icons/classes/necromancer.png',
414
+ image: '/images/classes/necromancer-full.png'
415
+ // All other properties (hit_die, saving_throws, etc.) are inherited from Wizard
416
+ }]);
417
+
418
+ // Step 2: Register the class name for validation
419
+ manager.register('classes', [asClass('Necromancer')]);
420
+ ```
421
+
422
+ ### Controlling Class Spawn Rates
423
+
424
+ Adjust how frequently custom (or default) classes appear during character generation:
425
+
426
+ ```typescript
427
+ import { ExtensionManager, CharacterGenerator } from 'playlist-data-engine';
428
+
429
+ const manager = ExtensionManager.getInstance();
430
+
431
+ // Make certain classes more or less common
432
+ manager.setWeights('classes', {
433
+ 'Necromancer': 0.5, // Rare (half default weight)
434
+ 'Sorcerer': 2.0, // Common (2x default weight)
435
+ 'Warlock': 1.5, // Uncommon (1.5x default weight)
436
+ 'Paladin': 0.3 // Very rare
437
+ });
438
+
439
+ // Classes will be selected according to their weights during generation
440
+ const character = CharacterGenerator.generate('my-seed', audioProfile, track);
441
+ // character.class will favor Sorcerer and Warlock over Necromancer and Paladin
442
+ ```
443
+
444
+ ### Overriding Audio Preferences for Default Classes:
445
+
446
+ ```typescript
447
+ import { ExtensionManager } from 'playlist-data-engine';
448
+
449
+ const manager = ExtensionManager.getInstance();
450
+
451
+ // Override default class audio preferences
452
+ manager.register('classes.data', [{
453
+ name: 'Barbarian', // Override default Barbarian
454
+ audio_preferences: {
455
+ primary: 'treble', // Make Barbarians prefer treble instead of bass
456
+ treble: 1.0
457
+ }
458
+ }]);
459
+
460
+ // Now Barbarians will be suggested for treble-heavy audio instead of bass-heavy
461
+ ```
462
+
463
+ ### Example: Complete Custom Class (from scratch):
464
+
465
+ ```typescript
466
+ import { ExtensionManager, asClass } from 'playlist-data-engine';
467
+
468
+ const manager = ExtensionManager.getInstance();
469
+
470
+ // Step 1: Register complete custom class data
471
+ manager.register('classes.data', [{
472
+ name: 'Runecaster',
473
+ // No baseClass - must specify everything
474
+ primary_ability: 'WIS',
475
+ hit_die: 8,
476
+ saving_throws: ['WIS', 'CON'],
477
+ is_spellcaster: true,
478
+ skill_count: 3,
479
+ available_skills: ['arcana', 'nature', 'religion', 'insight', 'medicine'],
480
+ has_expertise: false,
481
+ icon: '/icons/classes/runecaster.png',
482
+ image: '/images/classes/runecaster-full.png'
483
+ }]);
484
+
485
+ // Step 2: Register the class name
486
+ manager.register('classes', [asClass('Runecaster')]);
487
+
488
+ // Step 3: (Optional) Set custom spell list
489
+ manager.register('classSpellLists.Runecaster', [{
490
+ cantrips: ['druidcraft', 'guidance', 'resistance'],
491
+ spells_by_level: {
492
+ 1: ['detect magic', 'magic stone', 'faerie fire']
493
+ }
494
+ }]);
495
+
496
+ // Step 4: (Optional) Set custom spell slot progression
497
+ manager.register('classSpellSlots', [{
498
+ class: 'Runecaster',
499
+ slots: {
500
+ 1: { 1: 2 },
501
+ 2: { 1: 3 },
502
+ 3: { 1: 4, 2: 2 }
503
+ // ... define for all levels 1-20
504
+ }
505
+ }]);
506
+
507
+ // Step 5: (Optional) Set custom starting equipment
508
+ manager.register('classStartingEquipment.Runecaster', [{
509
+ weapons: ['Quarterstaff', 'Dagger'],
510
+ armor: [],
511
+ items: ['Component pouch', 'Spellbook']
512
+ }]);
513
+
514
+ // Now generate a Runecaster character!
515
+ const character = CharacterGenerator.generate(
516
+ 'my-seed',
517
+ audioProfile,
518
+ track
519
+ );
520
+ ```
521
+
522
+ **Note:** For complete ClassDataEntry property definitions and the full list of default D&D 5e classes, see [DATA_ENGINE_REFERENCE.md](../DATA_ENGINE_REFERENCE.md#data-types).
523
+
524
+ ### Common Patterns
525
+
526
+ Here are common patterns for creating custom classes using the template system:
527
+
528
+ **Archetype Variant** - Same class, different flavor:
529
+
530
+ ```typescript
531
+ {
532
+ name: 'BattleMage',
533
+ baseClass: 'Wizard',
534
+ hit_die: 10, // More durable than standard Wizard
535
+ saving_throws: ['INT', 'CON'], // CON instead of WIS
536
+ available_skills: ['arcana', 'athletics', 'intimidation'],
537
+ icon: '/icons/classes/battlemage.png'
538
+ }
539
+ ```
540
+
541
+ **Multiclass-Inspired** - Two classes combined:
542
+
543
+ ```typescript
544
+ {
545
+ name: 'Spellsword',
546
+ baseClass: 'Fighter',
547
+ is_spellcaster: true, // Add spellcasting
548
+ primary_ability: 'STR', // Keep Fighter primary
549
+ available_skills: ['athletics', 'acrobatics', 'arcana', 'intimidation'],
550
+ icon: '/icons/classes/spellsword.png'
551
+ }
552
+ ```
553
+
554
+ **Specialist** - Narrow focus:
555
+
556
+ ```typescript
557
+ {
558
+ name: 'Beastmaster',
559
+ baseClass: 'Ranger',
560
+ skill_count: 3, // Extra skill for animal handling
561
+ available_skills: ['animal_handling', 'nature', 'survival', 'perception'],
562
+ icon: '/icons/classes/beastmaster.png'
563
+ }
564
+ ```
565
+
566
+ ### Custom Class Validation
567
+
568
+ **Location:** [src/core/extensions/ExtensionManager.ts](../src/core/extensions/ExtensionManager.ts)
569
+
570
+ The ExtensionManager validates custom classes:
571
+
572
+ 1. **Class Names**: Must be either a default class or registered via `classes.data`
573
+ 2. **Class Data**: Must have `name` (string), `primary_ability` (Ability), `hit_die` (number), `saving_throws` (Ability[]), `is_spellcaster` (boolean), `skill_count` (number), `available_skills` (string[]), `has_expertise` (boolean)
574
+
575
+ ```typescript
576
+ // Validation errors for invalid class data
577
+ manager.register('classes', ['InvalidClass']);
578
+ // Throws: "Invalid items for category 'classes':
579
+ // Invalid class (must be one of: Barbarian, Bard, Cleric, Druid, Fighter,
580
+ // Monk, Paladin, Ranger, Rogue, Sorcerer, Warlock, Wizard or a custom
581
+ // class registered via 'classes.data')"
582
+ ```
583
+
584
+ ### ClassSuggester Custom Class Support
585
+
586
+ **Location:** [src/core/generation/ClassSuggester.ts](../src/core/generation/ClassSuggester.ts)
587
+
588
+ The `ClassSuggester` automatically includes custom classes registered via ExtensionManager when suggesting a class based on audio profile. Custom classes with `audio_preferences` are matched against the audio profile.
589
+
590
+ | Method | Returns | Description |
591
+ |--------|---------|-------------|
592
+ | `suggest(audioProfile: AudioProfile, rng: SeededRNG)` | `string` | Suggest a class based on audio profile |
593
+
594
+ ---
595
+
596
+ ## See Also
597
+
598
+ - [PREREQUISITES.md](PREREQUISITES.md) - Prerequisites system guide
599
+ - [DATA_ENGINE_REFERENCE.md](../DATA_ENGINE_REFERENCE.md) - Complete API reference
600
+ - [USAGE_IN_OTHER_PROJECTS.md](../USAGE_IN_OTHER_PROJECTS.md) - Usage examples
601
+ - [EXTENSIBILITY_GUIDE.md](EXTENSIBILITY_GUIDE.md) - Custom content registration and spawn rates
602
+ - [EQUIPMENT_SYSTEM.md](EQUIPMENT_SYSTEM.md) - Custom equipment
603
+ - [XP_AND_STATS.md](XP_AND_STATS.md) - Progression and stat strategies