diff --git a/packages/codemirror/codemirror.mjs b/packages/codemirror/codemirror.mjs index 0a722e1d..99c537f5 100644 --- a/packages/codemirror/codemirror.mjs +++ b/packages/codemirror/codemirror.mjs @@ -154,9 +154,9 @@ export class StrudelMirror { this.prebaked = prebake(); autodraw && this.drawFirstFrame(); - this.repl = repl({ ...replOptions, + id, onToggle: (started) => { replOptions?.onToggle?.(started); if (started) { @@ -171,11 +171,11 @@ export class StrudelMirror { } else { this.drawer.stop(); updateMiniLocations(this.editor, []); - cleanupDraw(false); + cleanupDraw(false, id); } }, beforeEval: async () => { - cleanupDraw(); + cleanupDraw(true, id); this.painters = []; const self = this; // this is similar to repl.mjs > injectPatternMethods diff --git a/packages/core/evaluate.mjs b/packages/core/evaluate.mjs index ea63d8df..23cd44c1 100644 --- a/packages/core/evaluate.mjs +++ b/packages/core/evaluate.mjs @@ -37,11 +37,11 @@ function safeEval(str, options = {}) { return Function(body)(); } -export const evaluate = async (code, transpiler) => { +export const evaluate = async (code, transpiler, transpilerOptions) => { let meta = {}; if (transpiler) { // transform syntactically correct js code to semantically usable code - const transpiled = transpiler(code); + const transpiled = transpiler(code, transpilerOptions); code = transpiled.output; meta = transpiled; } diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs index 5b7bcd71..3f3f5f24 100644 --- a/packages/core/repl.mjs +++ b/packages/core/repl.mjs @@ -19,6 +19,7 @@ export function repl({ sync = false, setInterval, clearInterval, + id, }) { const state = { schedulerError: undefined, @@ -32,6 +33,10 @@ export function repl({ started: false, }; + const transpilerOptions = { + id, + }; + const updateState = (update) => { Object.assign(state, update); state.isDirty = state.code !== state.activeCode; @@ -139,9 +144,10 @@ export function repl({ try { updateState({ code, pending: true }); await injectPatternMethods(); + setTime(() => scheduler.now()); // TODO: refactor? await beforeEval?.({ code }); shouldHush && hush(); - let { pattern, meta } = await _evaluate(code, transpiler); + let { pattern, meta } = await _evaluate(code, transpiler, transpilerOptions); if (Object.keys(pPatterns).length) { pattern = stack(...Object.values(pPatterns)); } diff --git a/packages/draw/draw.mjs b/packages/draw/draw.mjs index 81123f46..7fe6441e 100644 --- a/packages/draw/draw.mjs +++ b/packages/draw/draw.mjs @@ -36,8 +36,8 @@ function stopAnimationFrame(id) { delete animationFrames[id]; } } -function stopAllAnimations() { - Object.keys(animationFrames).forEach((id) => stopAnimationFrame(id)); +function stopAllAnimations(replID) { + Object.keys(animationFrames).forEach((id) => (!replID || id.startsWith(replID)) && stopAnimationFrame(id)); } let memory = {}; @@ -72,13 +72,10 @@ Pattern.prototype.draw = function (fn, options) { return this; }; -export const cleanupDraw = (clearScreen = true) => { +export const cleanupDraw = (clearScreen = true, id) => { const ctx = getDrawContext(); clearScreen && ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.width); - stopAllAnimations(); - if (window.strudelScheduler) { - clearInterval(window.strudelScheduler); - } + stopAllAnimations(id); }; Pattern.prototype.onPaint = function () { diff --git a/packages/draw/pianoroll.mjs b/packages/draw/pianoroll.mjs index 247213b4..d0480ef5 100644 --- a/packages/draw/pianoroll.mjs +++ b/packages/draw/pianoroll.mjs @@ -266,7 +266,7 @@ export function getDrawOptions(drawTime, options = {}) { let [lookbehind, lookahead] = drawTime; lookbehind = Math.abs(lookbehind); const cycles = lookahead + lookbehind; - const playhead = lookbehind / cycles; + const playhead = cycles !== 0 ? lookbehind / cycles : 0; return { fold: 1, ...options, cycles, playhead }; } diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index 6cd01499..2e566305 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -69,6 +69,7 @@ export function transpiler(input, options = {}) { to: node.end, index, type, + id: options.id, }; emitWidgets && widgets.push(widgetConfig); return this.replace(widgetWithLocation(node, widgetConfig)); @@ -162,7 +163,7 @@ export function getWidgetID(widgetConfig) { // that means, if we use the index index of line position as id, less garbage is generated // return `widget_${widgetConfig.to}`; // more gargabe //return `widget_${widgetConfig.index}_${widgetConfig.to}`; // also more garbage - return `widget_${widgetConfig.type}_${widgetConfig.index}`; // less garbage + return `${widgetConfig.id || ''}_widget_${widgetConfig.type}_${widgetConfig.index}`; // less garbage } function widgetWithLocation(node, widgetConfig) { diff --git a/website/src/docs/MiniRepl.jsx b/website/src/docs/MiniRepl.jsx index 03e3d6d3..f8e79a0d 100644 --- a/website/src/docs/MiniRepl.jsx +++ b/website/src/docs/MiniRepl.jsx @@ -34,7 +34,7 @@ export function MiniRepl({ const canvasId = useMemo(() => `canvas-${id}`, [id]); const shouldDraw = !!punchcard || !!claviature; const shouldShowCanvas = !!punchcard; - const drawTime = punchcard ? [0, 4] : [0, 0]; + const drawTime = punchcard ? [0, 4] : [-2, 2]; const [activeNotes, setActiveNotes] = useState([]); const init = useCallback(({ code, shouldDraw }) => {