Personal Library Format
PBE Karaoke ships with no song content at all. To study with it, you point it at a library manifest — a JSON file describing your own already-cleared recordings and the words/timing to sing along with them — plus the audio files that manifest refers to. This page describes what that manifest and its accompanying audio folder need to look like.
Loading a Library
Once you have a manifest and its audio files ready, the gate on the main page accepts them three ways:
-
Hosted URL — paste a link to the manifest JSON (or add
?library=<url>to the app's address). The audio files it points to must be reachable at that same URL's host, over a server that supports HTTP Range requests (virtually every static host does; see the app'sREADME.mdif you're setting up your own). - Upload Manifest File… — pick a manifest JSON file straight from disk. Handy for testing, or when someone hands you the file directly. It isn't remembered between visits, so it needs re-uploading each time.
- Load Local Folder… (Chrome/Edge only) or a shared OneDrive folder link — point the app at a whole folder containing both the manifest and the audio files, and it reads everything straight from there with no hosting required. See "Folder Structure" below for exactly what that folder needs to contain.
Manifest Shape
The manifest is a single JSON object with three top-level fields:
{
"year": "2026-2027",
"styles": [ ... ],
"sections": [ ... ]
}
year | Any string. Not shown in the UI — just a label for the manifest itself. |
|---|---|
styles | The list of musical styles used anywhere in sections. See below. |
sections | One entry per chapter (or verse range) you have recordings for. See below. |
styles
{
"id": "contemporarychristian",
"label": "Contemporary Christian",
"emoji": "🙏",
"churchFit": "great-match"
}
id | Required. Short, stable, unique identifier — this is what each recording's style field points back to. |
|---|---|
label | Required. Human-readable name shown in the style picker. |
emoji | Optional. One vibe emoji shown next to the label. |
churchFit | Optional. One of "great-match", "nervous", or "very-uncomfortable" — shown as a face icon. Leave it out if you'd rather not rate it; the app just shows the label. |
sections & recordings
Each section covers one chapter, or one verse range within a chapter, and lists every recording available for it:
{
"book": "Mark",
"chapter": 6,
"verseStart": 30,
"verseEnd": 56,
"recordings": [
{
"style": "contemporarychristian",
"take": 1,
"instrumentalUrl": "Mark 6_30-56 (1).instrumental.m4a",
"vocalUrl": "Mark 6_30-56 (1).vocal.m4a",
"words": [
{ "word": "Now", "start": 0.42, "end": 0.71, "verse": 30 },
{ "word": "the", "start": 0.71, "end": 0.85, "verse": 30 },
{ "word": "apostles", "start": 0.85, "end": 1.38, "verse": 30 }
]
}
]
}
book | Book name exactly as it should be displayed and grouped in the passage picker. |
|---|---|
chapter | Chapter number. |
verseStart / verseEnd | Optional. Omit both (or set to null) for a whole-chapter section. |
recordings | At least one recording, described below. A section can have several — different styles, or multiple takes of the same style. |
Each entry in recordings:
style | Must match one of the top-level styles[].id values. |
|---|---|
take | A number distinguishing alternate recordings of the same section+style. Any distinct numbers work — they don't need to start at 1 or be contiguous. |
instrumentalUrl / vocalUrl | Two separate audio files for the same recording — one with vocals removed, one with just the vocals — rather than a single mixed track. The app always plays both together and fades only the vocal track in and out, so the two files must be the same length and stay in sync. Any browser-playable audio format works (e.g. mp3, m4a, wav). See "Folder Structure" below for what these paths should look like. |
words | Word-by-word timing for this specific recording, described below. |
words
An ordered array covering every word in the recording, used to drive the karaoke highlight, the blanking/recall study modes, and Type Ahead/Sing-Along scoring:
{ "word": "apostles", "start": 0.85, "end": 1.38, "verse": 30 }
word | The word as it should be displayed. |
|---|---|
start / end | Seconds into this recording's own audio files (not the section, not a global clock) when the word is sung. |
verse |
The verse number this word belongs to. Use null for words that aren't part
of the scripture text itself (a spoken intro, an ad-lib, filler) — those play normally
but are excluded from study/scoring and from the verse picker.
|
Folder Structure (Local Folder / OneDrive Folder)
For a hosted URL, folder layout doesn't matter — only that instrumentalUrl
and vocalUrl are correct, reachable URLs. For "Load Local Folder…" or a
shared OneDrive folder link, the app reads relative to whatever single folder you point
it at, so that folder needs a specific shape:
- The manifest file must sit at the root of that folder, named exactly
manifest.local.json. -
Every
instrumentalUrl/vocalUrlin the manifest must be a path relative to that same root (forward slashes, subfolders allowed) pointing to a file that actually exists there.
For example, a folder organized by style:
My Library/
├── manifest.local.json
├── Contemporary Christian/
│ ├── Mark 6_30-56 (1).instrumental.m4a
│ └── Mark 6_30-56 (1).vocal.m4a
└── Broadway/
├── Mark 6_30-56 (1).instrumental.m4a
└── Mark 6_30-56 (1).vocal.m4a
would need the matching recording entry to read:
"instrumentalUrl": "Contemporary Christian/Mark 6_30-56 (1).instrumental.m4a",
"vocalUrl": "Contemporary Christian/Mark 6_30-56 (1).vocal.m4a"
Any folder layout works as long as the paths line up — a single flat folder of audio files is just as valid as one organized by style or by book.