diff --git a/packages/repl/index.mjs b/packages/repl/index.mjs index 330cd77d..4119059d 100644 --- a/packages/repl/index.mjs +++ b/packages/repl/index.mjs @@ -1 +1,2 @@ export * from './repl-component.mjs'; +export * from './prebake.mjs'; diff --git a/packages/repl/repl-component.mjs b/packages/repl/repl-component.mjs index 2eda358d..b8947640 100644 --- a/packages/repl/repl-component.mjs +++ b/packages/repl/repl-component.mjs @@ -103,8 +103,6 @@ if (typeof HTMLElement !== 'undefined') { // init settings this.editor.updateSettings(this.settings); this.editor.setCode(this.code); - // settingsMap.listen((settings, key) => editor.changeSetting(key, settings[key])); - // onEvent('strudel-toggle-play', () => this.editor.toggle()); } // Element functionality written in here } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 344a24bc..67599cd9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -793,6 +793,9 @@ importers: react-dom: specifier: ^18.2.0 version: 18.2.0(react@18.2.0) + react-hook-inview: + specifier: ^4.5.0 + version: 4.5.0(react-dom@18.2.0)(react@18.2.0) rehype-autolink-headings: specifier: ^6.1.1 version: 6.1.1 diff --git a/website/package.json b/website/package.json index b2267a69..b2c5f39a 100644 --- a/website/package.json +++ b/website/package.json @@ -34,9 +34,9 @@ "@strudel.cycles/transpiler": "workspace:*", "@strudel.cycles/webaudio": "workspace:*", "@strudel.cycles/xen": "workspace:*", - "@strudel/hydra": "workspace:*", "@strudel/codemirror": "workspace:*", "@strudel/desktopbridge": "workspace:*", + "@strudel/hydra": "workspace:*", "@strudel/repl": "workspace:*", "@supabase/supabase-js": "^2.21.0", "@tailwindcss/forms": "^0.5.3", @@ -54,6 +54,7 @@ "nanostores": "^0.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-hook-inview": "^4.5.0", "rehype-autolink-headings": "^6.1.1", "rehype-slug": "^5.0.1", "rehype-urls": "^1.1.1", diff --git a/website/src/docs/MicroRepl.jsx b/website/src/docs/MicroRepl.jsx index c0e34637..cc401cd6 100644 --- a/website/src/docs/MicroRepl.jsx +++ b/website/src/docs/MicroRepl.jsx @@ -1,32 +1,78 @@ import { useState, useRef, useCallback, useEffect } from 'react'; import { Icon } from './Icon'; -import '@strudel/repl'; +import { getDrawContext, silence } from '@strudel.cycles/core'; +import { transpiler } from '@strudel.cycles/transpiler'; +import { getAudioContext, webaudioOutput } from '@strudel.cycles/webaudio'; +import { StrudelMirror } from '@strudel/codemirror'; +import { prebake } from '@strudel/repl'; +import { useInView } from 'react-hook-inview'; -// import { useInView } from 'react-hook-inview'; +const initialSettings = { + keybindings: 'strudelTheme', + isLineNumbersDisplayed: false, + isActiveLineHighlighted: true, + isAutoCompletionEnabled: false, + isPatternHighlightingEnabled: true, + isFlashEnabled: true, + isTooltipEnabled: false, + isLineWrappingEnabled: false, + theme: 'strudelTheme', + fontFamily: 'monospace', + fontSize: 18, +}; -export function MicroRepl({ code, hideHeader = false }) { - /* const [ref, isVisible] = useInView({ +export function MicroRepl({ code, hideHeader = false, canvasHeight = 200, punchcard, punchcardLabels }) { + const init = useCallback(({ code }) => { + const drawContext = getDrawContext(); + const drawTime = [-2, 2]; + const editor = new StrudelMirror({ + defaultOutput: webaudioOutput, + getTime: () => getAudioContext().currentTime, + transpiler, + root: containerRef.current, + initialCode: '// LOADING', + pattern: silence, + settings: initialSettings, + drawTime, + 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 }); + }); + }, + prebake, + onUpdateState: (state) => { + setReplState({ ...state }); + }, + }); + // init settings + editor.updateSettings(initialSettings); + editor.setCode(code); + editorRef.current = editor; + }, []); + + const [ref, isVisible] = useInView({ threshold: 0.01, - }); */ + onEnter: () => { + if (!editorRef.current) { + init({ code }); + } + }, + }); const [replState, setReplState] = useState({}); const { started, isDirty, error } = replState; - const wc = useRef(); - function togglePlay() { - if (wc.current) { - wc.current?.editor.toggle(); - } - } - const listener = useCallback((e) => setReplState({ ...e.detail }), []); - useEffect(() => { - return () => { - wc.current.removeEventListener('update', listener); - }; - }, []); + const editorRef = useRef(); + const containerRef = useRef(); + + const [canvasId] = useState(Date.now()); + const drawContext = useCallback( + punchcard ? (canvasId) => document.querySelector('#' + canvasId)?.getContext('2d') : null, + [punchcard], + ); + return ( -