mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-24 03:58:53 +00:00
use cm6 in tutorial
+ move highlighting to hook + optimize tutorial loading time
This commit is contained in:
parent
f00e28ced3
commit
fc9a9e33d2
32
repl/package-lock.json
generated
32
repl/package-lock.json
generated
@ -20,6 +20,7 @@
|
|||||||
"react-codemirror2": "^7.2.1",
|
"react-codemirror2": "^7.2.1",
|
||||||
"react-codemirror6": "^1.1.0",
|
"react-codemirror6": "^1.1.0",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
"react-hook-inview": "^4.4.1",
|
||||||
"react-scripts": "5.0.0",
|
"react-scripts": "5.0.0",
|
||||||
"tone": "^14.7.77",
|
"tone": "^14.7.77",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
@ -31,6 +32,7 @@
|
|||||||
"autoprefixer": "^10.4.4",
|
"autoprefixer": "^10.4.4",
|
||||||
"parcel": "^2.3.1",
|
"parcel": "^2.3.1",
|
||||||
"postcss": "^8.4.12",
|
"postcss": "^8.4.12",
|
||||||
|
"process": "^0.11.10",
|
||||||
"serve": "^13.0.2",
|
"serve": "^13.0.2",
|
||||||
"tailwindcss": "^3.0.23"
|
"tailwindcss": "^3.0.23"
|
||||||
}
|
}
|
||||||
@ -16435,6 +16437,15 @@
|
|||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/process": {
|
||||||
|
"version": "0.11.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||||
|
"integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/process-nextick-args": {
|
"node_modules/process-nextick-args": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
@ -16861,6 +16872,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
|
||||||
"integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA=="
|
"integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/react-hook-inview": {
|
||||||
|
"version": "4.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-hook-inview/-/react-hook-inview-4.4.1.tgz",
|
||||||
|
"integrity": "sha512-JKx0+aWCna0YUfTCKSaphGbaMp25S/YjpWtfk5VbqhlESesOEAPr7TCGMRLS3Cv6I1mEDhWYIhz2YLHgnHX4Yw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.0 || ^17.0.0",
|
||||||
|
"react-dom": "^16.8.0 || ^17.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
@ -31994,6 +32014,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"process": {
|
||||||
|
"version": "0.11.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||||
|
"integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"process-nextick-args": {
|
"process-nextick-args": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
@ -32317,6 +32343,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz",
|
||||||
"integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA=="
|
"integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA=="
|
||||||
},
|
},
|
||||||
|
"react-hook-inview": {
|
||||||
|
"version": "4.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-hook-inview/-/react-hook-inview-4.4.1.tgz",
|
||||||
|
"integrity": "sha512-JKx0+aWCna0YUfTCKSaphGbaMp25S/YjpWtfk5VbqhlESesOEAPr7TCGMRLS3Cv6I1mEDhWYIhz2YLHgnHX4Yw==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
"react-codemirror2": "^7.2.1",
|
"react-codemirror2": "^7.2.1",
|
||||||
"react-codemirror6": "^1.1.0",
|
"react-codemirror6": "^1.1.0",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
"react-hook-inview": "^4.4.1",
|
||||||
"react-scripts": "5.0.0",
|
"react-scripts": "5.0.0",
|
||||||
"tone": "^14.7.77",
|
"tone": "^14.7.77",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
@ -56,6 +57,7 @@
|
|||||||
"autoprefixer": "^10.4.4",
|
"autoprefixer": "^10.4.4",
|
||||||
"parcel": "^2.3.1",
|
"parcel": "^2.3.1",
|
||||||
"postcss": "^8.4.12",
|
"postcss": "^8.4.12",
|
||||||
|
"process": "^0.11.10",
|
||||||
"serve": "^13.0.2",
|
"serve": "^13.0.2",
|
||||||
"tailwindcss": "^3.0.23"
|
"tailwindcss": "^3.0.23"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,7 @@ import '@strudel.cycles/osc/osc.mjs';
|
|||||||
import '@strudel.cycles/webaudio/webaudio.mjs';
|
import '@strudel.cycles/webaudio/webaudio.mjs';
|
||||||
import '@strudel.cycles/serial/serial.mjs';
|
import '@strudel.cycles/serial/serial.mjs';
|
||||||
import controls from '@strudel.cycles/core/controls.mjs';
|
import controls from '@strudel.cycles/core/controls.mjs';
|
||||||
|
import useHighlighting from './useHighlighting';
|
||||||
|
|
||||||
extend(
|
extend(
|
||||||
Tone,
|
Tone,
|
||||||
@ -71,7 +72,6 @@ const defaultSynth = getDefaultSynth();
|
|||||||
function App() {
|
function App() {
|
||||||
// const [editor, setEditor] = useState();
|
// const [editor, setEditor] = useState();
|
||||||
const [view, setView] = useState();
|
const [view, setView] = useState();
|
||||||
const [codeToHighlight, setCodeToHighlight] = useState();
|
|
||||||
const {
|
const {
|
||||||
setCode,
|
setCode,
|
||||||
setPattern,
|
setPattern,
|
||||||
@ -90,11 +90,7 @@ function App() {
|
|||||||
} = useRepl({
|
} = useRepl({
|
||||||
tune: decoded || randomTune,
|
tune: decoded || randomTune,
|
||||||
defaultSynth,
|
defaultSynth,
|
||||||
// onDraw: useCallback((time, event) => markEvent(editor)(time, event), [editor]),
|
|
||||||
// onDraw: useCallback((_, e, code) => code && highlightEvent(e, view, code), [view]),
|
|
||||||
onDraw: () => {},
|
|
||||||
});
|
});
|
||||||
const [uiHidden, setUiHidden] = useState(false);
|
|
||||||
const logBox = useRef();
|
const logBox = useRef();
|
||||||
// scroll log box to bottom when log changes
|
// scroll log box to bottom when log changes
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
@ -119,28 +115,7 @@ function App() {
|
|||||||
return () => window.removeEventListener('keydown', handleKeyPress);
|
return () => window.removeEventListener('keydown', handleKeyPress);
|
||||||
}, [pattern, code, activateCode, cycle]);
|
}, [pattern, code, activateCode, cycle]);
|
||||||
|
|
||||||
useEffect(() => {
|
useHighlighting({ view, pattern, started: cycle.started });
|
||||||
if (view) {
|
|
||||||
if (pattern && cycle.started) {
|
|
||||||
let frame = requestAnimationFrame(updateHighlights);
|
|
||||||
|
|
||||||
function updateHighlights() {
|
|
||||||
let audioTime = Tone.Transport.seconds;
|
|
||||||
let timespan = new strudel.TimeSpan(audioTime, audioTime + 1 / 60);
|
|
||||||
let events = pattern.query(new strudel.State(timespan));
|
|
||||||
view.dispatch({ effects: setHighlights.of(events) });
|
|
||||||
|
|
||||||
frame = requestAnimationFrame(updateHighlights);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
cancelAnimationFrame(frame);
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
view.dispatch({ effects: setHighlights.of([]) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [pattern, cycle.started]);
|
|
||||||
|
|
||||||
useWebMidi({
|
useWebMidi({
|
||||||
ready: useCallback(
|
ready: useCallback(
|
||||||
@ -167,10 +142,7 @@ function App() {
|
|||||||
<div className="min-h-screen flex flex-col">
|
<div className="min-h-screen flex flex-col">
|
||||||
<header
|
<header
|
||||||
id="header"
|
id="header"
|
||||||
className={cx(
|
className="flex-none w-full h-14 px-2 flex border-b border-gray-200 justify-between z-[10] bg-gray-100"
|
||||||
'flex-none w-full h-14 px-2 flex border-b border-gray-200 justify-between z-[10]',
|
|
||||||
uiHidden ? 'bg-transparent text-white' : 'bg-gray-100',
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<img src={logo} className="Tidal-logo w-10 h-10" alt="logo" />
|
<img src={logo} className="Tidal-logo w-10 h-10" alt="logo" />
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Tone } from '@strudel.cycles/tone';
|
import { Tone } from '@strudel.cycles/tone';
|
||||||
import useRepl from '../useRepl.mjs';
|
import useRepl from '../useRepl.mjs';
|
||||||
import CodeMirror, { markEvent } from '../CodeMirror';
|
|
||||||
import cx from '../cx';
|
import cx from '../cx';
|
||||||
|
import useHighlighting from '../useHighlighting';
|
||||||
|
import { useInView } from 'react-hook-inview';
|
||||||
|
|
||||||
// eval stuff start
|
// eval stuff start
|
||||||
import { extend } from '@strudel.cycles/eval';
|
import { extend } from '@strudel.cycles/eval';
|
||||||
@ -24,6 +25,7 @@ import '@strudel.cycles/xen/tune.mjs';
|
|||||||
import '@strudel.cycles/core/euclid.mjs';
|
import '@strudel.cycles/core/euclid.mjs';
|
||||||
import '@strudel.cycles/tone/pianoroll.mjs';
|
import '@strudel.cycles/tone/pianoroll.mjs';
|
||||||
import '@strudel.cycles/tone/draw.mjs';
|
import '@strudel.cycles/tone/draw.mjs';
|
||||||
|
import CodeMirror6 from '../CodeMirror6';
|
||||||
|
|
||||||
extend(Tone, strudel, strudel.Pattern.prototype.bootstrap(), toneHelpers, voicingHelpers, drawHelpers, uiHelpers, {
|
extend(Tone, strudel, strudel.Pattern.prototype.bootstrap(), toneHelpers, voicingHelpers, drawHelpers, uiHelpers, {
|
||||||
gist,
|
gist,
|
||||||
@ -43,17 +45,19 @@ const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone.Destina
|
|||||||
// "balanced" | "interactive" | "playback";
|
// "balanced" | "interactive" | "playback";
|
||||||
// Tone.setContext(new Tone.Context({ latencyHint: 'playback', lookAhead: 1 }));
|
// Tone.setContext(new Tone.Context({ latencyHint: 'playback', lookAhead: 1 }));
|
||||||
function MiniRepl({ tune, maxHeight = 500 }) {
|
function MiniRepl({ tune, maxHeight = 500 }) {
|
||||||
const [editor, setEditor] = useState();
|
const { code, setCode, pattern, activateCode, error, cycle, dirty, togglePlay } = useRepl({
|
||||||
const { code, setCode, activateCode, activeCode, setPattern, error, cycle, dirty, log, togglePlay, hash } = useRepl({
|
|
||||||
tune,
|
tune,
|
||||||
defaultSynth,
|
defaultSynth,
|
||||||
autolink: false,
|
autolink: false,
|
||||||
onDraw: useCallback(markEvent(editor), [editor]),
|
|
||||||
});
|
});
|
||||||
const lines = code.split('\n').length;
|
const lines = code.split('\n').length;
|
||||||
const height = Math.min(lines * 30 + 30, maxHeight);
|
const [view, setView] = useState();
|
||||||
|
const [ref, isVisible] = useInView({
|
||||||
|
threshold: 0.01,
|
||||||
|
});
|
||||||
|
useHighlighting({ view, pattern, started: cycle.started });
|
||||||
return (
|
return (
|
||||||
<div className="rounded-md overflow-hidden">
|
<div className="rounded-md overflow-hidden bg-[#444C57]" ref={ref}>
|
||||||
<div className="flex justify-between bg-slate-700 border-t border-slate-500">
|
<div className="flex justify-between bg-slate-700 border-t border-slate-500">
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<button
|
<button
|
||||||
@ -101,18 +105,8 @@ function MiniRepl({ tune, maxHeight = 500 }) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="text-right p-1 text-sm">{error && <span className="text-red-200">{error.message}</span>}</div>{' '}
|
<div className="text-right p-1 text-sm">{error && <span className="text-red-200">{error.message}</span>}</div>{' '}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex space-y-0 overflow-auto" style={{ height }}>
|
<div className="flex space-y-0 overflow-auto relative">
|
||||||
<CodeMirror
|
{isVisible && <CodeMirror6 value={code} onChange={setCode} onViewChanged={setView} />}
|
||||||
className="w-full"
|
|
||||||
value={code}
|
|
||||||
editorDidMount={setEditor}
|
|
||||||
options={{
|
|
||||||
mode: 'javascript',
|
|
||||||
theme: 'material',
|
|
||||||
lineNumbers: true,
|
|
||||||
}}
|
|
||||||
onChange={(_, __, value) => setCode(value)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="bg-slate-700 border-t border-slate-500 content-right pr-2 text-right">
|
{/* <div className="bg-slate-700 border-t border-slate-500 content-right pr-2 text-right">
|
||||||
<a href={`https://strudel.tidalcycles.org/#${hash}`} className="text-white items-center inline-flex">
|
<a href={`https://strudel.tidalcycles.org/#${hash}`} className="text-white items-center inline-flex">
|
||||||
|
|||||||
28
repl/src/useHighlighting.js
Normal file
28
repl/src/useHighlighting.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
import { setHighlights } from './CodeMirror6';
|
||||||
|
import { Tone } from '@strudel.cycles/tone';
|
||||||
|
|
||||||
|
function useHighlighting({ view, pattern, started }) {
|
||||||
|
useEffect(() => {
|
||||||
|
if (view) {
|
||||||
|
if (pattern && started) {
|
||||||
|
let frame = requestAnimationFrame(updateHighlights);
|
||||||
|
|
||||||
|
function updateHighlights() {
|
||||||
|
const audioTime = Tone.getTransport().seconds;
|
||||||
|
const events = pattern.queryArc(audioTime, audioTime + 1 / 60);
|
||||||
|
view.dispatch({ effects: setHighlights.of(events) });
|
||||||
|
frame = requestAnimationFrame(updateHighlights);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelAnimationFrame(frame);
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
view.dispatch({ effects: setHighlights.of([]) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [pattern, started, view]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useHighlighting;
|
||||||
@ -26,7 +26,7 @@ function useRepl({ tune, defaultSynth, autolink = true, onEvent, onDraw: onDrawP
|
|||||||
// below block allows disabling the highlighting by including "strudel disable-highlighting" in the code (as comment)
|
// below block allows disabling the highlighting by including "strudel disable-highlighting" in the code (as comment)
|
||||||
const onDraw = useMemo(() => {
|
const onDraw = useMemo(() => {
|
||||||
if (activeCode && !activeCode.includes('strudel disable-highlighting')) {
|
if (activeCode && !activeCode.includes('strudel disable-highlighting')) {
|
||||||
return (time, event) => onDrawProp(time, event, activeCode);
|
return (time, event) => onDrawProp?.(time, event, activeCode);
|
||||||
}
|
}
|
||||||
}, [activeCode, onDrawProp]);
|
}, [activeCode, onDrawProp]);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user