approaching proper draw logic in microrepl

This commit is contained in:
Felix Roos 2023-12-16 16:14:40 +01:00
parent fc034830d0
commit 7fcd9d8a83
3 changed files with 58 additions and 26 deletions

View File

@ -102,7 +102,8 @@ export class StrudelMirror {
this.onDraw?.(haps, time, currentFrame, this.painters); this.onDraw?.(haps, time, currentFrame, this.painters);
}, drawTime); }, drawTime);
// this approach might not work with multiple repls on screen.. // this approach does not work with multiple repls on screen
// TODO: refactor onPaint usages + find fix, maybe remove painters here?
Pattern.prototype.onPaint = function (onPaint) { Pattern.prototype.onPaint = function (onPaint) {
self.painters.push(onPaint); self.painters.push(onPaint);
return this; return this;

View File

@ -256,10 +256,13 @@ export function getDrawOptions(drawTime, options = {}) {
return { fold: 1, ...options, cycles, playhead }; return { fold: 1, ...options, cycles, playhead };
} }
export const getPunchcardPainter =
(options = {}) =>
(ctx, time, haps, drawTime, paintOptions = {}) =>
pianoroll({ ctx, time, haps, ...getDrawOptions(drawTime, { ...paintOptions, ...options }) });
Pattern.prototype.punchcard = function (options) { Pattern.prototype.punchcard = function (options) {
return this.onPaint((ctx, time, haps, drawTime, paintOptions = {}) => return this.onPaint(getPunchcardPainter(options));
pianoroll({ ctx, time, haps, ...getDrawOptions(drawTime, { ...paintOptions, ...options }) }),
);
}; };
/** /**

View File

@ -1,6 +1,6 @@
import { useState, useRef, useCallback, useEffect } from 'react'; import { useState, useRef, useCallback, useMemo } from 'react';
import { Icon } from './Icon'; import { Icon } from './Icon';
import { getDrawContext, silence } from '@strudel.cycles/core'; import { silence, getPunchcardPainter } from '@strudel.cycles/core';
import { transpiler } from '@strudel.cycles/transpiler'; import { transpiler } from '@strudel.cycles/transpiler';
import { getAudioContext, webaudioOutput } from '@strudel.cycles/webaudio'; import { getAudioContext, webaudioOutput } from '@strudel.cycles/webaudio';
import { StrudelMirror } from '@strudel/codemirror'; import { StrudelMirror } from '@strudel/codemirror';
@ -9,8 +9,8 @@ import { useInView } from 'react-hook-inview';
const initialSettings = { const initialSettings = {
keybindings: 'strudelTheme', keybindings: 'strudelTheme',
isLineNumbersDisplayed: false, isLineNumbersDisplayed: true,
isActiveLineHighlighted: true, isActiveLineHighlighted: false,
isAutoCompletionEnabled: false, isAutoCompletionEnabled: false,
isPatternHighlightingEnabled: true, isPatternHighlightingEnabled: true,
isFlashEnabled: true, isFlashEnabled: true,
@ -21,10 +21,33 @@ const initialSettings = {
fontSize: 18, fontSize: 18,
}; };
export function MicroRepl({ code, hideHeader = false, canvasHeight = 200, punchcard, punchcardLabels }) { export function MicroRepl({
const init = useCallback(({ code }) => { code,
const drawContext = getDrawContext(); hideHeader = false,
canvasHeight = 200,
onTrigger,
onPaint,
punchcard,
punchcardLabels = true,
}) {
const id = useMemo(() => s4(), []);
const canvasId = useMemo(() => `canvas-${id}`, [id]);
const shouldDraw = !!punchcard;
const init = useCallback(({ code, shouldDraw }) => {
const drawTime = [-2, 2]; const drawTime = [-2, 2];
const drawContext = shouldDraw ? document.querySelector('#' + canvasId)?.getContext('2d') : null;
let onDraw;
if (shouldDraw) {
onDraw = (haps, time, frame, painters) => {
painters.length && drawContext.clearRect(0, 0, drawContext.canvas.width * 2, drawContext.canvas.height * 2);
painters?.forEach((painter) => {
// ctx time haps drawTime paintOptions
painter(drawContext, time, haps, drawTime, { clear: false });
});
};
}
const editor = new StrudelMirror({ const editor = new StrudelMirror({
defaultOutput: webaudioOutput, defaultOutput: webaudioOutput,
getTime: () => getAudioContext().currentTime, getTime: () => getAudioContext().currentTime,
@ -34,12 +57,17 @@ export function MicroRepl({ code, hideHeader = false, canvasHeight = 200, punchc
pattern: silence, pattern: silence,
settings: initialSettings, settings: initialSettings,
drawTime, drawTime,
onDraw: (haps, time, frame, painters) => { onDraw,
painters.length && drawContext.clearRect(0, 0, drawContext.canvas.width * 2, drawContext.canvas.height * 2); editPattern: (pat, id) => {
painters?.forEach((painter) => { if (onTrigger) {
// ctx time haps drawTime paintOptions pat = pat.onTrigger(onTrigger, false);
painter(drawContext, time, haps, drawTime, { clear: false }); }
}); if (onPaint) {
editor.painters.push(onPaint);
} else if (punchcard) {
editor.painters.push(getPunchcardPainter({ labels: !!punchcardLabels }));
}
return pat;
}, },
prebake, prebake,
onUpdateState: (state) => { onUpdateState: (state) => {
@ -56,7 +84,7 @@ export function MicroRepl({ code, hideHeader = false, canvasHeight = 200, punchc
threshold: 0.01, threshold: 0.01,
onEnter: () => { onEnter: () => {
if (!editorRef.current) { if (!editorRef.current) {
init({ code }); init({ code, shouldDraw });
} }
}, },
}); });
@ -65,12 +93,6 @@ export function MicroRepl({ code, hideHeader = false, canvasHeight = 200, punchc
const editorRef = useRef(); const editorRef = useRef();
const containerRef = useRef(); const containerRef = useRef();
const [canvasId] = useState(Date.now());
const drawContext = useCallback(
punchcard ? (canvasId) => document.querySelector('#' + canvasId)?.getContext('2d') : null,
[punchcard],
);
return ( return (
<div className="overflow-hidden rounded-t-md bg-background border border-lineHighlight" ref={ref}> <div className="overflow-hidden rounded-t-md bg-background border border-lineHighlight" ref={ref}>
{!hideHeader && ( {!hideHeader && (
@ -101,7 +123,7 @@ export function MicroRepl({ code, hideHeader = false, canvasHeight = 200, punchc
<div ref={containerRef}></div> <div ref={containerRef}></div>
{error && <div className="text-right p-1 text-md text-red-200">{error.message}</div>} {error && <div className="text-right p-1 text-md text-red-200">{error.message}</div>}
</div> </div>
{/* punchcard && ( {shouldDraw && (
<canvas <canvas
id={canvasId} id={canvasId}
className="w-full pointer-events-none border-t border-lineHighlight" className="w-full pointer-events-none border-t border-lineHighlight"
@ -117,7 +139,7 @@ export function MicroRepl({ code, hideHeader = false, canvasHeight = 200, punchc
//} //}
}} }}
></canvas> ></canvas>
) */} )}
{/* !!log.length && ( {/* !!log.length && (
<div className="bg-gray-800 rounded-md p-2"> <div className="bg-gray-800 rounded-md p-2">
{log.map(({ message }, i) => ( {log.map(({ message }, i) => (
@ -133,3 +155,9 @@ function cx(...classes) {
// : Array<string | undefined> // : Array<string | undefined>
return classes.filter(Boolean).join(' '); return classes.filter(Boolean).join(' ');
} }
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}