diff --git a/packages/react/dist/index.cjs.js b/packages/react/dist/index.cjs.js
index 187182bf..bdcd41d6 100644
--- a/packages/react/dist/index.cjs.js
+++ b/packages/react/dist/index.cjs.js
@@ -1 +1 @@
-"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const t=require("react"),Z=require("@uiw/react-codemirror"),w=require("@codemirror/view"),x=require("@codemirror/state"),ee=require("@codemirror/lang-javascript"),s=require("@lezer/highlight"),te=require("@uiw/codemirror-themes"),B=require("@strudel.cycles/core"),K=require("@strudel.cycles/webaudio"),re=require("react-hook-inview"),ae=require("@strudel.cycles/transpiler"),I=e=>e&&typeof e=="object"&&"default"in e?e:{default:e},l=I(t),oe=I(Z),ne=te.createTheme({theme:"dark",settings:{background:"#222",foreground:"#75baff",caret:"#ffcc00",selection:"rgba(128, 203, 196, 0.5)",selectionMatch:"#036dd626",lineHighlight:"#00000050",gutterBackground:"transparent",gutterForeground:"#8a919966"},styles:[{tag:s.tags.keyword,color:"#c792ea"},{tag:s.tags.operator,color:"#89ddff"},{tag:s.tags.special(s.tags.variableName),color:"#eeffff"},{tag:s.tags.typeName,color:"#c3e88d"},{tag:s.tags.atom,color:"#f78c6c"},{tag:s.tags.number,color:"#c3e88d"},{tag:s.tags.definition(s.tags.variableName),color:"#82aaff"},{tag:s.tags.string,color:"#c3e88d"},{tag:s.tags.special(s.tags.string),color:"#c3e88d"},{tag:s.tags.comment,color:"#7d8799"},{tag:s.tags.variableName,color:"#c792ea"},{tag:s.tags.tagName,color:"#c3e88d"},{tag:s.tags.bracket,color:"#525154"},{tag:s.tags.meta,color:"#ffcb6b"},{tag:s.tags.attributeName,color:"#c792ea"},{tag:s.tags.propertyName,color:"#c792ea"},{tag:s.tags.className,color:"#decb6b"},{tag:s.tags.invalid,color:"#ffffff"}]});const L=x.StateEffect.define(),se=x.StateField.define({create(){return w.Decoration.none},update(e,a){try{for(let r of a.effects)if(r.is(L))if(r.value){const c=w.Decoration.mark({attributes:{style:"background-color: #FFCA2880"}});e=w.Decoration.set([c.range(0,a.newDoc.length)])}else e=w.Decoration.set([]);return e}catch(r){return console.warn("flash error",r),e}},provide:e=>w.EditorView.decorations.from(e)}),U=e=>{e.dispatch({effects:L.of(!0)}),setTimeout(()=>{e.dispatch({effects:L.of(!1)})},200)},A=x.StateEffect.define(),ce=x.StateField.define({create(){return w.Decoration.none},update(e,a){try{for(let r of a.effects)if(r.is(A)){const c=r.value.map(n=>(n.context.locations||[]).map(({start:i,end:u})=>{const f=n.context.color||"#FFCA28";let o=a.newDoc.line(i.line).from+i.column,d=a.newDoc.line(u.line).from+u.column;const g=a.newDoc.length;return o>g||d>g?void 0:w.Decoration.mark({attributes:{style:`outline: 1.5px solid ${f};`}}).range(o,d)})).flat().filter(Boolean)||[];e=w.Decoration.set(c,!0)}return e}catch{return w.Decoration.set([])}},provide:e=>w.EditorView.decorations.from(e)}),ie=[ee.javascript(),ne,ce,se];function W({value:e,onChange:a,onViewChanged:r,onSelectionChange:c,options:n,editorDidMount:i}){const u=t.useCallback(d=>{a?.(d)},[a]),f=t.useCallback(d=>{r?.(d)},[r]),o=t.useCallback(d=>{d.selectionSet&&c&&c?.(d.state.selection)},[c]);return l.default.createElement(l.default.Fragment,null,l.default.createElement(oe.default,{value:e,onChange:u,onCreateEditor:f,onUpdate:o,extensions:ie}))}function z(...e){return e.filter(Boolean).join(" ")}function $({view:e,pattern:a,active:r,getTime:c}){const n=t.useRef([]),i=t.useRef();t.useEffect(()=>{if(e)if(a&&r){let u=requestAnimationFrame(function f(){try{const o=c(),g=[Math.max(i.current||o,o-1/10,0),o+1/60];i.current=g[1],n.current=n.current.filter(b=>b.whole.end>o);const m=a.queryArc(...g).filter(b=>b.hasOnset());n.current=n.current.concat(m),e.dispatch({effects:A.of(n.current)})}catch{e.dispatch({effects:A.of([])})}u=requestAnimationFrame(f)});return()=>{cancelAnimationFrame(u)}}else n.current=[],e.dispatch({effects:A.of([])})},[a,r,e])}function le(e,a=!1){const r=t.useRef(),c=t.useRef(),n=f=>{if(c.current!==void 0){const o=f-c.current;e(f,o)}c.current=f,r.current=requestAnimationFrame(n)},i=()=>{r.current=requestAnimationFrame(n)},u=()=>{r.current&&cancelAnimationFrame(r.current),delete r.current};return t.useEffect(()=>{r.current&&(u(),i())},[e]),t.useEffect(()=>(a&&i(),u),[]),{start:i,stop:u}}function ue({pattern:e,started:a,getTime:r,onDraw:c}){let n=t.useRef([]),i=t.useRef(null);const{start:u,stop:f}=le(t.useCallback(()=>{const o=r();if(i.current===null){i.current=o;return}const d=e.queryArc(Math.max(i.current,o-1/10),o),g=4;i.current=o,n.current=(n.current||[]).filter(m=>m.whole.end>o-g).concat(d.filter(m=>m.hasOnset())),c(o,n.current)},[e]));t.useEffect(()=>{a?u():(n.current=[],f())},[a])}function J(e){return t.useEffect(()=>(window.addEventListener("message",e),()=>window.removeEventListener("message",e)),[e]),t.useCallback(a=>window.postMessage(a,"*"),[])}function G({defaultOutput:e,interval:a,getTime:r,evalOnMount:c=!1,initialCode:n="",autolink:i=!1,beforeEval:u,afterEval:f,onEvalError:o,onToggle:d,canvasId:g}){const m=t.useMemo(()=>de(),[]);g=g||`canvas-${m}`;const[b,k]=t.useState(),[C,q]=t.useState(),[E,M]=t.useState(n),[_,T]=t.useState(),[P,D]=t.useState(),[F,H]=t.useState(!1),v=E!==_,{scheduler:h,evaluate:R,start:Q,stop:V,pause:X}=t.useMemo(()=>B.repl({interval:a,defaultOutput:e,onSchedulerError:k,onEvalError:p=>{q(p),o?.(p)},getTime:r,transpiler:ae.transpiler,beforeEval:({code:p})=>{M(p),u?.()},afterEval:({pattern:p,code:N})=>{T(N),D(p),q(),k(),i&&(window.location.hash="#"+encodeURIComponent(btoa(N))),f?.()},onToggle:p=>{H(p),d?.(p)}}),[e,a,r]),Y=J(({data:{from:p,type:N}})=>{N==="start"&&p!==m&&V()}),S=t.useCallback(async(p=!0)=>{await R(E,p),Y({type:"start",from:m})},[R,E]),j=t.useRef();return t.useEffect(()=>{!j.current&&c&&E&&(j.current=!0,S())},[S,c,E]),t.useEffect(()=>()=>{h.stop()},[h]),{id:m,canvasId:g,code:E,setCode:M,error:b||C,schedulerError:b,scheduler:h,evalError:C,evaluate:R,activateCode:S,activeCode:_,isDirty:v,pattern:P,started:F,start:Q,stop:V,pause:X,togglePlay:async()=>{F?h.pause():await S()}}}function de(){return Math.floor((1+Math.random())*65536).toString(16).substring(1)}function O({type:e}){return l.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",className:"sc-h-5 sc-w-5",viewBox:"0 0 20 20",fill:"currentColor"},{refresh:l.default.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:l.default.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:l.default.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"})}[e])}const fe="_container_3i85k_1",ge="_header_3i85k_5",me="_buttons_3i85k_9",he="_button_3i85k_9",pe="_buttonDisabled_3i85k_17",ve="_error_3i85k_21",be="_body_3i85k_25",y={container:fe,header:ge,buttons:me,button:he,buttonDisabled:pe,error:ve,body:be},we=()=>K.getAudioContext().currentTime;function Ee({tune:e,hideOutsideView:a=!1,enableKeyboard:r,withCanvas:c=!1,canvasHeight:n=200}){const{code:i,setCode:u,evaluate:f,activateCode:o,error:d,isDirty:g,activeCode:m,pattern:b,started:k,scheduler:C,togglePlay:q,stop:E,canvasId:M}=G({initialCode:e,defaultOutput:K.webaudioOutput,getTime:we});ue({pattern:b,started:k,getTime:()=>C.now(),onDraw:(v,h)=>{const R=document.querySelector("#"+M).getContext("2d");B.pianoroll({ctx:R,time:v,haps:h,autorange:1,fold:1,playhead:1})}});const[_,T]=t.useState(),[P,D]=re.useInView({threshold:.01}),F=t.useRef(),H=t.useMemo(()=>((D||!a)&&(F.current=!0),D||F.current),[D,a]);return $({view:_,pattern:b,active:k&&!m?.includes("strudel disable-highlighting"),getTime:()=>C.getPhase()}),t.useLayoutEffect(()=>{if(r){const v=async h=>{(h.ctrlKey||h.altKey)&&(h.code==="Enter"?(h.preventDefault(),U(_),await o()):h.code==="Period"&&(E(),h.preventDefault()))};return window.addEventListener("keydown",v,!0),()=>window.removeEventListener("keydown",v,!0)}},[r,b,i,f,E,_]),l.default.createElement("div",{className:y.container,ref:P},l.default.createElement("div",{className:y.header},l.default.createElement("div",{className:y.buttons},l.default.createElement("button",{className:z(y.button,k?"sc-animate-pulse":""),onClick:()=>q()},l.default.createElement(O,{type:k?"pause":"play"})),l.default.createElement("button",{className:z(g?y.button:y.buttonDisabled),onClick:()=>o()},l.default.createElement(O,{type:"refresh"}))),d&&l.default.createElement("div",{className:y.error},d.message)),l.default.createElement("div",{className:y.body},H&&l.default.createElement(W,{value:i,onChange:u,onViewChanged:T})),c&&l.default.createElement("canvas",{id:M,className:"w-full pointer-events-none",height:n,ref:v=>{v&&v.width!==v.clientWidth&&(v.width=v.clientWidth)}}))}const ye=e=>t.useLayoutEffect(()=>(window.addEventListener("keydown",e,!0),()=>window.removeEventListener("keydown",e,!0)),[e]);exports.CodeMirror=W;exports.MiniRepl=Ee;exports.cx=z;exports.flash=U;exports.useHighlighting=$;exports.useKeydown=ye;exports.usePostMessage=J;exports.useStrudel=G;
+"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const t=require("react"),Z=require("@uiw/react-codemirror"),w=require("@codemirror/view"),x=require("@codemirror/state"),ee=require("@codemirror/lang-javascript"),c=require("@lezer/highlight"),te=require("@uiw/codemirror-themes"),B=require("@strudel.cycles/core"),K=require("@strudel.cycles/webaudio"),re=require("react-hook-inview"),ae=require("@strudel.cycles/transpiler"),I=e=>e&&typeof e=="object"&&"default"in e?e:{default:e},l=I(t),oe=I(Z),ne=te.createTheme({theme:"dark",settings:{background:"#222",foreground:"#75baff",caret:"#ffcc00",selection:"rgba(128, 203, 196, 0.5)",selectionMatch:"#036dd626",lineHighlight:"#00000050",gutterBackground:"transparent",gutterForeground:"#8a919966"},styles:[{tag:c.tags.keyword,color:"#c792ea"},{tag:c.tags.operator,color:"#89ddff"},{tag:c.tags.special(c.tags.variableName),color:"#eeffff"},{tag:c.tags.typeName,color:"#c3e88d"},{tag:c.tags.atom,color:"#f78c6c"},{tag:c.tags.number,color:"#c3e88d"},{tag:c.tags.definition(c.tags.variableName),color:"#82aaff"},{tag:c.tags.string,color:"#c3e88d"},{tag:c.tags.special(c.tags.string),color:"#c3e88d"},{tag:c.tags.comment,color:"#7d8799"},{tag:c.tags.variableName,color:"#c792ea"},{tag:c.tags.tagName,color:"#c3e88d"},{tag:c.tags.bracket,color:"#525154"},{tag:c.tags.meta,color:"#ffcb6b"},{tag:c.tags.attributeName,color:"#c792ea"},{tag:c.tags.propertyName,color:"#c792ea"},{tag:c.tags.className,color:"#decb6b"},{tag:c.tags.invalid,color:"#ffffff"}]});const L=x.StateEffect.define(),se=x.StateField.define({create(){return w.Decoration.none},update(e,a){try{for(let r of a.effects)if(r.is(L))if(r.value){const s=w.Decoration.mark({attributes:{style:"background-color: #FFCA2880"}});e=w.Decoration.set([s.range(0,a.newDoc.length)])}else e=w.Decoration.set([]);return e}catch(r){return console.warn("flash error",r),e}},provide:e=>w.EditorView.decorations.from(e)}),U=e=>{e.dispatch({effects:L.of(!0)}),setTimeout(()=>{e.dispatch({effects:L.of(!1)})},200)},A=x.StateEffect.define(),ce=x.StateField.define({create(){return w.Decoration.none},update(e,a){try{for(let r of a.effects)if(r.is(A)){const s=r.value.map(n=>(n.context.locations||[]).map(({start:i,end:u})=>{const f=n.context.color||"#FFCA28";let o=a.newDoc.line(i.line).from+i.column,d=a.newDoc.line(u.line).from+u.column;const g=a.newDoc.length;return o>g||d>g?void 0:w.Decoration.mark({attributes:{style:`outline: 1.5px solid ${f};`}}).range(o,d)})).flat().filter(Boolean)||[];e=w.Decoration.set(s,!0)}return e}catch{return w.Decoration.set([])}},provide:e=>w.EditorView.decorations.from(e)}),ie=[ee.javascript(),ne,ce,se];function W({value:e,onChange:a,onViewChanged:r,onSelectionChange:s,options:n,editorDidMount:i}){const u=t.useCallback(d=>{a?.(d)},[a]),f=t.useCallback(d=>{r?.(d)},[r]),o=t.useCallback(d=>{d.selectionSet&&s&&s?.(d.state.selection)},[s]);return l.default.createElement(l.default.Fragment,null,l.default.createElement(oe.default,{value:e,onChange:u,onCreateEditor:f,onUpdate:o,extensions:ie}))}function z(...e){return e.filter(Boolean).join(" ")}function $({view:e,pattern:a,active:r,getTime:s}){const n=t.useRef([]),i=t.useRef();t.useEffect(()=>{if(e)if(a&&r){let u=requestAnimationFrame(function f(){try{const o=s(),g=[Math.max(i.current||o,o-1/10,0),o+1/60];i.current=g[1],n.current=n.current.filter(v=>v.whole.end>o);const m=a.queryArc(...g).filter(v=>v.hasOnset());n.current=n.current.concat(m),e.dispatch({effects:A.of(n.current)})}catch{e.dispatch({effects:A.of([])})}u=requestAnimationFrame(f)});return()=>{cancelAnimationFrame(u)}}else n.current=[],e.dispatch({effects:A.of([])})},[a,r,e])}function le(e,a=!1){const r=t.useRef(),s=t.useRef(),n=f=>{if(s.current!==void 0){const o=f-s.current;e(f,o)}s.current=f,r.current=requestAnimationFrame(n)},i=()=>{r.current=requestAnimationFrame(n)},u=()=>{r.current&&cancelAnimationFrame(r.current),delete r.current};return t.useEffect(()=>{r.current&&(u(),i())},[e]),t.useEffect(()=>(a&&i(),u),[]),{start:i,stop:u}}function ue({pattern:e,started:a,getTime:r,onDraw:s}){let n=t.useRef([]),i=t.useRef(null);const{start:u,stop:f}=le(t.useCallback(()=>{const o=r();if(i.current===null){i.current=o;return}const d=e.queryArc(Math.max(i.current,o-1/10),o),g=4;i.current=o,n.current=(n.current||[]).filter(m=>m.whole.end>o-g).concat(d.filter(m=>m.hasOnset())),s(o,n.current)},[e]));t.useEffect(()=>{a?u():(n.current=[],f())},[a])}function J(e){return t.useEffect(()=>(window.addEventListener("message",e),()=>window.removeEventListener("message",e)),[e]),t.useCallback(a=>window.postMessage(a,"*"),[])}function G({defaultOutput:e,interval:a,getTime:r,evalOnMount:s=!1,initialCode:n="",autolink:i=!1,beforeEval:u,afterEval:f,onEvalError:o,onToggle:d,canvasId:g}){const m=t.useMemo(()=>de(),[]);g=g||`canvas-${m}`;const[v,k]=t.useState(),[C,q]=t.useState(),[E,M]=t.useState(n),[_,T]=t.useState(),[P,D]=t.useState(),[F,H]=t.useState(!1),b=E!==_,{scheduler:h,evaluate:R,start:Q,stop:V,pause:X}=t.useMemo(()=>B.repl({interval:a,defaultOutput:e,onSchedulerError:k,onEvalError:p=>{q(p),o?.(p)},getTime:r,transpiler:ae.transpiler,beforeEval:({code:p})=>{M(p),u?.()},afterEval:({pattern:p,code:N})=>{T(N),D(p),q(),k(),i&&(window.location.hash="#"+encodeURIComponent(btoa(N))),f?.()},onToggle:p=>{H(p),d?.(p)}}),[e,a,r]),Y=J(({data:{from:p,type:N}})=>{N==="start"&&p!==m&&V()}),S=t.useCallback(async(p=!0)=>{await R(E,p),Y({type:"start",from:m})},[R,E]),j=t.useRef();return t.useEffect(()=>{!j.current&&s&&E&&(j.current=!0,S())},[S,s,E]),t.useEffect(()=>()=>{h.stop()},[h]),{id:m,canvasId:g,code:E,setCode:M,error:v||C,schedulerError:v,scheduler:h,evalError:C,evaluate:R,activateCode:S,activeCode:_,isDirty:b,pattern:P,started:F,start:Q,stop:V,pause:X,togglePlay:async()=>{F?h.pause():await S()}}}function de(){return Math.floor((1+Math.random())*65536).toString(16).substring(1)}function O({type:e}){return l.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",className:"sc-h-5 sc-w-5",viewBox:"0 0 20 20",fill:"currentColor"},{refresh:l.default.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:l.default.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:l.default.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"})}[e])}const fe="_container_3i85k_1",ge="_header_3i85k_5",me="_buttons_3i85k_9",he="_button_3i85k_9",pe="_buttonDisabled_3i85k_17",be="_error_3i85k_21",ve="_body_3i85k_25",y={container:fe,header:ge,buttons:me,button:he,buttonDisabled:pe,error:be,body:ve},we=()=>K.getAudioContext().currentTime;function Ee({tune:e,hideOutsideView:a=!1,enableKeyboard:r,withCanvas:s=!1,canvasHeight:n=200}){const{code:i,setCode:u,evaluate:f,activateCode:o,error:d,isDirty:g,activeCode:m,pattern:v,started:k,scheduler:C,togglePlay:q,stop:E,canvasId:M}=G({initialCode:e,defaultOutput:K.webaudioOutput,getTime:we});ue({pattern:v,started:s&&k,getTime:()=>C.now(),onDraw:(b,h)=>{const R=document.querySelector("#"+M).getContext("2d");B.pianoroll({ctx:R,time:b,haps:h,autorange:1,fold:1,playhead:1})}});const[_,T]=t.useState(),[P,D]=re.useInView({threshold:.01}),F=t.useRef(),H=t.useMemo(()=>((D||!a)&&(F.current=!0),D||F.current),[D,a]);return $({view:_,pattern:v,active:k&&!m?.includes("strudel disable-highlighting"),getTime:()=>C.getPhase()}),t.useLayoutEffect(()=>{if(r){const b=async h=>{(h.ctrlKey||h.altKey)&&(h.code==="Enter"?(h.preventDefault(),U(_),await o()):h.code==="Period"&&(E(),h.preventDefault()))};return window.addEventListener("keydown",b,!0),()=>window.removeEventListener("keydown",b,!0)}},[r,v,i,f,E,_]),l.default.createElement("div",{className:y.container,ref:P},l.default.createElement("div",{className:y.header},l.default.createElement("div",{className:y.buttons},l.default.createElement("button",{className:z(y.button,k?"sc-animate-pulse":""),onClick:()=>q()},l.default.createElement(O,{type:k?"pause":"play"})),l.default.createElement("button",{className:z(g?y.button:y.buttonDisabled),onClick:()=>o()},l.default.createElement(O,{type:"refresh"}))),d&&l.default.createElement("div",{className:y.error},d.message)),l.default.createElement("div",{className:y.body},H&&l.default.createElement(W,{value:i,onChange:u,onViewChanged:T})),s&&l.default.createElement("canvas",{id:M,className:"w-full pointer-events-none",height:n,ref:b=>{b&&b.width!==b.clientWidth&&(b.width=b.clientWidth)}}))}const ye=e=>t.useLayoutEffect(()=>(window.addEventListener("keydown",e,!0),()=>window.removeEventListener("keydown",e,!0)),[e]);exports.CodeMirror=W;exports.MiniRepl=Ee;exports.cx=z;exports.flash=U;exports.useHighlighting=$;exports.useKeydown=ye;exports.usePostMessage=J;exports.useStrudel=G;
diff --git a/packages/react/dist/index.es.js b/packages/react/dist/index.es.js
index 0eb24591..6545e0a7 100644
--- a/packages/react/dist/index.es.js
+++ b/packages/react/dist/index.es.js
@@ -1,9 +1,9 @@
-import i, { useCallback as N, useRef as E, useEffect as C, useMemo as V, useState as _, useLayoutEffect as U } from "react";
+import i, { useCallback as N, useRef as E, useEffect as F, useMemo as V, useState as _, useLayoutEffect as U } from "react";
import Y from "@uiw/react-codemirror";
import { Decoration as y, EditorView as W } from "@codemirror/view";
import { StateEffect as $, StateField as G } from "@codemirror/state";
import { javascript as Z } from "@codemirror/lang-javascript";
-import { tags as a } from "@lezer/highlight";
+import { tags as s } from "@lezer/highlight";
import { createTheme as ee } from "@uiw/codemirror-themes";
import { repl as te, pianoroll as re } from "@strudel.cycles/core";
import { webaudioOutput as oe, getAudioContext as ne } from "@strudel.cycles/webaudio";
@@ -22,24 +22,24 @@ const ce = ee({
gutterForeground: "#8a919966"
},
styles: [
- { tag: a.keyword, color: "#c792ea" },
- { tag: a.operator, color: "#89ddff" },
- { tag: a.special(a.variableName), color: "#eeffff" },
- { tag: a.typeName, color: "#c3e88d" },
- { tag: a.atom, color: "#f78c6c" },
- { tag: a.number, color: "#c3e88d" },
- { tag: a.definition(a.variableName), color: "#82aaff" },
- { tag: a.string, color: "#c3e88d" },
- { tag: a.special(a.string), color: "#c3e88d" },
- { tag: a.comment, color: "#7d8799" },
- { tag: a.variableName, color: "#c792ea" },
- { tag: a.tagName, color: "#c3e88d" },
- { tag: a.bracket, color: "#525154" },
- { tag: a.meta, color: "#ffcb6b" },
- { tag: a.attributeName, color: "#c792ea" },
- { tag: a.propertyName, color: "#c792ea" },
- { tag: a.className, color: "#decb6b" },
- { tag: a.invalid, color: "#ffffff" }
+ { tag: s.keyword, color: "#c792ea" },
+ { tag: s.operator, color: "#89ddff" },
+ { tag: s.special(s.variableName), color: "#eeffff" },
+ { tag: s.typeName, color: "#c3e88d" },
+ { tag: s.atom, color: "#f78c6c" },
+ { tag: s.number, color: "#c3e88d" },
+ { tag: s.definition(s.variableName), color: "#82aaff" },
+ { tag: s.string, color: "#c3e88d" },
+ { tag: s.special(s.string), color: "#c3e88d" },
+ { tag: s.comment, color: "#7d8799" },
+ { tag: s.variableName, color: "#c792ea" },
+ { tag: s.tagName, color: "#c3e88d" },
+ { tag: s.bracket, color: "#525154" },
+ { tag: s.meta, color: "#ffcb6b" },
+ { tag: s.attributeName, color: "#c792ea" },
+ { tag: s.propertyName, color: "#c792ea" },
+ { tag: s.className, color: "#decb6b" },
+ { tag: s.invalid, color: "#ffffff" }
]
});
const B = $.define(), ie = G.define({
@@ -51,8 +51,8 @@ const B = $.define(), ie = G.define({
for (let t of r.effects)
if (t.is(B))
if (t.value) {
- const s = y.mark({ attributes: { style: "background-color: #FFCA2880" } });
- e = y.set([s.range(0, r.newDoc.length)]);
+ const a = y.mark({ attributes: { style: "background-color: #FFCA2880" } });
+ e = y.set([a.range(0, r.newDoc.length)]);
} else
e = y.set([]);
return e;
@@ -73,7 +73,7 @@ const B = $.define(), ie = G.define({
try {
for (let t of r.effects)
if (t.is(H)) {
- const s = t.value.map(
+ const a = t.value.map(
(n) => (n.context.locations || []).map(({ start: c, end: l }) => {
const d = n.context.color || "#FFCA28";
let o = r.newDoc.line(c.line).from + c.column, u = r.newDoc.line(l.line).from + l.column;
@@ -81,7 +81,7 @@ const B = $.define(), ie = G.define({
return o > f || u > f ? void 0 : y.mark({ attributes: { style: `outline: 1.5px solid ${d};` } }).range(o, u);
})
).flat().filter(Boolean) || [];
- e = y.set(s, !0);
+ e = y.set(a, !0);
}
return e;
} catch {
@@ -90,7 +90,7 @@ const B = $.define(), ie = G.define({
},
provide: (e) => W.decorations.from(e)
}), de = [Z(), ce, ue, ie];
-function fe({ value: e, onChange: r, onViewChanged: t, onSelectionChange: s, options: n, editorDidMount: c }) {
+function fe({ value: e, onChange: r, onViewChanged: t, onSelectionChange: a, options: n, editorDidMount: c }) {
const l = N(
(u) => {
r?.(u);
@@ -103,9 +103,9 @@ function fe({ value: e, onChange: r, onViewChanged: t, onSelectionChange: s, opt
[t]
), o = N(
(u) => {
- u.selectionSet && s && s?.(u.state.selection);
+ u.selectionSet && a && a?.(u.state.selection);
},
- [s]
+ [a]
);
return /* @__PURE__ */ i.createElement(i.Fragment, null, /* @__PURE__ */ i.createElement(Y, {
value: e,
@@ -118,14 +118,14 @@ function fe({ value: e, onChange: r, onViewChanged: t, onSelectionChange: s, opt
function j(...e) {
return e.filter(Boolean).join(" ");
}
-function me({ view: e, pattern: r, active: t, getTime: s }) {
+function me({ view: e, pattern: r, active: t, getTime: a }) {
const n = E([]), c = E();
- C(() => {
+ F(() => {
if (e)
if (r && t) {
let l = requestAnimationFrame(function d() {
try {
- const o = s(), f = [Math.max(c.current || o, o - 1 / 10, 0), o + 1 / 60];
+ const o = a(), f = [Math.max(c.current || o, o - 1 / 10, 0), o + 1 / 60];
c.current = f[1], n.current = n.current.filter((v) => v.whole.end > o);
const m = r.queryArc(...f).filter((v) => v.hasOnset());
n.current = n.current.concat(m), e.dispatch({ effects: H.of(n.current) });
@@ -142,25 +142,25 @@ function me({ view: e, pattern: r, active: t, getTime: s }) {
}, [r, t, e]);
}
function ge(e, r = !1) {
- const t = E(), s = E(), n = (d) => {
- if (s.current !== void 0) {
- const o = d - s.current;
+ const t = E(), a = E(), n = (d) => {
+ if (a.current !== void 0) {
+ const o = d - a.current;
e(d, o);
}
- s.current = d, t.current = requestAnimationFrame(n);
+ a.current = d, t.current = requestAnimationFrame(n);
}, c = () => {
t.current = requestAnimationFrame(n);
}, l = () => {
t.current && cancelAnimationFrame(t.current), delete t.current;
};
- return C(() => {
+ return F(() => {
t.current && (l(), c());
- }, [e]), C(() => (r && c(), l), []), {
+ }, [e]), F(() => (r && c(), l), []), {
start: c,
stop: l
};
}
-function pe({ pattern: e, started: r, getTime: t, onDraw: s }) {
+function pe({ pattern: e, started: r, getTime: t, onDraw: a }) {
let n = E([]), c = E(null);
const { start: l, stop: d } = ge(
N(() => {
@@ -170,21 +170,21 @@ function pe({ pattern: e, started: r, getTime: t, onDraw: s }) {
return;
}
const u = e.queryArc(Math.max(c.current, o - 1 / 10), o), f = 4;
- c.current = o, n.current = (n.current || []).filter((m) => m.whole.end > o - f).concat(u.filter((m) => m.hasOnset())), s(o, n.current);
+ c.current = o, n.current = (n.current || []).filter((m) => m.whole.end > o - f).concat(u.filter((m) => m.hasOnset())), a(o, n.current);
}, [e])
);
- C(() => {
+ F(() => {
r ? l() : (n.current = [], d());
}, [r]);
}
function he(e) {
- return C(() => (window.addEventListener("message", e), () => window.removeEventListener("message", e)), [e]), N((r) => window.postMessage(r, "*"), []);
+ return F(() => (window.addEventListener("message", e), () => window.removeEventListener("message", e)), [e]), N((r) => window.postMessage(r, "*"), []);
}
function ve({
defaultOutput: e,
interval: r,
getTime: t,
- evalOnMount: s = !1,
+ evalOnMount: a = !1,
initialCode: n = "",
autolink: c = !1,
beforeEval: l,
@@ -195,7 +195,7 @@ function ve({
}) {
const m = V(() => be(), []);
f = f || `canvas-${m}`;
- const [v, k] = _(), [M, T] = _(), [b, A] = _(n), [F, S] = _(), [z, D] = _(), [x, L] = _(!1), h = b !== F, { scheduler: g, evaluate: R, start: J, stop: O, pause: Q } = V(
+ const [v, k] = _(), [M, T] = _(), [b, A] = _(n), [C, S] = _(), [z, D] = _(), [x, L] = _(!1), h = b !== C, { scheduler: g, evaluate: R, start: J, stop: O, pause: Q } = V(
() => te({
interval: r,
defaultOutput: e,
@@ -224,9 +224,9 @@ function ve({
},
[R, b]
), K = E();
- return C(() => {
- !K.current && s && b && (K.current = !0, P());
- }, [P, s, b]), C(() => () => {
+ return F(() => {
+ !K.current && a && b && (K.current = !0, P());
+ }, [P, a, b]), F(() => () => {
g.stop();
}, [g]), {
id: m,
@@ -239,7 +239,7 @@ function ve({
evalError: M,
evaluate: R,
activateCode: P,
- activeCode: F,
+ activeCode: C,
isDirty: h,
pattern: z,
started: x,
@@ -278,16 +278,16 @@ function I({ type: e }) {
})
}[e]);
}
-const we = "_container_3i85k_1", ye = "_header_3i85k_5", Ee = "_buttons_3i85k_9", ke = "_button_3i85k_9", _e = "_buttonDisabled_3i85k_17", Ce = "_error_3i85k_21", Fe = "_body_3i85k_25", w = {
+const we = "_container_3i85k_1", ye = "_header_3i85k_5", Ee = "_buttons_3i85k_9", ke = "_button_3i85k_9", _e = "_buttonDisabled_3i85k_17", Fe = "_error_3i85k_21", Ce = "_body_3i85k_25", w = {
container: we,
header: ye,
buttons: Ee,
button: ke,
buttonDisabled: _e,
- error: Ce,
- body: Fe
+ error: Fe,
+ body: Ce
}, Ne = () => ne().currentTime;
-function Be({ tune: e, hideOutsideView: r = !1, enableKeyboard: t, withCanvas: s = !1, canvasHeight: n = 200 }) {
+function Be({ tune: e, hideOutsideView: r = !1, enableKeyboard: t, withCanvas: a = !1, canvasHeight: n = 200 }) {
const {
code: c,
setCode: l,
@@ -309,29 +309,29 @@ function Be({ tune: e, hideOutsideView: r = !1, enableKeyboard: t, withCanvas: s
});
pe({
pattern: v,
- started: k,
+ started: a && k,
getTime: () => M.now(),
onDraw: (h, g) => {
const R = document.querySelector("#" + A).getContext("2d");
re({ ctx: R, time: h, haps: g, autorange: 1, fold: 1, playhead: 1 });
}
});
- const [F, S] = _(), [z, D] = ae({
+ const [C, S] = _(), [z, D] = ae({
threshold: 0.01
}), x = E(), L = V(() => ((D || !r) && (x.current = !0), D || x.current), [D, r]);
return me({
- view: F,
+ view: C,
pattern: v,
active: k && !m?.includes("strudel disable-highlighting"),
getTime: () => M.getPhase()
}), U(() => {
if (t) {
const h = async (g) => {
- (g.ctrlKey || g.altKey) && (g.code === "Enter" ? (g.preventDefault(), le(F), await o()) : g.code === "Period" && (b(), g.preventDefault()));
+ (g.ctrlKey || g.altKey) && (g.code === "Enter" ? (g.preventDefault(), le(C), await o()) : g.code === "Period" && (b(), g.preventDefault()));
};
return window.addEventListener("keydown", h, !0), () => window.removeEventListener("keydown", h, !0);
}
- }, [t, v, c, d, b, F]), /* @__PURE__ */ i.createElement("div", {
+ }, [t, v, c, d, b, C]), /* @__PURE__ */ i.createElement("div", {
className: w.container,
ref: z
}, /* @__PURE__ */ i.createElement("div", {
@@ -356,7 +356,7 @@ function Be({ tune: e, hideOutsideView: r = !1, enableKeyboard: t, withCanvas: s
value: c,
onChange: l,
onViewChanged: S
- })), s && /* @__PURE__ */ i.createElement("canvas", {
+ })), a && /* @__PURE__ */ i.createElement("canvas", {
id: A,
className: "w-full pointer-events-none",
height: n,
diff --git a/packages/react/src/components/MiniRepl.jsx b/packages/react/src/components/MiniRepl.jsx
index 15c75e5c..a7874e55 100644
--- a/packages/react/src/components/MiniRepl.jsx
+++ b/packages/react/src/components/MiniRepl.jsx
@@ -37,7 +37,7 @@ export function MiniRepl({ tune, hideOutsideView = false, enableKeyboard, withCa
usePatternFrame({
pattern,
- started,
+ started: withCanvas && started,
getTime: () => scheduler.now(),
onDraw: (time, haps) => {
const ctx = document.querySelector('#' + canvasId).getContext('2d');
diff --git a/website/src/pages/learn/notes.mdx b/website/src/pages/learn/notes.mdx
index f4410e90..6bfd3b3d 100644
--- a/website/src/pages/learn/notes.mdx
+++ b/website/src/pages/learn/notes.mdx
@@ -15,7 +15,7 @@ Here's the same pattern written in three different ways:
- `note`: letter notation, good for those who are familiar with western music theory:
-
+
- `n`: number notation, good for those who want to use recognisable pitches, but don't care about music theory:
diff --git a/website/src/pages/technical-manual/docs.mdx b/website/src/pages/technical-manual/docs.mdx
new file mode 100644
index 00000000..30404ce4
--- /dev/null
+++ b/website/src/pages/technical-manual/docs.mdx
@@ -0,0 +1 @@
+TODO
\ No newline at end of file
diff --git a/website/src/pages/technical-manual/packages.mdx b/website/src/pages/technical-manual/packages.mdx
index cbab33b9..b4beeda6 100644
--- a/website/src/pages/technical-manual/packages.mdx
+++ b/website/src/pages/technical-manual/packages.mdx
@@ -7,4 +7,4 @@ There are different packages for different purposes. They..
Please refer to the individual README files in the [packages folder](https://github.com/tidalcycles/strudel/tree/main/packages)
-TODO
\ No newline at end of file
+TODO
diff --git a/website/src/pages/technical-manual/tests.mdx b/website/src/pages/technical-manual/tests.mdx
new file mode 100644
index 00000000..30404ce4
--- /dev/null
+++ b/website/src/pages/technical-manual/tests.mdx
@@ -0,0 +1 @@
+TODO
\ No newline at end of file