playlist-data-engine 1.7.2 → 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 (41) hide show
  1. package/README.md +20 -3
  2. package/bin/cli.cjs +85 -0
  3. package/dist/core/parser/TrackExtras.d.ts +150 -1
  4. package/dist/core/parser/TrackExtras.d.ts.map +1 -1
  5. package/dist/gateway-CDMPqFEH.js +1320 -0
  6. package/dist/gateway-DKa45Uz6.cjs +6 -0
  7. package/dist/gateway.d.ts +3 -1
  8. package/dist/gateway.d.ts.map +1 -1
  9. package/dist/gateway.js +1 -1
  10. package/dist/gateway.mjs +22 -14
  11. package/dist/index.d.ts +4 -3
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/playlist-data-engine.js +34 -34
  14. package/dist/playlist-data-engine.mjs +964 -1240
  15. package/dist/utils/engineDocs.d.ts +33 -0
  16. package/dist/utils/engineDocs.d.ts.map +1 -0
  17. package/dist/utils/playlistUtils.d.ts +37 -0
  18. package/dist/utils/playlistUtils.d.ts.map +1 -1
  19. package/dist/utils/validators.d.ts +27 -0
  20. package/dist/utils/validators.d.ts.map +1 -1
  21. package/docs/DATA_ENGINE_REFERENCE.md +6660 -0
  22. package/docs/USAGE_IN_OTHER_PROJECTS.md +587 -0
  23. package/docs/features/AUDIO_ANALYSIS.md +610 -0
  24. package/docs/features/BEAT_DETECTION.md +5250 -0
  25. package/docs/features/COMBAT_SYSTEM.md +1632 -0
  26. package/docs/features/CONTENT_PACKS.md +464 -0
  27. package/docs/features/CUSTOM_CONTENT.md +603 -0
  28. package/docs/features/ENEMY_GENERATION.md +1711 -0
  29. package/docs/features/EQUIPMENT_SYSTEM.md +2279 -0
  30. package/docs/features/EXTENSIBILITY_GUIDE.md +1106 -0
  31. package/docs/features/GATEWAY_RESOLUTION.md +725 -0
  32. package/docs/features/IRL_SENSORS.md +360 -0
  33. package/docs/features/PLAYLIST_PARSING.md +446 -0
  34. package/docs/features/PREREQUISITES.md +571 -0
  35. package/docs/features/ROLLS_AND_SEEDS.md +687 -0
  36. package/docs/features/XP_AND_STATS.md +1221 -0
  37. package/llms.txt +33 -0
  38. package/package.json +9 -2
  39. package/skills/playlist-data-engine/SKILL.md +69 -0
  40. package/dist/gateway-DUk4nCao.cjs +0 -1
  41. package/dist/gateway-DyR4M-uH.js +0 -681
@@ -0,0 +1,587 @@
1
+ # Playlist Data Engine Usage Guide
2
+
3
+ Transform music playlists into D&D 5e-inspired RPG characters through audio/visual analysis and deterministic generation.
4
+
5
+ **Quick Links:**
6
+ - **[API Reference](DATA_ENGINE_REFERENCE.md)** — Complete class and method documentation
7
+ - **[Audio Analysis](features/AUDIO_ANALYSIS.md)** — Triple-tap real-time, full timeline
8
+ - **[Beat Detection](features/BEAT_DETECTION.md)** — Beat detection, rhythm game
9
+ - **[XP and Leveling](features/XP_AND_STATS.md)** — Progression, stat increases, mastery
10
+ - **[Environmental Sensors](features/IRL_SENSORS.md)** — GPS, motion, weather, light modifiers
11
+ - **[Rolls and Seeds](features/ROLLS_AND_SEEDS.md)** — Deterministic random number generation
12
+ - **[Combat System](features/COMBAT_SYSTEM.md)** — Turn-based D&D 5e combat
13
+ - **[Enemy Generation](features/ENEMY_GENERATION.md)** — CR-based enemies, encounters, rarity scaling
14
+ - **[Extensibility Guide](features/EXTENSIBILITY_GUIDE.md)** — Custom content, classes, races, skills
15
+ - **[Equipment System](features/EQUIPMENT_SYSTEM.md)** — Properties, enchanting, templates
16
+ - **[Playlist Parsing](features/PLAYLIST_PARSING.md)** — Parsed playlist structure, metadata extraction, track extras, IPFS, VRMs
17
+ - **[Prerequisites](features/PREREQUISITES.md)** — Level/ability/class/skill/feature requirements
18
+ - **[Custom Classes & Races](features/CUSTOM_CONTENT.md)** — Template-based class inheritance
19
+ - **[Content Packs](features/CONTENT_PACKS.md)** — Data packs for custom content
20
+
21
+ ---
22
+
23
+ ### Installation
24
+
25
+ Install from local path (recommended):
26
+
27
+ ```json
28
+ {
29
+ "dependencies": {
30
+ "playlist-data-engine": "file:/path/to/playlist-data-engine"
31
+ }
32
+ }
33
+ ```
34
+
35
+ For development, use `npm link` to test changes without rebuilding:
36
+
37
+ ```bash
38
+ cd /path/to/playlist-data-engine && npm link
39
+ cd /path/to/your/project && npm link playlist-data-engine
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Import paths (read this first)
45
+
46
+ The engine ships **three entry points**. Picking the right one matters because
47
+ the audio-analysis surface depends on `@tensorflow/tfjs` (~14 MB), and importing
48
+ it accidentally will inflate your bundle.
49
+
50
+ | Import path | What it provides | Pulls TensorFlow? |
51
+ |---|---|---|
52
+ | `playlist-data-engine` (default) | Everything **except** audio analysis — gateway/URL utils, metadata parsing, character/rhythm generation, beat detection, color extraction. | **No** |
53
+ | `playlist-data-engine/gateway` | Just the Arweave/IPFS gateway manager + URL helpers + `MetadataExtractor`. The lightest entry. | **No** |
54
+ | `playlist-data-engine/analysis` | Audio analysis & level generation that needs ML: `MusicClassifier`, `AudioAnalyzer`, `EssentiaPitchDetector`, `PitchAnalyzer`, `LevelGenerator`, `LevelSerializer`, `BeatConverter`, `ButtonMapper`, `PitchBeatLinker`, `ModelCache`. | **Yes** |
55
+
56
+ Rules of thumb:
57
+ - **Default to the bare `playlist-data-engine` import.** It is TF-free and covers the vast majority of use cases (parsing, generation, beat detection without ML pitch).
58
+ - **Only import from `/analysis` in code that actually runs ML** — and ideally isolate that code in a Web Worker so the TensorFlow.js runtime is loaded on a worker thread, not the main thread.
59
+ - **Never re-export `/analysis` symbols through the main entry or `/gateway`** — that defeats the split and silently re-introduces TF into every consumer.
60
+
61
+ ```ts
62
+ // ✅ TF-free — most code should look like this
63
+ import { PlaylistParser, MetadataExtractor, BeatMapGenerator } from 'playlist-data-engine';
64
+ import { ArweaveGatewayManager } from 'playlist-data-engine/gateway';
65
+
66
+ // ✅ TF-bearing — only in your audio-analysis worker
67
+ import { MusicClassifier, AudioAnalyzer } from 'playlist-data-engine/analysis';
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Usage Examples
73
+
74
+ ### Basic
75
+ - [Playlist Parsing and Character Generation](#basic-playlist-parsing-and-character-generation) — Parse playlists, analyze audio, generate characters
76
+ - [Quick Data Extraction](#quick-data-extraction) — Simple arrays of URLs, titles, artists from playlists
77
+ - [XP from Listening](#earning-xp-from-listening-to-music) — Session tracking, XP calculation, level-ups
78
+
79
+ ### Specific Features
80
+ - [Color Extraction](#color-extraction) — Artwork color palette extraction
81
+ - [Character Naming](#character-naming) — Automatic and manual RPG-style name generation
82
+ - [Deterministic Character Generation](#deterministic-character-generation) — Same seed, same character
83
+ - [Stat Strategies](#stat-strategies) — Level-up stat increase options
84
+ - [XP Scaling](#xp-scaling) — Progression configuration
85
+ - [Prestige System](features/XP_AND_STATS.md#track-mastery-prestige-system) — Reset for badge upgrades after mastering tracks
86
+ - [Environmental Sensors](#environmental-sensors) — GPS, motion, weather, light modifiers
87
+ - [Gaming Platform Integration](#gaming-platform-integration) — Steam bonuses
88
+ - [Combat System](#combat-system) — Turn-based D&D 5e combat
89
+ - [Enemy Generation](#enemy-generation) — CR-based enemies, encounters, CR vs Rarity independence
90
+
91
+ ### Audio Analysis
92
+ - [Full Song Analysis](#full-song-analysis) — Segment-by-segment timeline analysis for visualization
93
+ - [Beat Detection](features/BEAT_DETECTION.md) — Rhythm game timing, beat maps, button press accuracy
94
+
95
+ ### Advanced Pipeline
96
+ - [Combining All Systems](#combining-all-systems) — Full pipeline with environmental and gaming context
97
+
98
+ ### Extensibility
99
+ See [Extensibility System](#extensibility-system) below for complete extensibility documentation and links to detailed guides.
100
+
101
+ ### Equipment System Links
102
+ See [EQUIPMENT_SYSTEM.md](features/EQUIPMENT_SYSTEM.md) for:
103
+ - Custom equipment — Properties, enchanting, templates
104
+ - Equipment spawning — Batch spawn by rarity, tags, or templates
105
+ - Box items — Containers, adventure packs, loot boxes (see also [BoxOpener](DATA_ENGINE_REFERENCE.md#boxopener))
106
+
107
+ ### Developer Reference
108
+ - [Available Exports](#available-exports) — Complete API reference
109
+ - [Equipment System](#equipment-system) — Quick introduction
110
+ - [Extensibility Overview](#extensibility-system) — Registration and custom content
111
+ - [Validation Schemas](#validation-schemas) — Runtime type validation with Zod
112
+ - [Development Workflow](#development-workflow) — Watch mode and hot reload
113
+ - [Environment Variables](#environment-variables) — API keys and sensor configuration
114
+ - [Arweave Gateway Resolution](#arweave-gateway-resolution) — Gateway fallback for Arweave URLs
115
+ - [Troubleshooting](#troubleshooting) — Common issues
116
+
117
+ ---
118
+
119
+ ## Basic Examples
120
+
121
+ ### Basic Playlist Parsing and Character Generation
122
+
123
+ ```typescript
124
+ import {
125
+ PlaylistParser,
126
+ CharacterGenerator
127
+ } from 'playlist-data-engine';
128
+ import { AudioAnalyzer } from 'playlist-data-engine/analysis';
129
+
130
+ // Parse a playlist
131
+ const parser = new PlaylistParser();
132
+ const playlist = await parser.parse(rawPlaylistJSON);
133
+ console.log(`Loaded ${playlist.tracks.length} tracks`);
134
+
135
+ // Analyze first track's audio
136
+ const analyzer = new AudioAnalyzer();
137
+ const track = playlist.tracks[0];
138
+ const audioProfile = await analyzer.extractSonicFingerprint(track.audio_url);
139
+ console.log(`Bass: ${audioProfile.bass_dominance}, Mid: ${audioProfile.mid_dominance}, Treble: ${audioProfile.treble_dominance}`);
140
+ console.log(`RMS Energy: ${audioProfile.rms_energy}, Dynamic Range: ${audioProfile.dynamic_range}`);
141
+
142
+ // Generate character deterministically from audio
143
+ const character = CharacterGenerator.generate(
144
+ track.id, // Deterministic seed
145
+ audioProfile,
146
+ track // Track metadata for automatic name generation
147
+ );
148
+
149
+ console.log(`Generated: ${character.name}`);
150
+ console.log(` Race: ${character.race}`);
151
+ console.log(` Class: ${character.class}`);
152
+ console.log(` STR: ${character.ability_scores.STR}, DEX: ${character.ability_scores.DEX}`);
153
+
154
+ // All generated data is on the character object:
155
+ character.skills // { athletics: 'proficient', perception: 'expertise', ... }
156
+ character.spells // { cantrips, known_spells, spell_slots }
157
+ character.equipment // { weapons, armor, items, totalWeight, equippedWeight }
158
+ character.appearance // { body_type, hair_color, eye_color, skin_tone, facial_features, aura_color }
159
+ ```
160
+
161
+ > For the full parsed playlist structure, field extraction priorities, and all parsing options, see [PLAYLIST_PARSING.md](features/PLAYLIST_PARSING.md).
162
+
163
+ ### Quick Data Extraction
164
+
165
+ For simple use cases where you just need arrays of URLs or basic data from a playlist:
166
+
167
+ ```typescript
168
+ import {
169
+ PlaylistParser,
170
+ getAudioUrls,
171
+ getImageUrls,
172
+ getTrackTitles,
173
+ getArtists,
174
+ getGenres,
175
+ getTags,
176
+ getTotalDuration,
177
+ getTrackCount,
178
+ getTracks,
179
+ getFullTracks,
180
+ } from 'playlist-data-engine';
181
+
182
+ // Parse playlist first (existing flow)
183
+ const parser = new PlaylistParser();
184
+ const playlist = await parser.parse(rawPlaylistData);
185
+
186
+ // Simple array extraction
187
+ const urls = getAudioUrls(playlist); // ['https://...', 'https://...']
188
+ const images = getImageUrls(playlist); // ['https://...', 'https://...']
189
+ const titles = getTrackTitles(playlist); // ['Song 1', 'Song 2']
190
+ const artists = getArtists(playlist); // ['Artist A', 'Artist B']
191
+ const genres = getGenres(playlist); // ['Electronic', 'Hip-Hop']
192
+ const tags = getTags(playlist); // ['chill', 'upbeat']
193
+ const duration = getTotalDuration(playlist); // 1234 (seconds)
194
+ const count = getTrackCount(playlist); // 10
195
+
196
+ // Simplified track objects
197
+ const tracks = getTracks(playlist);
198
+ // [{ title: 'Song', artist: 'Artist', audio_url: '...', image_url: '...', image_thumb_url: '...' }, ...]
199
+
200
+ // Full track data (all available fields)
201
+ const fullTracks = getFullTracks(playlist);
202
+ // [{ id, title, artist, album, duration, genre, tags, audio_url, image_url, image_thumb_url, ... }, ...]
203
+
204
+ // Use in your app - example: add all audio URLs to a player
205
+ urls.forEach(url => audioPlayer.add(url));
206
+ ```
207
+
208
+ > For VRM extraction, track extras, stems, mixes, and IPFS URLs, see [PLAYLIST_PARSING.md](features/PLAYLIST_PARSING.md) and [GATEWAY_RESOLUTION.md](features/GATEWAY_RESOLUTION.md). For mix playback, find a mix by name with `findMixByName`, resolve it to a playable URL with `resolveMixUrl`, or swap a track's audio with `selectMix` — see PLAYLIST_PARSING.md.
209
+
210
+ ### Full Song Analysis
211
+
212
+ Perform a detailed, segment-by-segment analysis of the entire song. This is ideal for generating game levels or showing a song's progression over time.
213
+
214
+ ```typescript
215
+ import { AudioAnalyzer } from 'playlist-data-engine/analysis';
216
+
217
+ const analyzer = new AudioAnalyzer();
218
+
219
+ // Option A: Sample every 2 seconds
220
+ const timelineInterval = await analyzer.analyzeTimeline(audioUrl, {
221
+ type: 'interval',
222
+ intervalSeconds: 2
223
+ });
224
+
225
+ // Option B: Generate exactly 100 data points across the song
226
+ const timelineCount = await analyzer.analyzeTimeline(audioUrl, {
227
+ type: 'count',
228
+ count: 100
229
+ });
230
+
231
+ // Access timeline data
232
+ timelineCount.forEach(event => {
233
+ console.log(`[${event.timestamp}s]`);
234
+ console.log(` Energy: ${event.rms_energy} (RMS), Peak: ${event.peak}`);
235
+ console.log(` Dynamic Range: ${event.dynamic_range}`);
236
+ console.log(` Frequency: B:${event.bass} M:${event.mid} T:${event.treble}`);
237
+ console.log(` Spectral Centroid: ${event.spectral_centroid}`);
238
+ console.log(` Zero Crossing Rate: ${event.zero_crossing_rate}`);
239
+ });
240
+ ```
241
+
242
+ **For detailed documentation, see [AUDIO_ANALYSIS.md](features/AUDIO_ANALYSIS.md)**
243
+
244
+ ### Beat Detect
245
+
246
+ **For detailed documentation, see [BEAT_DETECTION.md](features/BEAT_DETECTION.md)**
247
+
248
+ ### Earning XP from Listening to Music
249
+
250
+ Track listening sessions, calculate XP earned (~1 XP/second with environmental/gaming bonuses), and apply to your character. Level-ups happen automatically when XP thresholds are reached.
251
+
252
+ ```typescript
253
+ import { SessionTracker, CharacterUpdater } from 'playlist-data-engine';
254
+
255
+ const tracker = new SessionTracker();
256
+ const sessionId = tracker.startSession(track.id, track);
257
+
258
+ // ... user listens ...
259
+
260
+ const session = tracker.endSession(sessionId);
261
+ if (session) {
262
+ const updater = new CharacterUpdater();
263
+ const previousListenCount = tracker.getTrackListenCount(track.id) - 1;
264
+ const result = updater.updateCharacterFromSession(character, session, track, previousListenCount);
265
+
266
+ if (result.leveledUp) console.log(`Level up! Now ${result.newLevel}`);
267
+ if (result.masteredTrack) console.log(`Track mastered! +${result.masteryBonusXP} bonus XP`);
268
+ }
269
+ ```
270
+
271
+ **Customization**: Stat increases, XP sources, and level scaling are all configurable:
272
+
273
+ - **Stat strategies**: Auto-smart (default), manual D&D 5e, balanced, primary-only, random, or custom formulas
274
+ - **Game modes**: Standard (stats capped at 20, increases at levels 4/8/12/16/19) or uncapped (unlimited levels, every level)
275
+ - **XP sources**: Music listening, combat, quests, or any custom activity
276
+ - **Level scaling**: Default D&D 5e pattern or provide your own XP formulas
277
+
278
+ For complete details on progression, stat increases, prestige system, and customization, see **[XP_AND_STATS.md](features/XP_AND_STATS.md)**.
279
+
280
+
281
+ ## Specific Features
282
+
283
+ ### Color Extraction
284
+
285
+ ```typescript
286
+ import { ColorExtractor } from 'playlist-data-engine';
287
+
288
+ // Extract color palette from track artwork
289
+ const colorExtractor = new ColorExtractor();
290
+ const palette = await colorExtractor.extractPalette(track.image_url);
291
+ console.log(`Primary color: ${palette.primary_color}`);
292
+ console.log(`Colors: ${palette.colors.join(', ')}`);
293
+ console.log(`Brightness: ${palette.brightness}, Saturation: ${palette.saturation}`);
294
+ console.log(`Is monochrome: ${palette.is_monochrome}`);
295
+
296
+ ```
297
+
298
+ ### Character Naming
299
+
300
+ Names are automatically generated by `CharacterGenerator` using track metadata (title, artist, genre) combined with audio characteristics and character class. Names use 7 different naming formats with fantasy-inspired patterns.
301
+
302
+ ```typescript
303
+ import { CharacterGenerator } from 'playlist-data-engine';
304
+
305
+ // Names are generated automatically - no need to provide a name parameter
306
+ const character = CharacterGenerator.generate(track.id, audioProfile, track);
307
+ console.log(`Generated name: "${character.name}"`);
308
+ ```
309
+
310
+ **Naming Modes:**
311
+
312
+ | Mode | Behavior | Example |
313
+ |------|----------|---------|
314
+ | **Deterministic** (default) | Same seed always produces same name | `CharacterGenerator.generate(seed, audio, track)` |
315
+ | **Manual override** | Force a specific name | `CharacterGenerator.generate(seed, audio, track, { forceName: 'Gandalf' })` |
316
+ | **Non-deterministic** | Same seed produces different names | `CharacterGenerator.generate(seed, audio, track, { deterministicName: false })` |
317
+
318
+ **Advanced:** For manual name generation using the full `NamingEngine` API (with control over deterministic mode), see [DATA_ENGINE_REFERENCE.md](DATA_ENGINE_REFERENCE.md#helper-namingengine).
319
+
320
+
321
+ ### Deterministic Character Generation
322
+
323
+ The same seed and audio profile always produces the same character:
324
+
325
+ **For more details on deterministic seeding, hash utilities, and seeded randomness, see [ROLLS_AND_SEEDS.md](features/ROLLS_AND_SEEDS.md)**
326
+
327
+ ```typescript
328
+ import { CharacterGenerator, type CharacterSheet } from 'playlist-data-engine';
329
+ import { AudioAnalyzer } from 'playlist-data-engine/analysis';
330
+
331
+ const seed = 'ethereum-0x123abc-1';
332
+ const analyzer = new AudioAnalyzer();
333
+ const audio = await analyzer.extractSonicFingerprint(track.audio_url);
334
+
335
+ // Generate the same character every time (same inputs = same output)
336
+ const char1 = CharacterGenerator.generate(seed, audio, track);
337
+ const char2 = CharacterGenerator.generate(seed, audio, track);
338
+
339
+ // Game mode affects the output, so different game modes = different characters
340
+ const standardChar = CharacterGenerator.generate(seed, audio, track, { gameMode: 'standard' });
341
+ const uncappedChar = CharacterGenerator.generate(seed, audio, track, { gameMode: 'uncapped' });
342
+
343
+ console.log(char1.race === char2.race); // true
344
+ console.log(char1.class === char2.class); // true
345
+ console.log(JSON.stringify(char1) === JSON.stringify(char2)); // true
346
+
347
+ // Use this for caching characters in your app
348
+ const characterCache = new Map<string, CharacterSheet>();
349
+ if (!characterCache.has(track.id)) {
350
+ characterCache.set(track.id, CharacterGenerator.generate(track.id, audio, track));
351
+ }
352
+ ```
353
+
354
+
355
+ ---
356
+
357
+ ## Advanced Examples
358
+
359
+ ### Combining All Systems
360
+
361
+ ```typescript
362
+ import {
363
+ PlaylistParser,
364
+ CharacterGenerator,
365
+ EnvironmentalSensors,
366
+ GamingPlatformSensors,
367
+ SessionTracker,
368
+ CharacterUpdater
369
+ } from 'playlist-data-engine';
370
+ import { AudioAnalyzer } from 'playlist-data-engine/analysis';
371
+
372
+ // Full pipeline: Parse → Analyze → Generate → Track → Level Up
373
+
374
+ // Initialize components ONCE (outside the loop)
375
+ const parser = new PlaylistParser();
376
+ const analyzer = new AudioAnalyzer();
377
+ const tracker = new SessionTracker(); // Single tracker maintains session history
378
+ const sensors = new EnvironmentalSensors(process.env.WEATHER_API_KEY);
379
+ const gamingSensors = new GamingPlatformSensors({
380
+ steam: { apiKey: process.env.STEAM_API_KEY, steamId: process.env.STEAM_USER_ID }
381
+ });
382
+
383
+ const playlist = await parser.parse(playlistJSON);
384
+
385
+ for (const track of playlist.tracks) {
386
+ // 1. Generate character from audio (choose game mode at creation time)
387
+ const audio = await analyzer.extractSonicFingerprint(track.audio_url);
388
+ let character = CharacterGenerator.generate(
389
+ track.id,
390
+ audio,
391
+ track,
392
+ { gameMode: 'standard' } // or 'uncapped' for epic progression
393
+ );
394
+
395
+ // 2. Get environmental context (before starting session)
396
+ const envContext = await sensors.updateSnapshot();
397
+
398
+ // 3. Get gaming context (before starting session)
399
+ const gamingContext = gamingSensors.getContext();
400
+
401
+ // 4. Track listening session WITH context from the start
402
+ const sessionId = tracker.startSession(track.id, track, {
403
+ environmental_context: envContext,
404
+ gaming_context: gamingContext
405
+ });
406
+
407
+ // ... user listens to the track ...
408
+
409
+ // 5. End session (XP is calculated automatically with context)
410
+ const session = tracker.endSession(sessionId);
411
+ if (!session) continue;
412
+
413
+ // 6. Update character with session results
414
+ const updater = new CharacterUpdater();
415
+ const previousListenCount = tracker.getTrackListenCount(track.id) - 1;
416
+ const result = updater.updateCharacterFromSession(character, session, track, previousListenCount);
417
+
418
+ character = result.character;
419
+
420
+ console.log(`${character.name} earned ${result.xpEarned} XP`);
421
+ console.log(` Total: ${result.xpEarned}, Mastery Bonus: ${result.masteryBonusXP}`);
422
+ if (result.leveledUp) {
423
+ console.log(` LEVEL UP! Now level ${result.newLevel}`);
424
+ }
425
+ }
426
+ ```
427
+
428
+
429
+ ---
430
+
431
+ ## Stat Strategies & XP Scaling
432
+
433
+ **For detailed documentation, see [XP_AND_STATS.md](features/XP_AND_STATS.md)**
434
+
435
+ ---
436
+
437
+ ## Environmental Sensors & Gaming Platform Integration
438
+
439
+ GPS, motion, and weather sensors that provide XP modifiers based on real-world conditions (running, night, storm, altitude).
440
+
441
+ Steam game detection integration that provides XP bonuses based on gaming activity.
442
+
443
+ **For detailed documentation, see [IRL_SENSORS.md](features/IRL_SENSORS.md)**
444
+
445
+ ---
446
+
447
+ ## Combat System
448
+
449
+ Turn-based D&D 5e-inspired combat with initiative, attacks, spell casting, and dice rolling.
450
+
451
+ **For detailed documentation, see [COMBAT_SYSTEM.md](features/COMBAT_SYSTEM.md)**
452
+
453
+ ### Enemy Generation
454
+
455
+ Generate enemies and balanced encounters using the `EnemyGenerator` class. The system uses **two independent axes** for enemy creation:
456
+
457
+ | Concept | Determines | Examples |
458
+ |---------|------------|----------|
459
+ | **Challenge Rating (CR)** | Power level (stats, HP, level) | Weak beast vs. ancient dragon |
460
+ | **Rarity** | Complexity (abilities, resistances) | Simple guard vs. complex spellcaster |
461
+
462
+ **Key principle:** Any CR can combine with any rarity.
463
+
464
+ **For detailed documentation**, see [ENEMY_GENERATION.md](features/ENEMY_GENERATION.md) for:
465
+ - Complete template list
466
+ - Rarity tier breakdowns
467
+ - Leader promotion system
468
+ - Audio-influenced generation
469
+ - Encounter balance formulas
470
+
471
+
472
+ ---
473
+
474
+
475
+ ## Extensibility System
476
+
477
+ The extensibility system allows you to add custom content at runtime, including spells, equipment, races, classes, features, skills, and appearance options.
478
+
479
+ **Detailed guides:**
480
+ - [features/EXTENSIBILITY_GUIDE.md](features/EXTENSIBILITY_GUIDE.md) - Complete extensibility system (custom content, spawn rates, export/import, content packs)
481
+ - [features/CUSTOM_CONTENT.md](features/CUSTOM_CONTENT.md) - Custom races, subraces, and classes
482
+ - [features/CONTENT_PACKS.md](features/CONTENT_PACKS.md) - Content packs with data of many types all in one file.
483
+ - [features/PREREQUISITES.md](features/PREREQUISITES.md) - Skill, spell, and feature prerequisites
484
+ - [DATA_ENGINE_REFERENCE.md](DATA_ENGINE_REFERENCE.md) - Complete API reference
485
+
486
+ ---
487
+
488
+
489
+ ## Equipment System
490
+
491
+ Comprehensive equipment system with custom items, properties, enchanting, templates, batch spawning, and box-type containers.
492
+
493
+ **See [EQUIPMENT_SYSTEM.md](features/EQUIPMENT_SYSTEM.md)** for:
494
+ - Equipment properties — Stat bonuses, skills, abilities, damage, conditions
495
+ - Equipment modification — Enchanting, cursing, upgrading at runtime
496
+ - Equipment spawning — Batch spawn by rarity, tags, or templates
497
+ - Equipment-granted features — Items that grant features, skills, or spells
498
+ - Box items — Containers, adventure packs, and loot boxes
499
+
500
+ ---
501
+
502
+ ## Validation Schemas
503
+
504
+ Zod schemas for runtime validation (`PlaylistTrackSchema`, `ServerlessPlaylistSchema`, `AudioProfileSchema`, `AbilityScoresSchema`, `CharacterSheetSchema`). Use for API validation, type guards, or form data.
505
+
506
+ ```typescript
507
+ import { CharacterSheetSchema } from 'playlist-data-engine';
508
+
509
+ const result = CharacterSheetSchema.safeParse(externalData);
510
+ if (!result.success) {
511
+ console.error('Invalid:', result.error.format());
512
+ }
513
+ ```
514
+
515
+ ---
516
+
517
+
518
+
519
+ ## Available Exports
520
+
521
+ For a complete reference of all exports from the library, see **[DATA_ENGINE_REFERENCE.md](DATA_ENGINE_REFERENCE.md)**.
522
+
523
+ The reference includes:
524
+ - **Quick Export Reference** — Concise overview of all exports organized by category
525
+ - **Data Types** — Complete type definitions for all core data structures
526
+ - **Core Modules** — PlaylistParser, AudioAnalyzer, CharacterGenerator, and more
527
+ - **Progression System** — XP calculation, level-ups, stat increases
528
+ - **Equipment System** — Properties, enchanting, spawning, templates
529
+ - **Extensibility System** — ExtensionManager, FeatureQuery, SkillQuery, SpellQuery
530
+ - **Combat System** — Turn-based combat, initiative, dice rolling
531
+ - **Configuration** — Sensor and progression configuration
532
+ - **Utilities** — Seeded RNG, logging, validation schemas
533
+
534
+ ---
535
+
536
+ ## Development Workflow
537
+
538
+ **Watch mode**: `npm run dev` rebuilds on file changes.
539
+
540
+ When developing with `file://` or `npm link`: changes in `src/` are available immediately after rebuild.
541
+
542
+ **For complete environment configuration, see [`.env.example`](.env.example)** in the project root.
543
+
544
+ ---
545
+
546
+ ## Environment Variables
547
+
548
+ | Variable | Purpose |
549
+ |----------|---------|
550
+ | `WEATHER_API_KEY` | OpenWeatherMap API key for weather-based XP modifiers |
551
+ | `STEAM_API_KEY` | Steam Web API key for game detection |
552
+ | `STEAM_USER_ID` | Your 64-bit Steam ID |
553
+ | `XP_MAX_MODIFIER` | Maximum XP multiplier (default: 3.0) |
554
+
555
+ All variables are optional. For complete configuration with examples and programmatic options, see **[`.env.example`](.env.example)**.
556
+
557
+ ---
558
+
559
+ ## Arweave Gateway Resolution
560
+
561
+ The engine includes a built-in Arweave gateway manager that automatically provides fallback to alternate gateways when Arweave URLs fail. `MusicClassifier`, `EssentiaPitchDetector`, `ColorExtractor`, and `PlaylistParser` all use this automatically — no configuration needed.
562
+
563
+ For direct use in your application:
564
+
565
+ ```typescript
566
+ import { arweaveGatewayManager } from 'playlist-data-engine';
567
+
568
+ // Resolves Arweave URLs with automatic fallback to working gateways
569
+ const workingUrl = await arweaveGatewayManager.resolveUrl('https://arweave.net/txId/model.json');
570
+
571
+ // Non-Arweave URLs are returned unchanged
572
+ const regularUrl = await arweaveGatewayManager.resolveUrl('https://example.com/file.json');
573
+ ```
574
+ ---
575
+
576
+ ## Troubleshooting
577
+
578
+ ### Library changes not reflecting
579
+ - With `npm link`: Changes are instant
580
+ - With `file://` paths: Run `npm run build` in the library, then clear your project's cache: `rm -rf node_modules/.bin/playlist-data-engine`
581
+
582
+ ### Audio analysis not working
583
+ The `AudioAnalyzer` uses the Web Audio API, which requires:
584
+ 1. A browser environment, **or**
585
+ 2. A Node.js polyfill like `web-audio-api`
586
+
587
+ For TypeScript configuration issues, ensure `tsconfig.json` has `"moduleResolution": "node"` and `"esModuleInterop": true`.