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.
- package/README.md +20 -3
- package/bin/cli.cjs +85 -0
- package/dist/core/parser/TrackExtras.d.ts +150 -1
- package/dist/core/parser/TrackExtras.d.ts.map +1 -1
- package/dist/gateway-CDMPqFEH.js +1320 -0
- package/dist/gateway-DKa45Uz6.cjs +6 -0
- package/dist/gateway.d.ts +3 -1
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +1 -1
- package/dist/gateway.mjs +22 -14
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/playlist-data-engine.js +34 -34
- package/dist/playlist-data-engine.mjs +964 -1240
- package/dist/utils/engineDocs.d.ts +33 -0
- package/dist/utils/engineDocs.d.ts.map +1 -0
- package/dist/utils/playlistUtils.d.ts +37 -0
- package/dist/utils/playlistUtils.d.ts.map +1 -1
- package/dist/utils/validators.d.ts +27 -0
- package/dist/utils/validators.d.ts.map +1 -1
- package/docs/DATA_ENGINE_REFERENCE.md +6660 -0
- package/docs/USAGE_IN_OTHER_PROJECTS.md +587 -0
- package/docs/features/AUDIO_ANALYSIS.md +610 -0
- package/docs/features/BEAT_DETECTION.md +5250 -0
- package/docs/features/COMBAT_SYSTEM.md +1632 -0
- package/docs/features/CONTENT_PACKS.md +464 -0
- package/docs/features/CUSTOM_CONTENT.md +603 -0
- package/docs/features/ENEMY_GENERATION.md +1711 -0
- package/docs/features/EQUIPMENT_SYSTEM.md +2279 -0
- package/docs/features/EXTENSIBILITY_GUIDE.md +1106 -0
- package/docs/features/GATEWAY_RESOLUTION.md +725 -0
- package/docs/features/IRL_SENSORS.md +360 -0
- package/docs/features/PLAYLIST_PARSING.md +446 -0
- package/docs/features/PREREQUISITES.md +571 -0
- package/docs/features/ROLLS_AND_SEEDS.md +687 -0
- package/docs/features/XP_AND_STATS.md +1221 -0
- package/llms.txt +33 -0
- package/package.json +9 -2
- package/skills/playlist-data-engine/SKILL.md +69 -0
- package/dist/gateway-DUk4nCao.cjs +0 -1
- 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`.
|