mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-12 14:18:31 +00:00
MiniRepl: add punchcard flag for implicit vis
+ reintroduce editPattern + add punchcards to mini-notation.mdx
This commit is contained in:
parent
e4f538b674
commit
b2c6d87633
@ -13,7 +13,7 @@ export function repl({
|
||||
getTime,
|
||||
transpiler,
|
||||
onToggle,
|
||||
drawContext,
|
||||
editPattern,
|
||||
}) {
|
||||
const scheduler = new Cyclist({
|
||||
interval,
|
||||
@ -45,6 +45,7 @@ export function repl({
|
||||
let { pattern } = await _evaluate(code, transpiler);
|
||||
|
||||
logger(`[eval] code updated`);
|
||||
pattern = editPattern?.(pattern) || pattern;
|
||||
scheduler.setPattern(pattern, autostart);
|
||||
afterEval?.({ code, pattern });
|
||||
return pattern;
|
||||
|
||||
2
packages/react/dist/index.cjs.js
vendored
2
packages/react/dist/index.cjs.js
vendored
File diff suppressed because one or more lines are too long
542
packages/react/dist/index.es.js
vendored
542
packages/react/dist/index.es.js
vendored
@ -1,15 +1,15 @@
|
||||
import l, { useCallback as w, useRef as A, useEffect as k, useMemo as $, useState as _, useLayoutEffect as Y } from "react";
|
||||
import ie from "@uiw/react-codemirror";
|
||||
import { Decoration as M, EditorView as Z } from "@codemirror/view";
|
||||
import { StateEffect as ee, StateField as te } from "@codemirror/state";
|
||||
import { javascript as le } from "@codemirror/lang-javascript";
|
||||
import { tags as i } from "@lezer/highlight";
|
||||
import { createTheme as ue } from "@uiw/codemirror-themes";
|
||||
import { webaudioOutput as de, getAudioContext as fe } from "@strudel.cycles/webaudio";
|
||||
import { useInView as me } from "react-hook-inview";
|
||||
import { repl as he, logger as ge } from "@strudel.cycles/core";
|
||||
import { transpiler as pe } from "@strudel.cycles/transpiler";
|
||||
const ve = ue({
|
||||
import d, { useCallback as w, useRef as N, useEffect as k, useMemo as G, useState as M, useLayoutEffect as T } from "react";
|
||||
import le from "@uiw/react-codemirror";
|
||||
import { Decoration as A, EditorView as ee } from "@codemirror/view";
|
||||
import { StateEffect as te, StateField as re } from "@codemirror/state";
|
||||
import { javascript as ue } from "@codemirror/lang-javascript";
|
||||
import { tags as u } from "@lezer/highlight";
|
||||
import { createTheme as de } from "@uiw/codemirror-themes";
|
||||
import { webaudioOutput as fe, getAudioContext as me } from "@strudel.cycles/webaudio";
|
||||
import { useInView as he } from "react-hook-inview";
|
||||
import { repl as ge, logger as pe } from "@strudel.cycles/core";
|
||||
import { transpiler as ve } from "@strudel.cycles/transpiler";
|
||||
const be = de({
|
||||
theme: "dark",
|
||||
settings: {
|
||||
background: "#222",
|
||||
@ -22,413 +22,417 @@ const ve = ue({
|
||||
gutterForeground: "#8a919966"
|
||||
},
|
||||
styles: [
|
||||
{ tag: i.keyword, color: "#c792ea" },
|
||||
{ tag: i.operator, color: "#89ddff" },
|
||||
{ tag: i.special(i.variableName), color: "#eeffff" },
|
||||
{ tag: i.typeName, color: "#c3e88d" },
|
||||
{ tag: i.atom, color: "#f78c6c" },
|
||||
{ tag: i.number, color: "#c3e88d" },
|
||||
{ tag: i.definition(i.variableName), color: "#82aaff" },
|
||||
{ tag: i.string, color: "#c3e88d" },
|
||||
{ tag: i.special(i.string), color: "#c3e88d" },
|
||||
{ tag: i.comment, color: "#7d8799" },
|
||||
{ tag: i.variableName, color: "#c792ea" },
|
||||
{ tag: i.tagName, color: "#c3e88d" },
|
||||
{ tag: i.bracket, color: "#525154" },
|
||||
{ tag: i.meta, color: "#ffcb6b" },
|
||||
{ tag: i.attributeName, color: "#c792ea" },
|
||||
{ tag: i.propertyName, color: "#c792ea" },
|
||||
{ tag: i.className, color: "#decb6b" },
|
||||
{ tag: i.invalid, color: "#ffffff" }
|
||||
{ tag: u.keyword, color: "#c792ea" },
|
||||
{ tag: u.operator, color: "#89ddff" },
|
||||
{ tag: u.special(u.variableName), color: "#eeffff" },
|
||||
{ tag: u.typeName, color: "#c3e88d" },
|
||||
{ tag: u.atom, color: "#f78c6c" },
|
||||
{ tag: u.number, color: "#c3e88d" },
|
||||
{ tag: u.definition(u.variableName), color: "#82aaff" },
|
||||
{ tag: u.string, color: "#c3e88d" },
|
||||
{ tag: u.special(u.string), color: "#c3e88d" },
|
||||
{ tag: u.comment, color: "#7d8799" },
|
||||
{ tag: u.variableName, color: "#c792ea" },
|
||||
{ tag: u.tagName, color: "#c3e88d" },
|
||||
{ tag: u.bracket, color: "#525154" },
|
||||
{ tag: u.meta, color: "#ffcb6b" },
|
||||
{ tag: u.attributeName, color: "#c792ea" },
|
||||
{ tag: u.propertyName, color: "#c792ea" },
|
||||
{ tag: u.className, color: "#decb6b" },
|
||||
{ tag: u.invalid, color: "#ffffff" }
|
||||
]
|
||||
});
|
||||
const G = ee.define(), be = te.define({
|
||||
const J = te.define(), Ee = re.define({
|
||||
create() {
|
||||
return M.none;
|
||||
return A.none;
|
||||
},
|
||||
update(e, r) {
|
||||
try {
|
||||
for (let t of r.effects)
|
||||
if (t.is(G))
|
||||
if (t.is(J))
|
||||
if (t.value) {
|
||||
const o = M.mark({ attributes: { style: "background-color: #FFCA2880" } });
|
||||
e = M.set([o.range(0, r.newDoc.length)]);
|
||||
const n = A.mark({ attributes: { style: "background-color: #FFCA2880" } });
|
||||
e = A.set([n.range(0, r.newDoc.length)]);
|
||||
} else
|
||||
e = M.set([]);
|
||||
e = A.set([]);
|
||||
return e;
|
||||
} catch (t) {
|
||||
return console.warn("flash error", t), e;
|
||||
}
|
||||
},
|
||||
provide: (e) => Z.decorations.from(e)
|
||||
}), Ee = (e) => {
|
||||
e.dispatch({ effects: G.of(!0) }), setTimeout(() => {
|
||||
e.dispatch({ effects: G.of(!1) });
|
||||
provide: (e) => ee.decorations.from(e)
|
||||
}), ye = (e) => {
|
||||
e.dispatch({ effects: J.of(!0) }), setTimeout(() => {
|
||||
e.dispatch({ effects: J.of(!1) });
|
||||
}, 200);
|
||||
}, O = ee.define(), ye = te.define({
|
||||
}, B = te.define(), we = re.define({
|
||||
create() {
|
||||
return M.none;
|
||||
return A.none;
|
||||
},
|
||||
update(e, r) {
|
||||
try {
|
||||
for (let t of r.effects)
|
||||
if (t.is(O)) {
|
||||
const o = t.value.map(
|
||||
(u) => (u.context.locations || []).map(({ start: m, end: d }) => {
|
||||
const a = u.context.color || "#FFCA28";
|
||||
let c = r.newDoc.line(m.line).from + m.column, h = r.newDoc.line(d.line).from + d.column;
|
||||
const g = r.newDoc.length;
|
||||
return c > g || h > g ? void 0 : M.mark({ attributes: { style: `outline: 1.5px solid ${a};` } }).range(c, h);
|
||||
if (t.is(B)) {
|
||||
const n = t.value.map(
|
||||
(c) => (c.context.locations || []).map(({ start: m, end: s }) => {
|
||||
const a = c.context.color || "#FFCA28";
|
||||
let i = r.newDoc.line(m.line).from + m.column, g = r.newDoc.line(s.line).from + s.column;
|
||||
const b = r.newDoc.length;
|
||||
return i > b || g > b ? void 0 : A.mark({ attributes: { style: `outline: 1.5px solid ${a};` } }).range(i, g);
|
||||
})
|
||||
).flat().filter(Boolean) || [];
|
||||
e = M.set(o, !0);
|
||||
e = A.set(n, !0);
|
||||
}
|
||||
return e;
|
||||
} catch {
|
||||
return M.set([]);
|
||||
return A.set([]);
|
||||
}
|
||||
},
|
||||
provide: (e) => Z.decorations.from(e)
|
||||
}), we = [le(), ve, ye, be];
|
||||
function ke({ value: e, onChange: r, onViewChanged: t, onSelectionChange: o, options: u, editorDidMount: m }) {
|
||||
const d = w(
|
||||
(h) => {
|
||||
r?.(h);
|
||||
provide: (e) => ee.decorations.from(e)
|
||||
}), ke = [ue(), be, we, Ee];
|
||||
function Fe({ value: e, onChange: r, onViewChanged: t, onSelectionChange: n, options: c, editorDidMount: m }) {
|
||||
const s = w(
|
||||
(g) => {
|
||||
r?.(g);
|
||||
},
|
||||
[r]
|
||||
), a = w(
|
||||
(h) => {
|
||||
t?.(h);
|
||||
(g) => {
|
||||
t?.(g);
|
||||
},
|
||||
[t]
|
||||
), c = w(
|
||||
(h) => {
|
||||
h.selectionSet && o && o?.(h.state.selection);
|
||||
), i = w(
|
||||
(g) => {
|
||||
g.selectionSet && n && n?.(g.state.selection);
|
||||
},
|
||||
[o]
|
||||
[n]
|
||||
);
|
||||
return /* @__PURE__ */ l.createElement(l.Fragment, null, /* @__PURE__ */ l.createElement(ie, {
|
||||
return /* @__PURE__ */ d.createElement(d.Fragment, null, /* @__PURE__ */ d.createElement(le, {
|
||||
value: e,
|
||||
onChange: d,
|
||||
onChange: s,
|
||||
onCreateEditor: a,
|
||||
onUpdate: c,
|
||||
extensions: we
|
||||
onUpdate: i,
|
||||
extensions: ke
|
||||
}));
|
||||
}
|
||||
function T(...e) {
|
||||
function Y(...e) {
|
||||
return e.filter(Boolean).join(" ");
|
||||
}
|
||||
function Fe({ view: e, pattern: r, active: t, getTime: o }) {
|
||||
const u = A([]), m = A();
|
||||
function _e({ view: e, pattern: r, active: t, getTime: n }) {
|
||||
const c = N([]), m = N();
|
||||
k(() => {
|
||||
if (e)
|
||||
if (r && t) {
|
||||
let d = requestAnimationFrame(function a() {
|
||||
let s = requestAnimationFrame(function a() {
|
||||
try {
|
||||
const c = o(), g = [Math.max(m.current || c, c - 1 / 10, 0), c + 1 / 60];
|
||||
m.current = g[1], u.current = u.current.filter((p) => p.whole.end > c);
|
||||
const n = r.queryArc(...g).filter((p) => p.hasOnset());
|
||||
u.current = u.current.concat(n), e.dispatch({ effects: O.of(u.current) });
|
||||
const i = n(), b = [Math.max(m.current || i, i - 1 / 10, 0), i + 1 / 60];
|
||||
m.current = b[1], c.current = c.current.filter((h) => h.whole.end > i);
|
||||
const l = r.queryArc(...b).filter((h) => h.hasOnset());
|
||||
c.current = c.current.concat(l), e.dispatch({ effects: B.of(c.current) });
|
||||
} catch {
|
||||
e.dispatch({ effects: O.of([]) });
|
||||
e.dispatch({ effects: B.of([]) });
|
||||
}
|
||||
d = requestAnimationFrame(a);
|
||||
s = requestAnimationFrame(a);
|
||||
});
|
||||
return () => {
|
||||
cancelAnimationFrame(d);
|
||||
cancelAnimationFrame(s);
|
||||
};
|
||||
} else
|
||||
u.current = [], e.dispatch({ effects: O.of([]) });
|
||||
c.current = [], e.dispatch({ effects: B.of([]) });
|
||||
}, [r, t, e]);
|
||||
}
|
||||
function _e(e, r = !1) {
|
||||
const t = A(), o = A(), u = (a) => {
|
||||
if (o.current !== void 0) {
|
||||
const c = a - o.current;
|
||||
e(a, c);
|
||||
function Me(e, r = !1) {
|
||||
const t = N(), n = N(), c = (a) => {
|
||||
if (n.current !== void 0) {
|
||||
const i = a - n.current;
|
||||
e(a, i);
|
||||
}
|
||||
o.current = a, t.current = requestAnimationFrame(u);
|
||||
n.current = a, t.current = requestAnimationFrame(c);
|
||||
}, m = () => {
|
||||
t.current = requestAnimationFrame(u);
|
||||
}, d = () => {
|
||||
t.current = requestAnimationFrame(c);
|
||||
}, s = () => {
|
||||
t.current && cancelAnimationFrame(t.current), delete t.current;
|
||||
};
|
||||
return k(() => {
|
||||
t.current && (d(), m());
|
||||
}, [e]), k(() => (r && m(), d), []), {
|
||||
t.current && (s(), m());
|
||||
}, [e]), k(() => (r && m(), s), []), {
|
||||
start: m,
|
||||
stop: d
|
||||
stop: s
|
||||
};
|
||||
}
|
||||
function Me({ pattern: e, started: r, getTime: t, onDraw: o, drawTime: u = [-2, 2] }) {
|
||||
let [m, d] = u;
|
||||
function Ae({ pattern: e, started: r, getTime: t, onDraw: n, drawTime: c = [-2, 2] }) {
|
||||
let [m, s] = c;
|
||||
m = Math.abs(m);
|
||||
let a = A([]), c = A(null);
|
||||
let a = N([]), i = N(null);
|
||||
k(() => {
|
||||
if (e) {
|
||||
const n = t(), p = e.queryArc(n, n + d);
|
||||
a.current = a.current.filter((b) => b.whole.begin < n), a.current = a.current.concat(p);
|
||||
const l = t(), h = e.queryArc(l, l + s + 0.1);
|
||||
a.current = a.current.filter((v) => v.whole.begin < l), a.current = a.current.concat(h);
|
||||
}
|
||||
}, [e]);
|
||||
const { start: h, stop: g } = _e(
|
||||
const { start: g, stop: b } = Me(
|
||||
w(() => {
|
||||
const n = t() + d;
|
||||
if (c.current === null) {
|
||||
c.current = n;
|
||||
const l = t() + s;
|
||||
if (i.current === null) {
|
||||
i.current = l;
|
||||
return;
|
||||
}
|
||||
const p = e.queryArc(Math.max(c.current, n - 1 / 10), n);
|
||||
c.current = n, a.current = (a.current || []).filter((b) => b.whole.end >= n - m - d).concat(p.filter((b) => b.hasOnset())), o(e, n - d, a.current, u);
|
||||
const h = e.queryArc(Math.max(i.current, l - 1 / 10), l);
|
||||
i.current = l, a.current = (a.current || []).filter((v) => v.whole.end >= l - m - s).concat(h.filter((v) => v.hasOnset())), n(e, l - s, a.current, c);
|
||||
}, [e])
|
||||
);
|
||||
return k(() => {
|
||||
r ? h() : (a.current = [], g());
|
||||
r ? g() : (a.current = [], b());
|
||||
}, [r]), {
|
||||
clear: () => {
|
||||
a.current = [];
|
||||
}
|
||||
};
|
||||
}
|
||||
function Ae(e) {
|
||||
function Ne(e) {
|
||||
return k(() => (window.addEventListener("message", e), () => window.removeEventListener("message", e)), [e]), w((r) => window.postMessage(r, "*"), []);
|
||||
}
|
||||
function Ne({
|
||||
function De({
|
||||
defaultOutput: e,
|
||||
interval: r,
|
||||
getTime: t,
|
||||
evalOnMount: o = !1,
|
||||
initialCode: u = "",
|
||||
evalOnMount: n = !1,
|
||||
initialCode: c = "",
|
||||
autolink: m = !1,
|
||||
beforeEval: d,
|
||||
afterEval: a,
|
||||
onEvalError: c,
|
||||
onToggle: h,
|
||||
canvasId: g,
|
||||
drawContext: n,
|
||||
drawTime: p = [-2, 2]
|
||||
beforeEval: s,
|
||||
editPattern: a,
|
||||
afterEval: i,
|
||||
onEvalError: g,
|
||||
onToggle: b,
|
||||
canvasId: l,
|
||||
drawContext: h,
|
||||
drawTime: v = [-2, 2]
|
||||
}) {
|
||||
const b = $(() => De(), []);
|
||||
g = g || `canvas-${b}`;
|
||||
const [q, x] = _(), [C, z] = _(), [E, D] = _(u), [H, B] = _(), [N, P] = _(), [R, S] = _(!1), I = E !== H, { scheduler: s, evaluate: v, start: J, stop: V, pause: re } = $(
|
||||
() => he({
|
||||
const F = G(() => Ce(), []);
|
||||
l = l || `canvas-${F}`;
|
||||
const [x, z] = M(), [R, H] = M(), [E, C] = M(c), [P, I] = M(), [D, S] = M(), [L, V] = M(!1), K = E !== P, { scheduler: o, evaluate: p, start: Q, stop: O, pause: ne } = G(
|
||||
() => ge({
|
||||
interval: r,
|
||||
defaultOutput: e,
|
||||
onSchedulerError: x,
|
||||
onSchedulerError: z,
|
||||
onEvalError: (f) => {
|
||||
z(f), c?.(f);
|
||||
H(f), g?.(f);
|
||||
},
|
||||
getTime: t,
|
||||
drawContext: n,
|
||||
transpiler: pe,
|
||||
drawContext: h,
|
||||
transpiler: ve,
|
||||
editPattern: a,
|
||||
beforeEval: ({ code: f }) => {
|
||||
D(f), d?.();
|
||||
C(f), s?.();
|
||||
},
|
||||
afterEval: ({ pattern: f, code: y }) => {
|
||||
B(y), P(f), z(), x(), m && (window.location.hash = "#" + encodeURIComponent(btoa(y))), a?.();
|
||||
I(y), S(f), H(), z(), m && (window.location.hash = "#" + encodeURIComponent(btoa(y))), i?.();
|
||||
},
|
||||
onToggle: (f) => {
|
||||
S(f), h?.(f);
|
||||
V(f), b?.(f);
|
||||
}
|
||||
}),
|
||||
[e, r, t]
|
||||
), ne = Ae(({ data: { from: f, type: y } }) => {
|
||||
y === "start" && f !== b && V();
|
||||
}), K = w(
|
||||
), oe = Ne(({ data: { from: f, type: y } }) => {
|
||||
y === "start" && f !== F && O();
|
||||
}), j = w(
|
||||
async (f = !0) => {
|
||||
const y = await v(E, f);
|
||||
return ne({ type: "start", from: b }), y;
|
||||
const y = await p(E, f);
|
||||
return oe({ type: "start", from: F }), y;
|
||||
},
|
||||
[v, E]
|
||||
), L = w(
|
||||
(f, y, U, W) => {
|
||||
const { onPaint: ce } = f.context || {}, se = typeof n == "function" ? n(g) : n;
|
||||
ce?.(se, y, U, W);
|
||||
[p, E]
|
||||
), q = w(
|
||||
(f, y, W, $) => {
|
||||
const { onPaint: se } = f.context || {}, ie = typeof h == "function" ? h(l) : h;
|
||||
se?.(ie, y, W, $);
|
||||
},
|
||||
[n, g]
|
||||
), j = w(
|
||||
[h, l]
|
||||
), U = w(
|
||||
(f) => {
|
||||
if (n && L) {
|
||||
const [y, U] = p, W = f.queryArc(0, U);
|
||||
L(f, 0, W, p);
|
||||
if (h && q) {
|
||||
const [y, W] = v, $ = f.queryArc(0, W);
|
||||
q(f, 0, $, v);
|
||||
}
|
||||
},
|
||||
[p, L]
|
||||
), Q = A();
|
||||
[v, q]
|
||||
), X = N();
|
||||
k(() => {
|
||||
!Q.current && n && L && o && E && (Q.current = !0, v(E, !1).then((f) => j(f)));
|
||||
}, [K, o, E, j]), k(() => () => {
|
||||
s.stop();
|
||||
}, [s]);
|
||||
const oe = async () => {
|
||||
R ? (s.stop(), j(N)) : await K();
|
||||
}, ae = q || C;
|
||||
return Me({
|
||||
pattern: N,
|
||||
started: n && R,
|
||||
getTime: () => s.now(),
|
||||
drawTime: p,
|
||||
onDraw: L
|
||||
!X.current && h && q && n && E && (X.current = !0, p(E, !1).then((f) => U(f)));
|
||||
}, [j, n, E, U]), k(() => () => {
|
||||
o.stop();
|
||||
}, [o]);
|
||||
const ae = async () => {
|
||||
L ? (o.stop(), U(D)) : await j();
|
||||
}, ce = x || R;
|
||||
return Ae({
|
||||
pattern: D,
|
||||
started: h && L,
|
||||
getTime: () => o.now(),
|
||||
drawTime: v,
|
||||
onDraw: q
|
||||
}), {
|
||||
id: b,
|
||||
canvasId: g,
|
||||
id: F,
|
||||
canvasId: l,
|
||||
code: E,
|
||||
setCode: D,
|
||||
error: ae,
|
||||
schedulerError: q,
|
||||
scheduler: s,
|
||||
evalError: C,
|
||||
evaluate: v,
|
||||
activateCode: K,
|
||||
activeCode: H,
|
||||
isDirty: I,
|
||||
pattern: N,
|
||||
started: R,
|
||||
start: J,
|
||||
stop: V,
|
||||
pause: re,
|
||||
togglePlay: oe
|
||||
setCode: C,
|
||||
error: ce,
|
||||
schedulerError: x,
|
||||
scheduler: o,
|
||||
evalError: R,
|
||||
evaluate: p,
|
||||
activateCode: j,
|
||||
activeCode: P,
|
||||
isDirty: K,
|
||||
pattern: D,
|
||||
started: L,
|
||||
start: Q,
|
||||
stop: O,
|
||||
pause: ne,
|
||||
togglePlay: ae
|
||||
};
|
||||
}
|
||||
function De() {
|
||||
function Ce() {
|
||||
return Math.floor((1 + Math.random()) * 65536).toString(16).substring(1);
|
||||
}
|
||||
function X({ type: e }) {
|
||||
return /* @__PURE__ */ l.createElement("svg", {
|
||||
function Z({ type: e }) {
|
||||
return /* @__PURE__ */ d.createElement("svg", {
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
className: "sc-h-5 sc-w-5",
|
||||
viewBox: "0 0 20 20",
|
||||
fill: "currentColor"
|
||||
}, {
|
||||
refresh: /* @__PURE__ */ l.createElement("path", {
|
||||
refresh: /* @__PURE__ */ d.createElement("path", {
|
||||
fillRule: "evenodd",
|
||||
d: "M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z",
|
||||
clipRule: "evenodd"
|
||||
}),
|
||||
play: /* @__PURE__ */ l.createElement("path", {
|
||||
play: /* @__PURE__ */ d.createElement("path", {
|
||||
fillRule: "evenodd",
|
||||
d: "M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z",
|
||||
clipRule: "evenodd"
|
||||
}),
|
||||
pause: /* @__PURE__ */ l.createElement("path", {
|
||||
pause: /* @__PURE__ */ d.createElement("path", {
|
||||
fillRule: "evenodd",
|
||||
d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z",
|
||||
clipRule: "evenodd"
|
||||
}),
|
||||
stop: /* @__PURE__ */ l.createElement("path", {
|
||||
stop: /* @__PURE__ */ d.createElement("path", {
|
||||
fillRule: "evenodd",
|
||||
d: "M2 10a8 8 0 1116 0 8 8 0 01-16 0zm5-2.25A.75.75 0 017.75 7h4.5a.75.75 0 01.75.75v4.5a.75.75 0 01-.75.75h-4.5a.75.75 0 01-.75-.75v-4.5z",
|
||||
clipRule: "evenodd"
|
||||
})
|
||||
}[e]);
|
||||
}
|
||||
const Ce = "_container_3i85k_1", Re = "_header_3i85k_5", Le = "_buttons_3i85k_9", qe = "_button_3i85k_9", xe = "_buttonDisabled_3i85k_17", ze = "_error_3i85k_21", He = "_body_3i85k_25", F = {
|
||||
container: Ce,
|
||||
header: Re,
|
||||
buttons: Le,
|
||||
button: qe,
|
||||
buttonDisabled: xe,
|
||||
error: ze,
|
||||
body: He
|
||||
}, Pe = () => fe().currentTime;
|
||||
function Te({ tune: e, hideOutsideView: r = !1, enableKeyboard: t, drawTime: o, canvasHeight: u = 200 }) {
|
||||
const Re = "_container_3i85k_1", Le = "_header_3i85k_5", qe = "_buttons_3i85k_9", xe = "_button_3i85k_9", ze = "_buttonDisabled_3i85k_17", He = "_error_3i85k_21", Pe = "_body_3i85k_25", _ = {
|
||||
container: Re,
|
||||
header: Le,
|
||||
buttons: qe,
|
||||
button: xe,
|
||||
buttonDisabled: ze,
|
||||
error: He,
|
||||
body: Pe
|
||||
}, Se = () => me().currentTime;
|
||||
function Ye({ tune: e, hideOutsideView: r = !1, enableKeyboard: t, drawTime: n, punchcard: c, canvasHeight: m = 200 }) {
|
||||
n = n || (c ? [0, 4] : void 0);
|
||||
const {
|
||||
code: m,
|
||||
setCode: d,
|
||||
evaluate: a,
|
||||
activateCode: c,
|
||||
error: h,
|
||||
isDirty: g,
|
||||
activeCode: n,
|
||||
pattern: p,
|
||||
started: b,
|
||||
scheduler: q,
|
||||
togglePlay: x,
|
||||
stop: C,
|
||||
canvasId: z,
|
||||
code: s,
|
||||
setCode: a,
|
||||
evaluate: i,
|
||||
activateCode: g,
|
||||
error: b,
|
||||
isDirty: l,
|
||||
activeCode: h,
|
||||
pattern: v,
|
||||
started: F,
|
||||
scheduler: x,
|
||||
togglePlay: z,
|
||||
stop: R,
|
||||
canvasId: H,
|
||||
id: E
|
||||
} = Ne({
|
||||
} = De({
|
||||
initialCode: e,
|
||||
defaultOutput: de,
|
||||
getTime: Pe,
|
||||
evalOnMount: !!o,
|
||||
drawContext: o ? (s) => document.querySelector("#" + s)?.getContext("2d") : null,
|
||||
drawTime: o
|
||||
}), [D, H] = _(), [B, N] = me({
|
||||
defaultOutput: fe,
|
||||
editPattern: (o) => c ? o.punchcard() : o,
|
||||
getTime: Se,
|
||||
evalOnMount: !!n,
|
||||
drawContext: n ? (o) => document.querySelector("#" + o)?.getContext("2d") : null,
|
||||
drawTime: n
|
||||
}), [C, P] = M(), [I, D] = he({
|
||||
threshold: 0.01
|
||||
}), P = A(), R = $(() => ((N || !r) && (P.current = !0), N || P.current), [N, r]);
|
||||
Fe({
|
||||
view: D,
|
||||
pattern: p,
|
||||
active: b && !n?.includes("strudel disable-highlighting"),
|
||||
getTime: () => q.now()
|
||||
}), Y(() => {
|
||||
}), S = N(), L = G(() => ((D || !r) && (S.current = !0), D || S.current), [D, r]);
|
||||
_e({
|
||||
view: C,
|
||||
pattern: v,
|
||||
active: F && !h?.includes("strudel disable-highlighting"),
|
||||
getTime: () => x.now()
|
||||
}), T(() => {
|
||||
if (t) {
|
||||
const s = async (v) => {
|
||||
(v.ctrlKey || v.altKey) && (v.code === "Enter" ? (v.preventDefault(), Ee(D), await c()) : v.code === "Period" && (C(), v.preventDefault()));
|
||||
const o = async (p) => {
|
||||
(p.ctrlKey || p.altKey) && (p.code === "Enter" ? (p.preventDefault(), ye(C), await g()) : p.code === "Period" && (R(), p.preventDefault()));
|
||||
};
|
||||
return window.addEventListener("keydown", s, !0), () => window.removeEventListener("keydown", s, !0);
|
||||
return window.addEventListener("keydown", o, !0), () => window.removeEventListener("keydown", o, !0);
|
||||
}
|
||||
}, [t, p, m, a, C, D]);
|
||||
const [S, I] = _([]);
|
||||
return Se(
|
||||
w((s) => {
|
||||
const { data: v } = s.detail;
|
||||
v?.hap?.context?.id === E && I((V) => V.concat([s.detail]).slice(-10));
|
||||
}, [t, v, s, i, R, C]);
|
||||
const [V, K] = M([]);
|
||||
return Ve(
|
||||
w((o) => {
|
||||
const { data: p } = o.detail;
|
||||
p?.hap?.context?.id === E && K((O) => O.concat([o.detail]).slice(-10));
|
||||
}, [])
|
||||
), /* @__PURE__ */ l.createElement("div", {
|
||||
className: F.container,
|
||||
ref: B
|
||||
}, /* @__PURE__ */ l.createElement("div", {
|
||||
className: F.header
|
||||
}, /* @__PURE__ */ l.createElement("div", {
|
||||
className: F.buttons
|
||||
}, /* @__PURE__ */ l.createElement("button", {
|
||||
className: T(F.button, b ? "sc-animate-pulse" : ""),
|
||||
onClick: () => x()
|
||||
}, /* @__PURE__ */ l.createElement(X, {
|
||||
type: b ? "stop" : "play"
|
||||
})), /* @__PURE__ */ l.createElement("button", {
|
||||
className: T(g ? F.button : F.buttonDisabled),
|
||||
onClick: () => c()
|
||||
}, /* @__PURE__ */ l.createElement(X, {
|
||||
), /* @__PURE__ */ d.createElement("div", {
|
||||
className: _.container,
|
||||
ref: I
|
||||
}, /* @__PURE__ */ d.createElement("div", {
|
||||
className: _.header
|
||||
}, /* @__PURE__ */ d.createElement("div", {
|
||||
className: _.buttons
|
||||
}, /* @__PURE__ */ d.createElement("button", {
|
||||
className: Y(_.button, F ? "sc-animate-pulse" : ""),
|
||||
onClick: () => z()
|
||||
}, /* @__PURE__ */ d.createElement(Z, {
|
||||
type: F ? "stop" : "play"
|
||||
})), /* @__PURE__ */ d.createElement("button", {
|
||||
className: Y(l ? _.button : _.buttonDisabled),
|
||||
onClick: () => g()
|
||||
}, /* @__PURE__ */ d.createElement(Z, {
|
||||
type: "refresh"
|
||||
}))), h && /* @__PURE__ */ l.createElement("div", {
|
||||
className: F.error
|
||||
}, h.message)), /* @__PURE__ */ l.createElement("div", {
|
||||
className: F.body
|
||||
}, R && /* @__PURE__ */ l.createElement(ke, {
|
||||
value: m,
|
||||
onChange: d,
|
||||
onViewChanged: H
|
||||
})), o && /* @__PURE__ */ l.createElement("canvas", {
|
||||
id: z,
|
||||
}))), b && /* @__PURE__ */ d.createElement("div", {
|
||||
className: _.error
|
||||
}, b.message)), /* @__PURE__ */ d.createElement("div", {
|
||||
className: _.body
|
||||
}, L && /* @__PURE__ */ d.createElement(Fe, {
|
||||
value: s,
|
||||
onChange: a,
|
||||
onViewChanged: P
|
||||
})), n && /* @__PURE__ */ d.createElement("canvas", {
|
||||
id: H,
|
||||
className: "w-full pointer-events-none",
|
||||
height: u,
|
||||
ref: (s) => {
|
||||
s && s.width !== s.clientWidth && (s.width = s.clientWidth);
|
||||
height: m,
|
||||
ref: (o) => {
|
||||
o && o.width !== o.clientWidth && (o.width = o.clientWidth);
|
||||
}
|
||||
}), !!S.length && /* @__PURE__ */ l.createElement("div", {
|
||||
}), !!V.length && /* @__PURE__ */ d.createElement("div", {
|
||||
className: "sc-bg-gray-800 sc-rounded-md sc-p-2"
|
||||
}, S.map(({ message: s }, v) => /* @__PURE__ */ l.createElement("div", {
|
||||
key: v
|
||||
}, s))));
|
||||
}, V.map(({ message: o }, p) => /* @__PURE__ */ d.createElement("div", {
|
||||
key: p
|
||||
}, o))));
|
||||
}
|
||||
function Se(e) {
|
||||
Ve(ge.key, e);
|
||||
function Ve(e) {
|
||||
Oe(pe.key, e);
|
||||
}
|
||||
function Ve(e, r, t = !1) {
|
||||
function Oe(e, r, t = !1) {
|
||||
k(() => (document.addEventListener(e, r, t), () => {
|
||||
document.removeEventListener(e, r, t);
|
||||
}), [r]);
|
||||
}
|
||||
const Xe = (e) => Y(() => (window.addEventListener("keydown", e, !0), () => window.removeEventListener("keydown", e, !0)), [e]);
|
||||
const Ze = (e) => T(() => (window.addEventListener("keydown", e, !0), () => window.removeEventListener("keydown", e, !0)), [e]);
|
||||
export {
|
||||
ke as CodeMirror,
|
||||
Te as MiniRepl,
|
||||
T as cx,
|
||||
Ee as flash,
|
||||
Fe as useHighlighting,
|
||||
Xe as useKeydown,
|
||||
Ae as usePostMessage,
|
||||
Ne as useStrudel
|
||||
Fe as CodeMirror,
|
||||
Ye as MiniRepl,
|
||||
Y as cx,
|
||||
ye as flash,
|
||||
_e as useHighlighting,
|
||||
Ze as useKeydown,
|
||||
Ne as usePostMessage,
|
||||
De as useStrudel
|
||||
};
|
||||
|
||||
@ -13,7 +13,8 @@ import { logger } from '@strudel.cycles/core';
|
||||
|
||||
const getTime = () => getAudioContext().currentTime;
|
||||
|
||||
export function MiniRepl({ tune, hideOutsideView = false, enableKeyboard, drawTime, canvasHeight = 200 }) {
|
||||
export function MiniRepl({ tune, hideOutsideView = false, enableKeyboard, drawTime, punchcard, canvasHeight = 200 }) {
|
||||
drawTime = drawTime || (punchcard ? [0, 4] : undefined);
|
||||
const {
|
||||
code,
|
||||
setCode,
|
||||
@ -32,6 +33,7 @@ export function MiniRepl({ tune, hideOutsideView = false, enableKeyboard, drawTi
|
||||
} = useStrudel({
|
||||
initialCode: tune,
|
||||
defaultOutput: webaudioOutput,
|
||||
editPattern: (pat) => (punchcard ? pat.punchcard() : pat),
|
||||
getTime,
|
||||
evalOnMount: !!drawTime,
|
||||
drawContext: !!drawTime ? (canvasId) => document.querySelector('#' + canvasId)?.getContext('2d') : null,
|
||||
|
||||
@ -10,7 +10,7 @@ function usePatternFrame({ pattern, started, getTime, onDraw, drawTime = [-2, 2]
|
||||
useEffect(() => {
|
||||
if (pattern) {
|
||||
const t = getTime();
|
||||
const futureHaps = pattern.queryArc(t, t + lookahead);
|
||||
const futureHaps = pattern.queryArc(t, t + lookahead + 0.1); // +0.1 = workaround for weird holes in query..
|
||||
visibleHaps.current = visibleHaps.current.filter((h) => h.whole.begin < t);
|
||||
visibleHaps.current = visibleHaps.current.concat(futureHaps);
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ function useStrudel({
|
||||
initialCode = '',
|
||||
autolink = false,
|
||||
beforeEval,
|
||||
editPattern,
|
||||
afterEval,
|
||||
onEvalError,
|
||||
onToggle,
|
||||
@ -44,6 +45,7 @@ function useStrudel({
|
||||
getTime,
|
||||
drawContext,
|
||||
transpiler,
|
||||
editPattern,
|
||||
beforeEval: ({ code }) => {
|
||||
setCode(code);
|
||||
beforeEval?.();
|
||||
|
||||
@ -22,7 +22,7 @@ if (typeof window !== 'undefined') {
|
||||
prebake();
|
||||
}
|
||||
|
||||
export function MiniRepl({ tune, drawTime }) {
|
||||
export function MiniRepl({ tune, drawTime, punchcard, canvasHeight = 100 }) {
|
||||
const [Repl, setRepl] = useState();
|
||||
useEffect(() => {
|
||||
// we have to load this package on the client
|
||||
@ -31,5 +31,11 @@ export function MiniRepl({ tune, drawTime }) {
|
||||
setRepl(() => res.MiniRepl);
|
||||
});
|
||||
}, []);
|
||||
return Repl ? <Repl tune={tune} hideOutsideView={true} drawTime={drawTime} /> : <pre>{tune}</pre>;
|
||||
return Repl ? (
|
||||
<div className="mb-4">
|
||||
<Repl tune={tune} hideOutsideView={true} drawTime={drawTime} punchcard={punchcard} canvasHeight={canvasHeight} />
|
||||
</div>
|
||||
) : (
|
||||
<pre>{tune}</pre>
|
||||
);
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ Strudel however runs directly in your web browser, does not require any custom s
|
||||
The main place to actually make music with Strudel is the [Strudel REPL](https://strudel.tidalcycles.org/) ([what is a REPL?](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop)), but in these pages you will also encounter interactive "MiniREPLs" where you can listen to and edit Strudel patterns.
|
||||
Try clicking the play icon below:
|
||||
|
||||
<MiniRepl client:idle tune={`s("bd sd").punchcard()`} drawTime={[0, 2]} />
|
||||
<MiniRepl client:idle tune={`s("bd sd")`} punchcard />
|
||||
|
||||
Then edit the text so it reads `s("bd sd cp hh")` and click the refresh icon.
|
||||
Congratulations, you have now live coded your first Strudel pattern!
|
||||
|
||||
@ -51,12 +51,12 @@ If you do just want to get a regular string that is _not_ parsed as mini-notatio
|
||||
|
||||
We can play more notes by separating them with spaces:
|
||||
|
||||
<MiniRepl client:idle tune={`note("c e g").punchcard()`} drawTime={[0, 4]} />
|
||||
<MiniRepl client:idle tune={`note("c e g b")`} punchcard />
|
||||
|
||||
Here, those four notes are squashed into one cycle, so each note is a quarter second long.
|
||||
Try adding or removing notes and notice how the tempo changes!
|
||||
|
||||
<MiniRepl client:idle tune={`note("c d e f g a b").punchcard()`} drawTime={[0, 4]} />
|
||||
<MiniRepl client:idle tune={`note("c d e f g a b")`} punchcard />
|
||||
|
||||
Note that the overall duration of time does not change, and instead each note length descreases.
|
||||
This is a key idea, as it illustrates the 'Cycle' in TidalCycles!
|
||||
@ -72,28 +72,28 @@ But, it will begin to make sense as we go through more elements of mini-notation
|
||||
|
||||
We can slow the sequence down by enclosing it in brackets and dividing it by a number (`/2`):
|
||||
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]/2")`} />
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]/2")`} punchcard />
|
||||
|
||||
The division by two means that the sequence will be played over the course of two cycles.
|
||||
You can also use decimal numbers for any tempo you like (`/2.75`).
|
||||
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]/2.75")`} />
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]/2.75")`} punchcard />
|
||||
|
||||
## Angle Brackets
|
||||
|
||||
Using angle brackets `<>`, we can define the sequence length based on the number of events:
|
||||
|
||||
<MiniRepl client:idle tune={`note("<e5 b4 d5 c5>")`} />
|
||||
<MiniRepl client:idle tune={`note("<e5 b4 d5 c5>")`} punchcard />
|
||||
|
||||
The above snippet is the same as:
|
||||
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]/4")`} />
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]/4")`} punchcard />
|
||||
|
||||
The advantage of the angle brackets, is that we can add more events without needing to change the number at the end.
|
||||
|
||||
<MiniRepl client:idle tune={`note("<e5 b4 d5 c5 e5>")`} />
|
||||
<MiniRepl client:idle tune={`note("<e5 b4 d5 c5 e5>")`} punchcard />
|
||||
|
||||
<MiniRepl client:idle tune={`note("<e5 b4 d5 c5 e5 b4>")`} />
|
||||
<MiniRepl client:idle tune={`note("<e5 b4 d5 c5 e5 b4>")`} punchcard />
|
||||
|
||||
This is more similar to traditional music sequencers and piano rolls, where adding a note increases the perceived overall duration.
|
||||
|
||||
@ -101,15 +101,13 @@ This is more similar to traditional music sequencers and piano rolls, where addi
|
||||
|
||||
Contrary to division, a sequence can be sped up by multiplying it by a number using the asterisk symbol (`*`):
|
||||
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]*2")`} />
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]*2")`} punchcard />
|
||||
|
||||
The multiplication by two here means that the sequence will play twice a cycle.
|
||||
|
||||
As with divisions, multiplications can be decimal (`*2.75`):
|
||||
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]*2.75")`} />
|
||||
|
||||
Actually, this is not true, but this will be [fixed](https://github.com/tidalcycles/strudel/issues/314) :)
|
||||
<MiniRepl client:idle tune={`note("[e5 b4 d5 c5]*2.75")`} punchcard />
|
||||
|
||||
## Subdividing time with bracket nesting
|
||||
|
||||
@ -133,7 +131,7 @@ Well, what this means is that in TidalCycles, not only can you divide time any w
|
||||
|
||||
The "~" represents a rest, and will create silence between other events:
|
||||
|
||||
<MiniRepl client:idle tune={`note("[b4 [~ c5] d5 e5]")`} />
|
||||
<MiniRepl client:idle tune={`note("[b4 [~ c5] d5 e5]")`} punchcard />
|
||||
|
||||
## Parallel / polyphony
|
||||
|
||||
@ -141,17 +139,17 @@ Using commas, we can play chords.
|
||||
The following are the same:
|
||||
|
||||
<MiniRepl client:idle tune={`note("[g3,b3,e4]")`} />
|
||||
<MiniRepl client:idle tune={`note("g3,b3,e4")`} />
|
||||
<MiniRepl client:idle tune={`note("g3,b3,e4")`} punchcard canvasHeight={80} />
|
||||
|
||||
But to play multiple chords in a sequence, we have to wrap them in brackets:
|
||||
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4] [b3,e4,g4]>")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4] [a3,c3,e4] [b3,d3,f#4] [b3,e4,g4]>")`} punchcard />
|
||||
|
||||
## Elongation
|
||||
|
||||
With the "@" symbol, we can specify temporal "weight" of a sequence child:
|
||||
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]@2 [a3,c3,e4] [b3,d3,f#4]>")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]@2 [a3,c3,e4] [b3,d3,f#4]>")`} punchcard />
|
||||
|
||||
Here, the first chord has a weight of 2, making it twice the length of the other chords. The default weight is 1.
|
||||
|
||||
@ -159,7 +157,7 @@ Here, the first chord has a weight of 2, making it twice the length of the other
|
||||
|
||||
Using "!" we can repeat without speeding up:
|
||||
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>")`} />
|
||||
<MiniRepl client:idle tune={`note("<[g3,b3,e4]!2 [a3,c3,e4] [b3,d3,f#4]>")`} punchcard />
|
||||
|
||||
In essence, the `x!n` is like a shortcut for `[x*n]@n`.
|
||||
|
||||
@ -181,24 +179,24 @@ Using round brackets after an event, we can create rhythmical sub-divisions base
|
||||
This algorithm can be found in many different types of music software, and is often referred to as a [Euclidean rhythm](https://en.wikipedia.org/wiki/Euclidean_rhythm) sequencer, after computer scientist Godfriend Toussaint.
|
||||
Why is it interesting? Well, consider the following simple example:
|
||||
|
||||
<MiniRepl client:idle tune={`s("bd(3,8,0)")`} />
|
||||
<MiniRepl client:idle tune={`s("bd(3,8,0)")`} punchcard canvasHeight={50} />
|
||||
|
||||
Sound familiar?
|
||||
This is a popular Euclidian rhythm going by various names, such as "Pop Clave".
|
||||
These rhythms can be found in all musical cultures, and the Euclidian rhythm algorithm allows us to express them extremely easily.
|
||||
Writing this rhythm out in full require describing:
|
||||
|
||||
<MiniRepl client:idle tune={`s("bd ~ ~ bd ~ ~ bd ~")`} />
|
||||
<MiniRepl client:idle tune={`s("bd ~ ~ bd ~ ~ bd ~")`} punchcard canvasHeight={50} />
|
||||
|
||||
But using the Euclidian rhythm notation, we only need to express "3 beats over 8 segments, starting on position 1".
|
||||
|
||||
This makes it easy to write patterns with interesting rhythmic structures and variations that still sound familiar:
|
||||
|
||||
<MiniRepl client:idle tune={`note("e5(2,8) b4(3,8) d5(2,8) c5(3,8)").slow(4)`} />
|
||||
<MiniRepl client:idle tune={`note("e5(2,8) b4(3,8) d5(2,8) c5(3,8)").slow(4)`} punchcard canvasHeight={50} />
|
||||
|
||||
Note that since the example above does not use the third `offset` parameter, it can be written simply as `"(3,8)"`.
|
||||
|
||||
<MiniRepl client:idle tune={`s("bd(3,8)")`} />
|
||||
<MiniRepl client:idle tune={`s("bd(3,8)")`} punchcard canvasHeight={50} />
|
||||
|
||||
Let's look at those three parameters in detail.
|
||||
|
||||
@ -207,26 +205,26 @@ Let's look at those three parameters in detail.
|
||||
`beats`: the first parameter controls how may beats will be played.
|
||||
Compare these:
|
||||
|
||||
<MiniRepl client:idle tune={`s("bd(2,8)")`} />
|
||||
<MiniRepl client:idle tune={`s("bd(5,8)")`} />
|
||||
<MiniRepl client:idle tune={`s("bd(7,8)")`} />
|
||||
<MiniRepl client:idle tune={`s("bd(2,8)")`} punchcard canvasHeight={50} />
|
||||
<MiniRepl client:idle tune={`s("bd(5,8)")`} punchcard canvasHeight={50} />
|
||||
<MiniRepl client:idle tune={`s("bd(7,8)")`} punchcard canvasHeight={50} />
|
||||
|
||||
### Segments
|
||||
|
||||
`segments`: the second parameter controls the total amount of segments the beats will be distributed over:
|
||||
|
||||
<MiniRepl client:idle tune={`s("bd(3,4)")`} />
|
||||
<MiniRepl client:idle tune={`s("bd(3,8)")`} />
|
||||
<MiniRepl client:idle tune={`s("bd(3,13)")`} />
|
||||
<MiniRepl client:idle tune={`s("bd(3,4)")`} punchcard canvasHeight={50} />
|
||||
<MiniRepl client:idle tune={`s("bd(3,8)")`} punchcard canvasHeight={50} />
|
||||
<MiniRepl client:idle tune={`s("bd(3,13)")`} punchcard canvasHeight={50} />
|
||||
|
||||
### Offsets
|
||||
|
||||
`offset`: the third (optional) parameter controls the starting position for distributing the beats.
|
||||
We need a secondary rhythm to hear the difference:
|
||||
|
||||
<MiniRepl client:idle tune={`s("bd(3,8,0), hh cp")`} />
|
||||
<MiniRepl client:idle tune={`s("bd(3,8,3), hh cp")`} />
|
||||
<MiniRepl client:idle tune={`s("bd(3,8,5), hh cp")`} />
|
||||
<MiniRepl client:idle tune={`s("bd(3,8,0), hh cp")`} punchcard />
|
||||
<MiniRepl client:idle tune={`s("bd(3,8,3), hh cp")`} punchcard />
|
||||
<MiniRepl client:idle tune={`s("bd(3,8,5), hh cp")`} punchcard />
|
||||
|
||||
## Mini-notation exercise
|
||||
|
||||
|
||||
@ -29,11 +29,11 @@ add a mini repl with
|
||||
|
||||
- `client:idle` is required to tell astro that the repl should be interactive, see [Client Directive](https://docs.astro.build/en/reference/directives-reference/#client-directives)
|
||||
- `tune`: be any valid pattern code
|
||||
- `drawTime`: time window for drawing. Use together with `.punchcard()`. Example:
|
||||
- `punchcard`: if added, a punchcard / pianoroll visualization is renderd
|
||||
- `drawTime`: time window for drawing, defaults to `[0, 4]`
|
||||
- `canvasHeight`: height of the canvas, defaults to 100px
|
||||
|
||||
```jsx
|
||||
<MiniRepl client:idle tune={`note("a3 c#4 e4 a4").punchcard()`} drawTime={[0, 2]} />
|
||||
```
|
||||
See `mini-notation.mdx` for usage examples
|
||||
|
||||
## In-Source Documentation
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user