All data exchanged between the static file server and the browser is plain JSON or Markdown. There is no dynamic API — the browser loads a manifest, fetches per-song JSON and Markdown files, and fetches pre-generated peak data for waveform rendering. This page documents every TypeScript interface that describes those files, where each file lives on disk, and how the files are generated.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/cocreating/4StemPlayer/llms.txt
Use this file to discover all available pages before exploring further.
Complete Type Definitions
The canonical source of truth issrc/lib/types.ts. The full file is reproduced here for reference:
SongMetadata
File:static/songs/<Folder>/song.json
SongMetadata is the shape of each song’s song.json file. It carries all human-readable and structural information about the song.
The display title of the song, for example
"Glory Box".The artist or band name, for example
"Portishead".The musical key of the song, for example
"D minor" or "G major".Beats per minute. Must be a numeric value; the validator rejects string BPM values.
Time signature string, for example
"4/4" or "6/8".Human-readable duration in
m:ss format, for example "5:06". Used by SongInfoPanel when displaying song length. Either duration or durationSeconds (or both) may be present.Total duration in whole seconds, for example
306. The UI derives a formatted string from this when duration is absent.Chord information. Can be a plain legacy string (
"Am - F - C - G") or a structured object whose keys are section identifiers. Each value is either a short progression string or a full ChordSection object. See ChordSection below.Free-form notes about the song — arrangement tips, key changes, capo position, or anything else useful for rehearsal.
Inline lyrics as a plain string. The preferred approach is a separate
lyrics.md file; this field exists for backwards compatibility.Ordered list of named section markers. Each section has a
label, a start time in seconds, and an optional end time. The SectionsPopover component renders these as jump buttons. See SectionMarker below.Example song.json
ChordSection
ChordSection is the structured form of a single chord section inside the chords map.
Display label for the section, for example
"Verse". When absent, the key from the parent object is title-cased and used as the label.The chord progression for this section, for example
"Am - F - C - G".Additional notes specific to this section, for example
"Repeat 4×" or "Half-time feel".SectionMarker
SectionMarker describes a named point or range in the song timeline, used for jump-to-section navigation.
Human-readable section name, for example
"Chorus", "Bridge", or "Guitar Solo".Start time in seconds from the beginning of the song.
End time in seconds. When absent the section is treated as a point marker rather than a range.
SongManifestEntry
File:static/songs/manifest.json → .songs[]
Each entry in the manifest corresponds to one song folder. AppShell uses entries to populate the song selector and to construct the LoadableSong passed to AudioEngine.loadSong().
Unique song identifier derived from the folder name, for example
"GloryBox".The song’s folder name under
static/songs/, for example "GloryBox".Song title, copied from
song.json at manifest generation time.Artist name, copied from
song.json.BPM, copied from
song.json.Musical key, copied from
song.json.Time signature, copied from
song.json.URL-encoded path to the song’s
song.json, for example /songs/GloryBox/song.json.URL-encoded path to the song’s
lyrics.md, for example /songs/GloryBox/lyrics.md.Map of stem name to URL-encoded MP3 path. Always includes at minimum
bass, drums, and vocals. May also include guitar, strings, fx, and other if those files exist in the folder. Example:Map of stem name to URL-encoded peaks JSON path. Present only for stems whose When a peaks file is absent for a stem, WaveSurfer fetches and decodes the MP3 to generate the waveform on the fly — which is slower and uses more CPU.
.peaks.json file exists. Example:SongManifest
File:static/songs/manifest.json
The top-level manifest file loaded at startup by loadSongManifest().
ISO 8601 timestamp of when the manifest was last generated, for example
"2026-05-20T14:32:00.000Z". Updated every time songs:prepare runs.Ordered list of all song entries. The order matches the filesystem sort order of song folders.
Example manifest.json (abbreviated)
manifest.json is regenerated every time songs:prepare runs. The generatedAt field always updates, even if the songs themselves have not changed. Commit the updated manifest to source control after adding or renaming any song file.SongBundle
SongBundle is the runtime in-memory object AppShell holds once a song has been fully loaded. It is never written to disk.
The original manifest entry for the song, providing stem URLs, peaks URLs, and basic display metadata.
The full parsed
song.json object, including chords, notes, sections, and timing metadata.The raw Markdown text from
lyrics.md. Displayed by LyricsViewer inside a preserved-whitespace block. May be an empty string if the file exists but is empty (the validator treats an empty lyrics file as a warning, not an error).PeaksFile
File:static/songs/<Folder>/<stem>.peaks.json
Peak files let WaveSurfer render waveforms without re-decoding the MP3. Each stem has its own peaks file generated from the same MP3 used for playback.
The sample rate used when generating the peaks, always
8000 Hz (down-sampled mono for compact file size).How many audio samples each peak value represents. Determines the horizontal resolution of the waveform.
Array of peak magnitude values, one entry per
samplesPerPixel block. Values are floats in the range [0, 1]. Passed directly to the WaveSurfer peaks option.Example peaks file (abbreviated)
File Locations Summary
| File | Path on disk | Served at |
|---|---|---|
| Song metadata | static/songs/<Folder>/song.json | /songs/<Folder>/song.json |
| Lyrics | static/songs/<Folder>/lyrics.md | /songs/<Folder>/lyrics.md |
| Stem MP3 | static/songs/<Folder>/<Folder>_<stem>.mp3 | /songs/<Folder>/<Folder>_<stem>.mp3 |
| Peak data | static/songs/<Folder>/<stem>.peaks.json | /songs/<Folder>/<stem>.peaks.json |
| Manifest | static/songs/manifest.json | /songs/manifest.json |
Generating the Manifest
Regeneratemanifest.json after adding, removing, or renaming any song file:
scripts/generate-song-manifest.ts) URL-encodes all asset paths so that folder and file names containing spaces are safe for use in fetch() calls.
Generating Peak Files
Peak files are generated byscripts/generate-peaks.ts, which shells out to ffmpeg:
ffmpeg converts each stem MP3 to mono float PCM at 8000 Hz, then the script computes peak magnitudes and writes *.peaks.json. Existing peak files are skipped unless they are older than their source MP3, keeping incremental runs fast.
Running the complete release pipeline — which includes validation, peaks generation, manifest regeneration, type checking, unit tests, and a production build — is the recommended pre-deploy command: