Split demo seed into Styles + Practice; add shuffle/samba/nañigo

Two seed set lists instead of one mixed "Demos":
- 🥁 Styles — grooves/feels: four-on-the-floor, swing ride, Purdie
  half-time shuffle (triplet grid, backbeat on 3, snare ghosts), Samba
  (2/4, surdo on 2), Nañigo (6/8 bembé bell), 6/8, 7/8, 5/4.
- 🎯 Practice — polyrhythms, triplet hats, accent demo, tempo builder,
  gap trainer.

Seed is now versioned + additive: a bumped SEED_VERSION adds any seed
list whose title isn't already present, without clobbering or re-adding
the user's lists.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Me Here 2026-05-25 11:51:45 -05:00
parent 766d5d40ae
commit 8171b37e72

View file

@ -1184,19 +1184,29 @@ function applyHashShare() {
} }
// Demo set list (each item authored in the share language — also exercises the parser). // Demo set list (each item authored in the share language — also exercises the parser).
const DEMOS = [ const SEED_SETLISTS = [
["Four-on-the-floor", "t120;kick:4;snare:4=.x.x;hatClosed:4/2"], { title: "🥁 Styles", description: "Grooves & feels — load one, press Space, and click pads to shape the accents.", items: [
["Swing ride", "t150;ride:4/2s;kick:4=X..x;snare:4=.x.x"], ["Four-on-the-floor", "t120;kick:4;snare:4=.x.x;hatClosed:4/2"],
["Accents (click a pad to cycle)", "t92;kick:4=X..X;snare:4=.X.X;hatClosed:4/2"], ["Swing ride", "t150;ride:4/2s;kick:4=X..x;snare:4=.x.x"],
["5 over 4 polyrhythm", "t100;kick:4;claves:5~"], // Purdie half-time shuffle: triplet grid, backbeat on 3, snare ghosts (normal) around it
["3 over 2 hemiola", "t96;woodblock:2;cowbell:3~"], ["Purdie half-time shuffle", "t92;kick:4/3=X....x...x..;snare:4/3=..xx.xX.xx.x;hatClosed:4/3=X.xX.xX.xX.x"],
["2 & 4 & 3 over one bar", "t100;kick:3;cowbell:2~;claves:4~"], // Samba in 2/4 (16ths): surdo strong on beat 2, steady ganzá, tamborim teleco-teco
["7/8 (2+2+3)", "t130;kick:2+2+3=x..x..x;hatClosed:2+2+3/2"], ["Samba (2/4)", "t104;tomLow:2/4=x...X...;hatClosed:2/4;woodblock:2/4=X.xx.xX."],
["6/8 groove", "t100;kick:3+3=x..x..;snare:3+3=...x..;hatClosed:3+3/2"], // Nañigo / 6/8 bembé bell over a 12/8 grid, low drum on the two main pulses
["5/4 (3+2)", "t112;kick:3+2=x..x.;snare:3+2=..x..;hatClosed:3+2/2"], ["Nañigo (6/8 bembé)", "t130;cowbell:4/3=X.xx.x.xx.x.;kick:4/3=X.....X.....;hatClosed:4/3=..x..x..x..x"],
["Triplet hats", "t100;kick:4;snare:4=.x.x;hatClosed:4/3"], ["6/8 groove", "t100;kick:3+3=x..x..;snare:3+3=...x..;hatClosed:3+3/2"],
["Tempo builder 80↑", "t80;woodblock:4;rmp80/4/4"], ["7/8 (2+2+3)", "t130;kick:2+2+3=x..x..x;hatClosed:2+2+3/2"],
["Gap trainer (play 2 / rest 2)", "t100;kick:4;hatClosed:4/2;tr2/2"], ["5/4 (3+2)", "t112;kick:3+2=x..x.;snare:3+2=..x..;hatClosed:3+2/2"],
] },
{ title: "🎯 Practice", description: "Polyrhythms, independence and tempo / gap tools.", items: [
["5 over 4 polyrhythm", "t100;kick:4;claves:5~"],
["3 over 2 hemiola", "t96;woodblock:2;cowbell:3~"],
["2 & 4 & 3 over one bar", "t100;kick:3;cowbell:2~;claves:4~"],
["Triplet hats", "t100;kick:4;snare:4=.x.x;hatClosed:4/3"],
["Accents — cycle the pads", "t92;kick:4=X..X;snare:4=.X.X;hatClosed:4/2"],
["Tempo builder 80↑", "t80;woodblock:4;rmp80/4/4"],
["Gap trainer (play 2 / rest 2)", "t100;kick:4;hatClosed:4/2;tr2/2"],
] },
]; ];
/* ========================================================================= /* =========================================================================
@ -1427,13 +1437,19 @@ window.addEventListener("keydown", (e) => {
}); });
/* init */ /* init */
// seed the demo set list once (first run only; not re-added if the user deletes it) // Seed the demo set lists. Versioned + additive: a newer SEED_VERSION adds any
if (!lsGet(LS.seeded, false)) { // seed list whose title isn't already present, without clobbering the user's lists
if (!setlists.length) { // (and won't re-add one they've deleted at the same version).
setlists.push({ title: "✨ Demos", description: "Click an item to load it, then press Space — meters, polyrhythms, odd time, subdivisions & practice tools.", items: DEMOS.map(([n, p]) => ({ name: n, ...patchToSetup(p) })) }); const SEED_VERSION = 2;
activeSL = 0; saveSetlists(); if ((lsGet(LS.seeded, 0) | 0) < SEED_VERSION) {
for (const s of SEED_SETLISTS) {
if (!setlists.some((x) => x.title === s.title)) {
setlists.push({ title: s.title, description: s.description, items: s.items.map(([n, p]) => ({ name: n, ...patchToSetup(p) })) });
}
} }
lsSet(LS.seeded, true); if (activeSL >= setlists.length) activeSL = Math.max(0, setlists.length - 1);
saveSetlists();
lsSet(LS.seeded, SEED_VERSION);
} }
// a shared link (#p=… settings / #sl=… set list) sets the state; otherwise default lanes // a shared link (#p=… settings / #sl=… set list) sets the state; otherwise default lanes
if (!applyHashShare()) { if (!applyHashShare()) {