- add Stepper + use it everywhere

- rename files to make more sense
- add transpilation slide
This commit is contained in:
Felix Roos
2023-04-06 22:14:17 +02:00
parent 8ca850f9fe
commit 123323e32b
17 changed files with 200 additions and 92 deletions
+1 -1
View File
@@ -28,7 +28,7 @@ function EventEditor({ code: initialCode }) {
await initAudio;
json.forEach((value) => {
const hap = new Hap(new TimeSpan(0, 1), new TimeSpan(0, 1), value);
webaudioOutput(hap, 0.1, 1, 1);
webaudioOutput(hap, 0.01, 1, 1);
});
} else if (e.key === '.') {
stop();
+10 -16
View File
@@ -1,8 +1,8 @@
import EventEditor from './EventEditor.jsx';
import { useState } from 'react';
import Stepper from './Stepper.jsx';
const snippets = [
[`{ "s": "cp" }`, 'Samples'],
[`{ "s": "cp", "crush": 4 }`, 'Samples'],
[`{ "s": "sawtooth", "note": "e3" }`, 'Oscillators'],
[
`[
@@ -24,21 +24,15 @@ const snippets = [
];
function EventsDemo() {
const [step, setStep] = useState(1);
return (
<div className="not-prose">
{snippets.slice(0, step).map(([code, label], i) => {
const isActive = i === step - 1;
return (
<div key={i} className={`border-l-4 pl-8 border-gray-500 py-4 ${isActive ? 'p-4 border-yellow-500' : ''}`}>
<h3 className="pb-4">{label}</h3>
<EventEditor code={code} />
</div>
);
})}
{step < snippets.length && <button onClick={() => setStep((r) => r + 1)}>next</button>}
</div>
<Stepper
steps={snippets.map(([code, label]) => (
<>
<h3 className="pb-4">{label}</h3>
<EventEditor code={code} />
</>
))}
/>
);
}
+9 -4
View File
@@ -1,12 +1,17 @@
import SyntaxHighlighter from 'react-syntax-highlighter';
//import {Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
//import { atomDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
//import SyntaxHighlighter from 'react-syntax-highlighter';
import { atomOneDark } from 'react-syntax-highlighter/dist/esm/styles/hljs';
Object.assign(atomOneDark.hljs, { padding: '10px' });
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter';
import js from 'react-syntax-highlighter/dist/esm/languages/hljs/javascript';
import hs from 'react-syntax-highlighter/dist/esm/languages/hljs/haskell';
SyntaxHighlighter.registerLanguage('javascript', js);
SyntaxHighlighter.registerLanguage('haskell', hs);
function Highlight({ code, language }) {
return (
<div className="mb-4 text-[32px] leading-10 rounded-xl overflow-hidden">
<SyntaxHighlighter language={language} style={atomOneDark}>
<SyntaxHighlighter language={language} style={atomOneDark} customStyle={{ padding: '8px 10px' }}>
{code}
</SyntaxHighlighter>
</div>
+15 -20
View File
@@ -1,5 +1,5 @@
import { useState } from 'react';
import { SlideRepl } from './SlideRepl.jsx';
import Stepper from './Stepper.jsx';
const snippets = [
[`sound("bd [hh sd]")`, `sound(seq("bd", ["hh", "sd"]))`, 'Nested Sequences'], //
@@ -11,7 +11,6 @@ const snippets = [
];
function MiniComparison() {
const [step, setStep] = useState(1);
return (
<>
<h1>
@@ -19,25 +18,21 @@ function MiniComparison() {
<br />
<small>External DSL</small>
</h1>
<div className="not-prose">
{snippets.slice(0, step).map(([a, b, label], i) => {
const isActive = i === step - 1;
return (
<div key={i} className={`border-l-4 pl-8 border-gray-500 py-4 ${isActive ? 'p-4 border-yellow-500' : ''}`}>
<h3 className="pb-4">{label}</h3>
<div className="flex space-x-2">
<img src="./img/tidalcycles.svg" className={`h-10 mt-2`} />
<SlideRepl tune={a} hideHeader />
</div>
<div className="flex space-x-2">
<img src="./img/js.jpg" className={`h-10 mt-2`} />
<SlideRepl tune={b} hideHeader />
</div>
<Stepper
steps={snippets.map(([a, b, label]) => (
<>
<h3 className="pb-4">{label}</h3>
<div className="flex space-x-2">
<img src="./img/tidalcycles.svg" className={`h-10 mt-2`} />
<SlideRepl tune={a} hideHeader />
</div>
);
})}
</div>
{step < snippets.length && <button onClick={() => setStep((r) => r + 1)}>next</button>}
<div className="flex space-x-2">
<img src="./img/js.jpg" className={`h-10 mt-2`} />
<SlideRepl tune={b} hideHeader />
</div>
</>
))}
/>
</>
);
}
+16 -20
View File
@@ -1,22 +1,23 @@
import { SlideRepl } from './SlideRepl.jsx';
import Highlight from './Highlight.jsx';
import { useState } from 'react';
import Stepper from './Stepper.jsx';
const snippets = [
[<SlideRepl tune={`sound("bd [hh sd]").crush(4).log()`} hideHeader />, 'Logging Events'],
[<SlideRepl tune={`s("bd [hh sd]").crush(4).log()`} hideHeader />, 'Logging Events'],
[
<>
<Highlight
code={`sound("bd [hh sd]").crush(4) // pattern
.queryArc(0, 1)`}
code={`let pattern = s("bd [hh sd]").crush(4);
let events = pattern.queryArc(0, 1);
console.log(events.map(e => e.show()))`}
language="javascript"
/>
<Highlight
language="json"
code={`[
"0/1 -> 1/2 | sound:bd",
"1/2 -> 3/4 | sound:hh",
"3/4 -> 1/1 | sound:sd"
"0/1 -> 1/2 | s:bd crush:4",
"1/2 -> 3/4 | s:hh crush:4",
"3/4 -> 1/1 | s:sd crush:4"
]`}
/>
</>,
@@ -25,20 +26,15 @@ const snippets = [
];
function QueryDemo() {
const [step, setStep] = useState(1);
return (
<div className="not-prose">
{snippets.slice(0, step).map(([snippet, label], i) => {
const isActive = i === step - 1;
return (
<div key={i} className={`border-l-4 pl-8 border-gray-500 py-4 ${isActive ? 'p-4 border-yellow-500' : ''}`}>
<h3 className="pb-4">{label}</h3>
{snippet}
</div>
);
})}
{step < snippets.length && <button onClick={() => setStep((r) => r + 1)}>next</button>}
</div>
<Stepper
steps={snippets.map(([snippet, label]) => (
<>
<h3 className="pb-4">{label}</h3>
{snippet}
</>
))}
/>
);
}
+12 -1
View File
@@ -16,7 +16,18 @@ const loadedMDXFiles = await Promise.all(
}),
);
const order = ['01', '02-0', '02-1', '02-2', 'mini-comparison', 'patterns-events', 'events-audio', '04'];
const order = [
'cover',
'whatIsStrudel',
'history',
'hs2js',
'mini-comparison',
'patterns-events',
'events-audio',
'transpilation',
'replflow',
'systems',
];
const slideEntries = order.map((name) => loadedMDXFiles.find(([file]) => file === name));
+20
View File
@@ -0,0 +1,20 @@
import { useState } from 'react';
function Stepper({ steps }) {
const [step, setStep] = useState(1);
return (
<div className="not-prose">
{steps.slice(0, step).map((snippet, i) => {
const isActive = i === step - 1;
return (
<div key={i} className={`border-l-4 pl-8 border-gray-500 py-4 ${isActive ? 'p-4 border-yellow-500' : ''}`}>
{snippet}
</div>
);
})}
{step < steps.length && <button onClick={() => setStep((r) => r + 1)}>next</button>}
</div>
);
}
export default Stepper;
+19 -28
View File
@@ -1,6 +1,6 @@
import { useState } from 'react';
import { SlideRepl } from './SlideRepl.jsx';
import Highlight from './Highlight.jsx';
import Stepper from './Stepper.jsx';
const snippets = [
[`sound "bd ~ [sd cp]"`, [`sound("bd ~ [sd cp]")`], 'Mini Notation'], //
@@ -40,7 +40,6 @@ const snippets = [
];
function SyntaxComparison() {
const [step, setStep] = useState(1);
return (
<>
<h1>
@@ -48,35 +47,27 @@ function SyntaxComparison() {
<br />
<small>Internal DSL / Fluent Interface</small>
</h1>
<div className=" not-prose justify-start items-start">
{/* <div className="grid grid-cols-2">
<div>Tidal</div>
<div>Strudel</div>
</div> */}
{snippets.slice(0, step).map(([hs, js, label], i) => {
const isActive = i === step - 1;
return (
<div key={i} className={`border-l-4 pl-8 border-gray-500 py-4 ${isActive ? 'p-4 border-yellow-500' : ''}`}>
<h3 className="pb-4">{label}</h3>
<Stepper
steps={snippets.map(([hs, js, label]) => (
<>
<h3 className="pb-4">{label}</h3>
<div>
<div className="flex space-x-4">
<img src="./img/haskell.png" className="h-10 mt-2" />
<Highlight language="haskell" code={hs} />
</div>
<div>
<div className="flex space-x-4">
<img src="./img/haskell.png" className="h-10 mt-2" />
<Highlight language="haskell" code={hs} />
</div>
<div>
{js.map((c, j) => (
<div className="flex space-x-4" key={j}>
<img src="./img/js.jpg" className={`h-10 mt-2`} />
<SlideRepl tune={c} hideHeader />
</div>
))}
</div>
{js.map((c, j) => (
<div className="flex space-x-4" key={j}>
<img src="./img/js.jpg" className={`h-10 mt-2`} />
<SlideRepl tune={c} hideHeader />
</div>
))}
</div>
</div>
);
})}
</div>
{step < snippets.length && <button onClick={() => setStep((r) => r + 1)}>next</button>}
</>
))}
/>
</>
);
}
+91
View File
@@ -0,0 +1,91 @@
import { useState, useCallback } from 'react';
import { atomone } from '@uiw/codemirror-themes-all';
import { CodeMirror, flash, useKeydown } from '@strudel.cycles/react';
import { transpiler } from '@strudel.cycles/transpiler';
import Highlight from './Highlight';
import Stepper from './Stepper';
import escodegen from 'escodegen';
function getTranspiled(code) {
return transpiler(code, {
addReturn: false,
codegenOptions: {
format: escodegen.FORMAT_MINIFY,
},
});
}
function TranspilationEditor({ code: initialCode }) {
const [code, setCode] = useState(initialCode);
const [transpiled, setTranspiled] = useState(getTranspiled(initialCode));
const [view, setView] = useState();
useKeydown(
useCallback(
async (e) => {
if (view?.hasFocus) {
if (e.ctrlKey || e.altKey) {
if (e.code === 'Enter') {
/* if (getAudioContext().state !== 'running') {
alert('please click play to initialize the audio. you can use shortcuts after that!');
return;
} */
e.preventDefault();
flash(view);
const t = getTranspiled(code);
setTranspiled(t);
console.log('transpiled', t);
} else if (e.key === '.') {
stop();
e.preventDefault();
}
}
}
},
[code, view],
),
);
return (
<>
<CodeMirror
value={code}
onChange={(v) => {
setCode(v);
}}
theme={atomone}
onViewChanged={(v) => setView(v)}
fontSize={32}
/>
<span>
transpiles to <small>via acorn / estree-walker / escodegen</small>
</span>
<Highlight language="javascript" code={transpiled} />
</>
);
}
function TranspilationDemo() {
return (
<div className="not-prose space-y-8">
<Stepper
steps={[
<TranspilationEditor code={`"bd [hh sd]".s()`} />,
<>
<span> calls </span> <small>via peggy</small>
<Highlight
code={`seq(
reify('bd').withLocation([1,1,1], [1,4,4]),
seq(
reify('hh').withLocation([1,5,5], [1,8,8]),
reify('sd').withLocation([1,8,8], [1,10,10]),
)
).withMiniLocation([1,0,0],[1,12,12]).s()`}
/>
<span> location can be used for highlighting</span>
</>,
]}
/>
</div>
);
}
export default TranspilationDemo;
@@ -0,0 +1,5 @@
import TranspilationDemo from '../TranspilationDemo';
# Transpilation
<TranspilationDemo />
+2 -2
View File
@@ -4,7 +4,7 @@ import { walk } from 'estree-walker';
import { isNoteWithOctave } from '@strudel.cycles/core';
export function transpiler(input, options = {}) {
const { wrapAsync = false, addReturn = true, simpleLocs = false } = options;
const { wrapAsync = false, addReturn = true, simpleLocs = false, codegenOptions = {} } = options;
let ast = parse(input, {
ecmaVersion: 2022,
@@ -47,7 +47,7 @@ export function transpiler(input, options = {}) {
argument: expression,
};
}
const output = escodegen.generate(ast);
const output = escodegen.generate(ast, codegenOptions);
if (wrapAsync) {
return `(async ()=>{${output}})()`;
}