Mixtape Component Refinement Spec
Built for offline playback, emotional clarity, and HTML-level storytelling
The following specification is the origin story of Skirbi. It isn’t implemented yet. And it probably violates some principles of current day Skirbi, but fuck it, it’s here.
Mixtape Component Refinement Spec
Canonical Elements
| Element | Purpose | Notes |
|---|---|---|
<chapter> |
Groups a themed collection | Represents a tape side or segment |
<playlist> |
Holds <track-item>s |
Main container |
<track-item> |
Defines one audio/video imprint | Can be hidden, aliased |
<playback> |
Triggers playback (global/local) | Replaces queue-playlist |
Supported Aliases
For <track-item>
| Alias | Description |
|---|---|
imprint |
Poetic emphasis on intent |
bonus-track |
Hidden or post-arc material |
skit |
Spoken interlude or vignette |
intro |
Prelude or thematic opener |
reprise |
Return or variation |
All aliases map to
TrackItemlogic.
customElements.define('imprint', TrackItem);
customElements.define('bonus-track', TrackItem);
// etc.
For <playlist>
| Alias | Description |
|---|---|
tracklist |
Structural clarity |
setlist |
Concert or performance metaphor |
All aliases map to
playlistbehavior. No logic changes.
Chapter Structure
<chapter name="sideA" tagline="Letters I Never Sent">
<playlist>
<track-item ... />
<track-item ... />
</playlist>
<playback type="audio">▶ Play Side A</playback>
</chapter>
Attributes
| Attribute | Purpose |
|---|---|
name |
Internal label (non-visible) |
tagline |
Subtitle or short description |
hidden |
Visually hides the entire chapter |
playHidden="0" |
Prevents hidden chapters from being included in playback |
audioBase / videoBase / artBase |
Base paths for resolving track assets |
Playback Behavior
<playback type="audio">
Triggers either global or local queue based on DOM position.
| Position | Scope |
|---|---|
Inside <chapter> |
Local to chapter |
| Outside chapters | Global (all playlists) |
Playback Inclusion Flags
| Attribute | Plays? | Visible? | Description |
|---|---|---|---|
| — | ✅ | ✅ | Default |
hidden |
✅ | ❌ | Hidden track (like a CD bonus) |
hidden + playHidden="0" |
❌ | ❌ | Fully skipped |
playHidden="0" (alone) |
✅ | ✅ | No effect unless hidden |
Hidden tracks play unless explicitly told not to. Like real mixtapes.
Player Structure
<div id="playerSection">
<button id="closePlayer">...</button>
<audio id="audioPlayer" controls></audio>
<video id="videoPlayer" controls></video>
<div id="queueControls">
<button id="prevTrack">⏮</button>
<div id="trackMeta">
<strong id="trackTitle">Title</strong>
<span id="trackArtist">Artist</span>
</div>
<button id="nextTrack">⏭</button>
</div>
</div>
Styling Tips
- Use CSS only to reposition metadata (
#trackMeta) - Change layout via grid/flex to match mood
- Move controls left/right based on UX tone
Hidden Tracks & Discovery
- Hidden tracks can be unlocked at runtime via
removeAttribute('hidden') - Tracks with
playHidden="0"remain excluded even when hidden - Typical use: easter eggs, emotional reveals, interludes
Future-Proof Design
| Feature | Current Status | Future Option |
|---|---|---|
| Shuffle mode | Manual | mode="shuffle" |
| Playback limits | Scoped | target="chapterX" |
| Custom styling | Author-driven | Tag-specific theming via CSS |
Naming Philosophy
- playlist is familiar and keeps the HTML human
- playback aligns with physical metaphor (play the tape)
- track-item is literal; aliases like
imprintgive emotional weight - Chapters are structural and thematic containers — mix sides, arcs, or acts
<mixtape> — Root-Level Configuration Container
The <mixtape> tag acts as the top-level element for a mixtape instance, allowing shared configuration and asset path definitions, as well as overall metadata.
Purpose
- Set global paths for media resolution
- Provide shared config for all nested
track-items - Contain multiple
<chapter>s or playlists - Define mixtape-level name and tagline
Example
<mixtape
name="The One That Wasn't"
tagline="A mixtape for a moment that never began"
audioBase="../audio/"
videoBase="../video/"
artBase="../art/"
>
<chapter name="A" tagline="Intro / Side A">
<playlist>
<track-item song="Rocket Man" artist="Elton John" track="A01-Rocket_Man" />
</playlist>
<playback type="audio">▶ Play Side A</playback>
</chapter>
</mixtape>
Attributes
| Attribute | Purpose |
|---|---|
name |
Internal identifier for the mixtape |
tagline |
Descriptive or poetic subtitle |
audioBase |
Base folder for .mp3 or .m3u |
videoBase |
Base folder for .mp4 or .m3u |
artBase |
Base path for cover art/thumbnails |
If omitted, base paths default to ./audio/, etc.
Scoping Behavior
- Attributes on
<mixtape>are inherited by nested elements unless overridden - Chapters or tracks can override media paths if needed
Semantic Track Aliases with Behavior
Unlike purely visual tags, some aliases carry built-in behavior to mirror real-world mixtape, CD, or vinyl structures. Authors can still override these via attributes.
Behavior Table
| Alias | Base Tag | hidden |
playHidden |
Purpose |
|---|---|---|---|---|
bonus-track |
track-item |
✅ | 1 |
Hidden track that still plays |
intro |
track-item |
❌ | 0 |
Thematic opening, never skipped |
interlude |
track-item |
✅ | 1 |
Mood-setter or ambient filler |
skit |
track-item |
❌ | 1 |
Spoken word / vignette |
reprise |
track-item |
❌ | 1 |
Musical callback |
outro |
track-item |
❌ | 0 |
Closing gesture, always plays |
live-track |
track-item |
❌ | 1 |
Recorded performance |
instrumental |
track-item |
❌ | 1 |
No vocals version |
remix |
track-item |
❌ | 1 |
Altered or alternate version |
imprint |
track-item |
❌ | 1 |
Optional poetic alias (docs only) |
All of these are just aliases for
TrackItem, but some come with default attributes applied.
JavaScript Implementation (Concept)
function defineAlias(tag, defaults = {}) {
class AliasTrackItem extends TrackItem {
connectedCallback() {
for (const [attr, val] of Object.entries(defaults)) {
if (!this.hasAttribute(attr)) {
this.setAttribute(attr, val);
}
}
super.connectedCallback();
}
}
customElements.define(tag, AliasTrackItem);
}
defineAlias('bonus-track', { hidden: '', playHidden: '1' });
defineAlias('intro', { playHidden: '0' });
defineAlias('interlude', { hidden: '', playHidden: '1' });
// Add remaining aliases as needed...
Authors may override any default by explicitly setting
hidden,playHidden, etc.
Summary
You now have:
- A clean, offline-compatible HTML format
- Fully scoping playback and visibility
- Themeable naming via aliasing
- CSS-driven layout customization
- Media-rich storytelling via Web Components