♪⬛ Global Scale + Play One — one key for the planet, glitch by chance
Global Scale (Live 12 Scale Awareness §3.13): a root + scale the whole groove editor sings in. The piano-roll rows ARE the scale degrees (always folded to scale), so every melody is in key; change the scale and drawn patterns re-harmonise in place. Travels with the patch. Play One (adapted from Ableton's Group Notes → Play One): a piano-roll column can hold several candidate degrees — stack them (they turn blue) and the sequencer picks one at random each fire. Stack in-scale notes under a fast Euclidean fill and the line glitches itself, always in key. Applied in both grid editors, seqTick, and .mid export (prints the first candidate). Self-check guards scaleRows + the stack helpers. Grimoire + manual in sync. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
d4a1b71427
commit
f65598a988
@ -540,6 +540,8 @@ Learn these seven gestures and the whole planet is under your hands:
|
||||
|
||||
- **The Groove — one feel for the whole pattern.** The grooves tab carries Ableton's Groove Pool, reduced to the 16-step grid: **swing** lays the off-beats back, **humanize** is a touch of random timing so nothing is machine-stiff, **velocity** lets each hit breathe in loudness, and an **amount** master scales the lot — with one-click presets (*straight, swing 16, MPC 8-4, drunk*). Under the roll sit two expression lanes: **velocity** (how hard each step hits) and **chance** (how likely each step fires at all — drop a step to 40% and it plays four times in ten, so the loop varies itself). The feel and the per-step shaping **save with your patch**. And any lane takes a **⬢ Euclidean fill** — say how many *pulses* to spread across the steps and they distribute themselves as evenly as possible (E(3,8) is the tresillo, E(5,8) the cinquillo, E(4,16) four-on-the-floor), with *steps* and *rotate* to taste: the oldest rhythms of the world fall straight out of the arithmetic.
|
||||
|
||||
- **♪ One scale for the whole planet, and ⬛ Play One for the glitch.** Set a **root and scale** at the top of the grooves tab and every melody you draw is in that key — the piano roll is only ever the scale's own notes, so nothing lands wrong; change the scale and your patterns *re-harmonise* in place. And a column isn't limited to one note: **stack several** and it turns blue — a **Play One** group, from which the sequencer picks a single note at random each time it fires. Stack a handful of in-key notes under a fast Euclidean fill and the line glitches itself into something new on every pass, always in tune. (Adapted from Ableton's *Group Notes → Play One*.)
|
||||
|
||||
- **⤳ Follow actions — the song composes itself.** Give any clip (A/B/C) a **follow action** in the grooves tab — *play again, next, any, any other, stop* — with a **chance**, and once the arrangement is playing that clip can hand off to another at the bar line instead of just repeating. Set two clips to "any other" and they trade the lane back and forth; sprinkle a low-chance divert and the piece drifts. As Ableton's manual puts it, "structures that repeat but can also be surprising… never exactly repeat." A ⤳ marks any clip that can divert. Nothing changes for arrangements without follow actions — they loop exactly as written.
|
||||
|
||||
- **📽 The stage — send the visual to any screen.** Right-click the sky → **the stage** and a clean black mirror window opens, fed live from the canvas. Drag it to a projector, an AirPlay display, a second monitor — macOS treats it like any window — and **double-click for fullscreen**. The stage has a **camera**: the whole view by default (whatever you're in — a skin, the wheel, mind mode's POV), or right-click any node → **project this node** and the camera glides after that one sphere through its orbits, or **project its station** to frame a whole wheel and its satellites. Change cameras live from the menus while the projector runs; the audience sees the camera breathe from subject to subject.
|
||||
@ -972,3 +974,5 @@ Every feed the world sends is one of eight temperaments; the shape dictates how
|
||||
- **Per-step expression** — a `velocity` lane (how hard each step hits) and a `chance` lane (0..100% probability the step fires) under the piano roll, per voice. Drop a step's chance and the loop varies itself.
|
||||
- **⤳ Follow Actions** — each arranger clip (A/B/C) can hand off to another at the bar line by chance: again / next / any / any-other / stop. A live overlay diverts playback without rewriting the authored grid; arrangements with no follow actions loop exactly as written. Turns an 8-bar loop into a self-composing structure.
|
||||
- **⬢ Euclidean fills** — Live 12's Euclidean generator (§11.3.5): spread N `pulses` as evenly as possible over the pattern, with adjustable `steps` (cycle length) and `rotate`. E(3,8) tresillo, E(5,8) cinquillo, E(4,16) four-on-the-floor — the world's oldest rhythms falling straight out of the arithmetic. Fills any groove or gate lane.
|
||||
- **♪ Global Scale** — Live 12 Scale Awareness (§3.13): one root + scale (major, dorian, minor pentatonic, hirajoshi, …) that the whole groove editor sings in. The piano roll's rows ARE the scale degrees, so it's always folded-to-scale; change the scale and drawn patterns re-harmonise in place. Travels with the patch.
|
||||
- **⬛ Play One** — adapted from Ableton's Group Notes → Play One: a piano-roll column can hold several candidate degrees (stack them; they turn blue). On each fire the sequencer picks one at random — stack in-scale notes under a fast Euclidean fill and the line glitches itself, always in key. `.mid` export prints the first candidate.
|
||||
|
||||
@ -210,6 +210,8 @@
|
||||
#arranger .acell.hasfollow { position: relative; }
|
||||
#arranger .acell.hasfollow::after { content: "⤳"; position: absolute; top: -2px; right: 2px;
|
||||
font-size: 9px; color: rgba(255,225,150,0.9); }
|
||||
.seqcell.playone { background: rgba(90,150,255,0.9) !important; /* Play-One stack — Ableton blue */
|
||||
box-shadow: inset 0 0 0 1px rgba(175,205,255,0.95); }
|
||||
|
||||
/* the groove grid — piano roll / 808 steps inside a voice's tab */
|
||||
.seqgrid { display: grid; grid-template-columns: repeat(16, 12px); gap: 2px; margin-top: 6px; }
|
||||
@ -957,6 +959,7 @@
|
||||
<li><b>The groove grids — sequence the voices.</b> Open any voice's tab (shift-click it) and there's a <b>16-step grid on the godtime clock</b>. The note voices (<i>lead, bass</i>) get a <b>mini piano roll</b> — eight rows of minor pentatonic, click to place a note, click again to clear — and while your groove is on, <i>your melody replaces the data's</i>: bitcoin lets go of the lead and you take it. Every other voice gets an <b>808-style gate row</b> that rhythmically chops the world's signal — the reverb, the grit, the percussion breathing in your pattern while the planet still decides how hard. Grooves ride the godtime tempo (lock the dial, or let your heart drive it), and they <b>save with your patch</b>. And the <b>sources</b> get the grid too, with a different power: <b>sample & hold</b> — while a source's groove is on, the world's number is only <i>sampled</i> on your lit steps and held between them, so a smooth drifting feed becomes stepped, rhythmic, quantized in time. Bitcoin arpeggiating in your pattern. The wind as a sequence. If an out port is chosen in ⚙, godtime also sends <b>MIDI clock</b> (24 ppqn), so a DAW can slave its tempo to the planet — or to your pulse. And the grids play <i>outward</i> too: with an out port chosen, <b>piano-roll notes go out as real MIDI</b> on the lead and bass channels (each note one sixteenth long), and the <b>mind-mode console plays on its own third channel</b> — so your grooves and your chakra-scale jams drive Ableton, Strudel, or hardware exactly as they drive the built-in synth. The three mouths drink at once: ♪ for the browser synth, the out port for MIDI, both or neither — there is no switch, only where you point the sound.</li>
|
||||
<li><b>Press <kbd>T</kbd> — tracks, for making actual songs.</b> A conventional tracks-and-clips view for anyone who finds the cathedral overwhelming: every voice is a <b>track</b>, eight <b>bars</b> run across, and each cell cycles <b>● live</b> (the world plays that lane) → <b>A</b> → <b>B</b> → <b>C</b> (clip patterns on the groove grids — A and B come pre-seeded so it makes music immediately) → <b>silent</b>. Double-click any clip to edit its groove in the piano roll. Press <b>▶</b> and the arrangement loops on the godtime clock — the planet still plays <i>through</i> your song, because live lanes stay wired to the world. Arrangements <b>save with your patch</b>, play out over MIDI like everything else, and <b>export .mid</b> hands you a Standard MIDI File of the note lanes to drag into Ableton, Logic, anything. Not a DAW — a sketchpad where the world sits in on your session. The panel earns its keep like one, too: a <b>🎛 tracks button</b> sits bottom-right always; <b>drag the panel's top edge to resize</b> (remembered); the top bar <b>tabs between clips and grooves</b> — the grooves tab is a full-size pattern editor (pick a track, pick a letter, big piano roll or 16 steps; double-clicking any clip jumps you straight there); and <b>right-click any track name for that voice's full routing menu</b> — every cable, every level, patch and unpatch without leaving the panel.</li>
|
||||
<li><b>The Groove — one feel for the whole pattern.</b> The grooves tab carries Ableton's Groove Pool, reduced to the 16-step grid: <b>swing</b> lays the off-beats back, <b>humanize</b> is a touch of random timing so nothing is machine-stiff, <b>velocity</b> lets each hit breathe in loudness, and an <b>amount</b> master scales the lot — with one-click presets (<i>straight, swing 16, MPC 8-4, drunk</i>). Under the roll sit two expression lanes: <b>velocity</b> (how hard each step hits) and <b>chance</b> (how likely each step fires at all — drop a step to 40% and it plays four times in ten, so the loop varies itself). The feel and the per-step shaping <b>save with your patch</b>. And any lane takes a <b>⬢ Euclidean fill</b> — say how many <i>pulses</i> to spread across the steps and they distribute themselves as evenly as possible (E(3,8) is the tresillo, E(5,8) the cinquillo, E(4,16) four-on-the-floor), with <i>steps</i> and <i>rotate</i> to taste: the oldest rhythms of the world fall straight out of the arithmetic.</li>
|
||||
<li><b>♪ One scale for the whole planet, and ⬛ Play One for the glitch.</b> Set a <b>root and scale</b> at the top of the grooves tab and every melody you draw is in that key — the piano roll is only ever the scale's own notes, so nothing lands wrong; change the scale and your patterns <i>re-harmonise</i> in place. And a column isn't limited to one note: <b>stack several</b> and it turns blue — a <b>Play One</b> group, from which the sequencer picks a single note at random each time it fires. Stack a handful of in-key notes under a fast Euclidean fill and the line glitches itself into something new on every pass, always in tune. (Adapted from Ableton's <i>Group Notes → Play One</i>.)</li>
|
||||
<li><b>⤳ Follow actions — the song composes itself.</b> Give any clip (A/B/C) a <b>follow action</b> in the grooves tab — <i>play again, next, any, any other, stop</i> — with a <b>chance</b>, and once the arrangement is playing that clip can hand off to another at the bar line instead of just repeating. Set two clips to "any other" and they trade the lane back and forth; sprinkle a low-chance divert and the piece drifts. As Ableton's manual puts it, "structures that repeat but can also be surprising… never exactly repeat." A ⤳ marks any clip that can divert. Nothing changes for arrangements without follow actions — they loop exactly as written.</li>
|
||||
<li><b>📽 The stage — send the visual to any screen.</b> Right-click the sky → <b>the stage</b> and a clean black mirror window opens, fed live from the canvas. Drag it to a projector, an AirPlay display, a second monitor — macOS treats it like any window — and <b>double-click for fullscreen</b>. The stage has a <b>camera</b>: the whole view by default (whatever you're in — a skin, the wheel, mind mode's POV), or right-click any node → <b>project this node</b> and the camera glides after that one sphere through its orbits, or <b>project its station</b> to frame a whole wheel and its satellites. Change cameras live from the menus while the projector runs; the audience sees the camera breathe from subject to subject.</li>
|
||||
<li><b>🕸 The commune — play together, properly.</b> Right-click the sky → <b>the commune</b>. This is for <b>signed-in players</b>: your session rides the connection, so the hub knows exactly who everyone is — no impostors, no setup, no Bluetooth. One of you <b>hosts</b>: name the room, then <b>✉ invite</b> the others by their username (they must be on the site — invitations reach the present). The invited see the invitation arrive live and <b>join or decline</b>; anyone may <b>leave</b> whenever they wish, and if the host leaves, the room closes with them. Then the sections: members <b>claim voices</b> (right-click any voice, or the panel's picker), or the <b>host allocates</b> them — this bass to her, those pads to him, <b>the godtime itself</b> to whoever conducts — and the hub enforces it: only the section's holder can speak for it. From that moment your levels, mutes, grooves and arranger lanes for what you hold follow your hands on every screen, same living room or opposite sides of the earth. The world — the Source — stays identical for everyone, because it always was. Three people, one planet, one instrument.</li></ul>
|
||||
@ -1307,8 +1310,34 @@
|
||||
}
|
||||
}
|
||||
let midiClockPhase = 0; // 24-ppqn accumulator for MIDI clock out
|
||||
const SEQ_ROWS = [0, 3, 5, 7, 10, 12, 15, 17]; // minor pentatonic, two octaves, low->high
|
||||
const seqRootFor = (key) => /bass/.test(key) ? 36 : 60;
|
||||
// The global Scale (Live 12 Scale Awareness §3.13): one root + scale the whole
|
||||
// groove editor sings in. The piano roll's 8 rows ARE the scale degrees (always
|
||||
// "folded to scale"), so every melody you draw is in key; change the scale and
|
||||
// your patterns re-harmonise. Factory data-melodies keep their own tuned scales.
|
||||
const gScale = { root: 0, name: "minor_pent" }; // NOTE_NAMES already defined above (midiToName)
|
||||
function scaleRows(name) { // 8 piano-roll rows from a scale's intervals
|
||||
const s = SCALES[name] || SCALES.minor_pent, rows = [];
|
||||
for (let o = 0; rows.length < 8; o++) for (const iv of s) if (rows.length < 8) rows.push(iv + 12 * o);
|
||||
return rows;
|
||||
}
|
||||
let SEQ_ROWS = scaleRows(gScale.name);
|
||||
const seqRootFor = (key) => (/bass/.test(key) ? 36 : 60) + gScale.root;
|
||||
// "Play One" (adapted from Ableton's Group Notes → Play One): a column may hold
|
||||
// SEVERAL candidate degrees — on each fire, one is chosen at random. Stack a
|
||||
// handful of in-scale notes and the sequence glitches itself, always in key.
|
||||
function stepHas(v, rw) { return Array.isArray(v) ? v.includes(rw) : v === rw; }
|
||||
function stepStack(v) { return Array.isArray(v) && v.length >= 2; }
|
||||
function stepPick(v) { return Array.isArray(v) ? (v.length ? v[Math.floor(Math.random() * v.length)] : -1) : v; }
|
||||
function stepFirst(v) { return Array.isArray(v) ? (v.length ? v[0] : -1) : v; }
|
||||
function stepToggle(steps, stp, rw) { // click a note lane: build/undo a Play-One stack
|
||||
const v = steps[stp];
|
||||
if (Array.isArray(v)) {
|
||||
const i = v.indexOf(rw); if (i >= 0) v.splice(i, 1); else v.push(rw);
|
||||
steps[stp] = v.length === 0 ? -1 : v.length === 1 ? v[0] : v;
|
||||
} else if (v === rw) steps[stp] = -1; // click a lit single → clear
|
||||
else if (v >= 0) steps[stp] = [v, rw]; // a second note in the column → a stack
|
||||
else steps[stp] = rw; // first note
|
||||
}
|
||||
function seqFor(key, isNote) {
|
||||
return seqs[key] || (seqs[key] = {
|
||||
on: false,
|
||||
@ -1419,8 +1448,9 @@
|
||||
if (st !== "A" && st !== "B" && st !== "C") continue;
|
||||
const steps = arrBank(key, true)[st];
|
||||
for (let s2 = 0; s2 < 16; s2++) {
|
||||
if (steps[s2] < 0) continue;
|
||||
const note = root + SEQ_ROWS[steps[s2]], tick = (b * 16 + s2) * TICKS16;
|
||||
const d = stepFirst(steps[s2]); // export the stack's first candidate
|
||||
if (d < 0) continue;
|
||||
const note = root + SEQ_ROWS[d], tick = (b * 16 + s2) * TICKS16;
|
||||
ev.push([tick, 0x90 | ch, note, 100], [tick + TICKS16 - 2, 0x80 | ch, note, 0]);
|
||||
}
|
||||
}
|
||||
@ -1548,11 +1578,28 @@
|
||||
const hint2 = document.createElement("span"); hint2.className = "albl";
|
||||
const nSel = dests.get(arrSelKey);
|
||||
hint2.textContent = nSel.isNote
|
||||
? "piano roll · " + midiToName(seqRootFor(arrSelKey)) + " minor pent · click to place, click again to clear"
|
||||
? "piano roll · " + NOTE_NAMES[gScale.root] + " " + gScale.name.replace("_", " ") + " · click to place · stack 2+ in a column → plays one at random"
|
||||
: "16-step gate · lit steps let the world's signal through";
|
||||
pick.appendChild(hint2);
|
||||
body.appendChild(pick);
|
||||
|
||||
// --- the global Scale (§3.13): root + scale every groove you draw sings in ---
|
||||
const scRow = document.createElement("div"); scRow.className = "arow grow";
|
||||
const scL = document.createElement("span"); scL.className = "glbl"; scL.style.minWidth = "auto"; scL.textContent = "♪ scale";
|
||||
scRow.appendChild(scL);
|
||||
const rootSel = document.createElement("select"); rootSel.className = "asel";
|
||||
NOTE_NAMES.forEach((nm, i) => { const o = document.createElement("option"); o.value = String(i); o.textContent = nm; if (i === gScale.root) o.selected = true; rootSel.appendChild(o); });
|
||||
rootSel.onchange = () => { gScale.root = +rootSel.value; openArranger(); };
|
||||
scRow.appendChild(rootSel);
|
||||
const scaleSel = document.createElement("select"); scaleSel.className = "asel";
|
||||
Object.keys(SCALES).forEach(nm => { const o = document.createElement("option"); o.value = nm; o.textContent = nm.replace("_", " "); if (nm === gScale.name) o.selected = true; scaleSel.appendChild(o); });
|
||||
scaleSel.onchange = () => { gScale.name = scaleSel.value; SEQ_ROWS = scaleRows(gScale.name); openArranger(); };
|
||||
scRow.appendChild(scaleSel);
|
||||
const scHint = document.createElement("span"); scHint.className = "albl";
|
||||
scHint.textContent = "every groove is in this key — change it and your patterns re-harmonise (the roll is always folded to the scale)";
|
||||
scRow.appendChild(scHint);
|
||||
body.appendChild(scRow);
|
||||
|
||||
// --- the Groove controls: one feel for every playing pattern (§14.1) ---
|
||||
const gr = document.createElement("div"); gr.className = "arow grow";
|
||||
const mkGSlider = (label, get, set, max) => {
|
||||
@ -1643,7 +1690,7 @@
|
||||
if (stp % 4 === 0) cell.classList.add("bar");
|
||||
if (nSel.isNote) {
|
||||
cell.title = midiToName(seqRootFor(arrSelKey) + SEQ_ROWS[rw]) + " · step " + (stp + 1);
|
||||
cell.onclick = () => { steps[stp] = steps[stp] === rw ? -1 : rw; paintG(); };
|
||||
cell.onclick = () => { stepToggle(steps, stp, rw); paintG(); };
|
||||
} else {
|
||||
cell.title = "step " + (stp + 1);
|
||||
cell.onclick = () => { steps[stp] = steps[stp] ? 0 : 1; paintG(); };
|
||||
@ -1654,7 +1701,8 @@
|
||||
}
|
||||
const paintG = () => {
|
||||
for (const c2 of cells) {
|
||||
c2.el.classList.toggle("on", nSel.isNote ? steps[c2.stp] === c2.rw : !!steps[c2.stp]);
|
||||
c2.el.classList.toggle("on", nSel.isNote ? stepHas(steps[c2.stp], c2.rw) : !!steps[c2.stp]);
|
||||
c2.el.classList.toggle("playone", nSel.isNote && stepStack(steps[c2.stp]) && stepHas(steps[c2.stp], c2.rw));
|
||||
c2.el.classList.toggle("cur", arr.playing && c2.stp === seqCurStep);
|
||||
}
|
||||
};
|
||||
@ -2095,7 +2143,7 @@
|
||||
if (!sq.on) continue;
|
||||
const n = dests.get(k);
|
||||
if (n && n.isNote) {
|
||||
const deg = sq.steps[seqCurStep];
|
||||
const deg = stepPick(sq.steps[seqCurStep]); // Play One: pick a random candidate
|
||||
if (deg >= 0) {
|
||||
const ch = sq.chance ? sq.chance[seqCurStep] : 1; // chance: does this note fire?
|
||||
if (ch >= 1 || Math.random() < ch) {
|
||||
@ -2244,6 +2292,16 @@
|
||||
euclidFill(er0, 3, 8, 0, false); euclidFill(er1, 3, 8, 1, false); euclidFill(erN, 3, 8, 8, false);
|
||||
if (er0.join("") === er1.join("")) f.push("euclid-rot-shift"); // rot 1 changes it
|
||||
if (er0.join("") !== erN.join("")) f.push("euclid-rot-cycle"); // rot=len is identity
|
||||
// global scale — 8 folded rows per scale
|
||||
if (scaleRows("major").join() !== "0,2,4,5,7,9,11,12") f.push("scale-major");
|
||||
if (scaleRows("minor_pent").join() !== "0,3,5,7,10,12,15,17") f.push("scale-minorpent");
|
||||
// play-one stacks
|
||||
const ps = new Array(16).fill(-1);
|
||||
stepToggle(ps, 0, 3); if (ps[0] !== 3) f.push("po-single"); // first note = plain
|
||||
stepToggle(ps, 0, 5); if (!Array.isArray(ps[0]) || ps[0].join() !== "3,5") f.push("po-stack"); // 2nd = stack
|
||||
stepToggle(ps, 0, 3); if (ps[0] !== 5) f.push("po-unstack"); // remove one → back to plain
|
||||
if (!stepHas([3, 5], 5) || stepHas([3, 5], 7)) f.push("po-has");
|
||||
if (stepPick([4]) !== 4 || stepFirst([9, 2]) !== 9) f.push("po-pickfirst");
|
||||
if (f.length) console.error("⚠ groove self-check FAILED:", f); else console.log("✓ groove self-check passed");
|
||||
return f.length === 0;
|
||||
}
|
||||
@ -2258,6 +2316,7 @@
|
||||
follow: JSON.parse(JSON.stringify(arr.follow)) },
|
||||
bpm: godtime.bpm,
|
||||
groove: Object.assign({}, groove), // the feel travels with the patch
|
||||
scale: Object.assign({}, gScale), // the key travels too
|
||||
};
|
||||
}
|
||||
function loadPatch(p) {
|
||||
@ -2274,6 +2333,7 @@
|
||||
if (s) seqs[k] = s;
|
||||
}
|
||||
if (p.groove) Object.assign(groove, p.groove);
|
||||
if (p.scale) { Object.assign(gScale, p.scale); SEQ_ROWS = scaleRows(gScale.name); }
|
||||
if (p.arr && p.arr.grid && p.arr.banks) { // the arrangement travels too
|
||||
arr.grid = JSON.parse(JSON.stringify(p.arr.grid));
|
||||
arr.banks = JSON.parse(JSON.stringify(p.arr.banks));
|
||||
@ -5416,7 +5476,7 @@
|
||||
const lbl = document.createElement("span");
|
||||
lbl.style.marginLeft = "8px";
|
||||
lbl.textContent = isSource ? "sample & hold — the data steps in your time"
|
||||
: node.isNote ? "16 steps · " + midiToName(seqRootFor(node.key)) + " minor pent"
|
||||
: node.isNote ? "16 steps · " + NOTE_NAMES[gScale.root] + " " + gScale.name.replace("_", " ") + " · stack 2+ = play one"
|
||||
: "16-step gate on the data";
|
||||
head.appendChild(lbl);
|
||||
wrap.appendChild(head);
|
||||
@ -5432,10 +5492,7 @@
|
||||
if (stp % 4 === 0) cell.classList.add("bar");
|
||||
if (node.isNote) {
|
||||
cell.title = midiToName(seqRootFor(node.key) + SEQ_ROWS[rw]) + " · step " + (stp + 1);
|
||||
cell.onclick = () => {
|
||||
sq.steps[stp] = sq.steps[stp] === rw ? -1 : rw; // click sets, click again clears
|
||||
paint();
|
||||
};
|
||||
cell.onclick = () => { stepToggle(sq.steps, stp, rw); paint(); }; // stack 2+ = Play One
|
||||
} else {
|
||||
cell.title = "step " + (stp + 1);
|
||||
cell.onclick = () => { sq.steps[stp] = sq.steps[stp] ? 0 : 1; paint(); };
|
||||
@ -5446,7 +5503,8 @@
|
||||
}
|
||||
const paint = () => {
|
||||
for (const c of cells) {
|
||||
c.el.classList.toggle("on", node.isNote ? sq.steps[c.stp] === c.rw : !!sq.steps[c.stp]);
|
||||
c.el.classList.toggle("on", node.isNote ? stepHas(sq.steps[c.stp], c.rw) : !!sq.steps[c.stp]);
|
||||
c.el.classList.toggle("playone", node.isNote && stepStack(sq.steps[c.stp]) && stepHas(sq.steps[c.stp], c.rw));
|
||||
c.el.classList.toggle("cur", c.stp === seqCurStep && sq.on);
|
||||
}
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user