feat(audio): Music becomes a crossfading playlist of 5 mellow synth tracks
Replace the single ethereal loop with the operator's chosen set — Music for Manatees, Dewdrop Fantasy, Eastminster, Overheat, Concentration (Kevin MacLeod, CC BY 4.0, drumless). The Music source now plays one track and every 5 min crossfades to a random OTHER track (pure HEFScrub.pickNextIndex, never an immediate repeat), altitude-independent, reusing the two audio elements; both primed in-gesture for Safari. Intervals injectable via window.__hefMusicRotateMs / __hefMusicXfadeMs. Media loudness-normalized + transcoded under the 25MB LFS limit (build_audio_media MUSIC), committed via LFS; ethereal loop retired. CC-BY attribution added to credits.html. Docs updated (music-candidate-pool = final set; audio-candidate-pool ethereal section superseded). +2 node unit (pickNextIndex), +2 e2e (music-playlist), audio-source spec updated. 40 unit + 49 e2e green; live probe confirms playback + rotation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,26 @@ test("audioPlan: Music ignores altitude fraction (constant across the dial)", ()
|
||||
assert.deepEqual(a, b);
|
||||
});
|
||||
|
||||
test("pickNextIndex: never returns the current track; covers the rest", () => {
|
||||
// r in [0,1) maps onto the (count-1) other indices, skipping `current`.
|
||||
assert.equal(S.pickNextIndex(0, 5, 0), 1);
|
||||
assert.equal(S.pickNextIndex(0, 5, 0.999), 4);
|
||||
assert.equal(S.pickNextIndex(2, 5, 0), 0);
|
||||
assert.equal(S.pickNextIndex(2, 5, 0.5), 3);
|
||||
assert.equal(S.pickNextIndex(4, 5, 0.999), 3);
|
||||
// sweep: for each current, every r lands somewhere valid and never on current
|
||||
for (let cur = 0; cur < 5; cur++) {
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const n = S.pickNextIndex(cur, 5, i / 20);
|
||||
assert.ok(n >= 0 && n < 5 && n !== cur, `cur=${cur} r=${i / 20} -> ${n}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("pickNextIndex: single-track playlist stays on 0", () => {
|
||||
assert.equal(S.pickNextIndex(0, 1, 0.7), 0);
|
||||
});
|
||||
|
||||
test("audioPlan: Soundtrack blends lo/hi by fraction, scaled by level", () => {
|
||||
assert.deepEqual(S.audioPlan("soundtrack", 1, 0), { mode: "blend", lo: 1, hi: 0 });
|
||||
assert.deepEqual(S.audioPlan("soundtrack", 1, 1), { mode: "blend", lo: 0, hi: 1 });
|
||||
|
||||
Reference in New Issue
Block a user