From 3b631cb6af8b10f2dff6ff9a6c7b1aa5e7bc2814 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Sun, 7 May 2023 11:56:35 +0200 Subject: [PATCH] add @strudel/web umbrella package + example --- packages/web/README.md | 35 ++++++++++++++ packages/web/examples/repl-example/.gitignore | 24 ++++++++++ packages/web/examples/repl-example/index.html | 29 ++++++++++++ .../web/examples/repl-example/package.json | 18 ++++++++ packages/web/package.json | 46 +++++++++++++++++++ packages/web/repl.mjs | 38 +++++++++++++++ pnpm-lock.yaml | 35 ++++++++++++++ pnpm-workspace.yaml | 3 +- 8 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 packages/web/README.md create mode 100644 packages/web/examples/repl-example/.gitignore create mode 100644 packages/web/examples/repl-example/index.html create mode 100644 packages/web/examples/repl-example/package.json create mode 100644 packages/web/package.json create mode 100644 packages/web/repl.mjs diff --git a/packages/web/README.md b/packages/web/README.md new file mode 100644 index 00000000..c70a5df7 --- /dev/null +++ b/packages/web/README.md @@ -0,0 +1,35 @@ +# @strudel/web + +This package provides an easy to use bundle of multiple strudel packages for the web. + +## Usage + +```js +import { repl } from '@strudel/web'; + +const strudel = repl(); + +document.getElementById('play').addEventListener('click', + () => strudel.evaluate('note("c a f e").jux(rev)') +); +``` + +Note: Due to the [Autoplay policy](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Best_practices#autoplay_policy), you can only play audio in a browser after a click event. + +### Loading samples + +By default, no external samples are loaded, but you can add them like this: + +```js +import { repl, samples } from '@strudel/web'; + +const strudel = repl({ + prebake: () => samples('github:tidalcycles/Dirt-Samples/master'), +}); + +document.getElementById('play').addEventListener('click', + () => strudel.evaluate('s("bd,jvbass(3,8)").jux(rev)') +); +``` + +You can learn [more about the `samples` function here](https://strudel.tidalcycles.org/learn/samples#loading-custom-samples). diff --git a/packages/web/examples/repl-example/.gitignore b/packages/web/examples/repl-example/.gitignore new file mode 100644 index 00000000..a547bf36 --- /dev/null +++ b/packages/web/examples/repl-example/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/packages/web/examples/repl-example/index.html b/packages/web/examples/repl-example/index.html new file mode 100644 index 00000000..a7954e64 --- /dev/null +++ b/packages/web/examples/repl-example/index.html @@ -0,0 +1,29 @@ + + + + + + + @strudel/web REPL Example + + +
+ + + + + + + diff --git a/packages/web/examples/repl-example/package.json b/packages/web/examples/repl-example/package.json new file mode 100644 index 00000000..42fb8b83 --- /dev/null +++ b/packages/web/examples/repl-example/package.json @@ -0,0 +1,18 @@ +{ + "name": "repl-example", + "private": true, + "version": "0.0.0", + "type": "module", + "license": "AGPL-3.0-or-later", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "vite": "^4.3.2" + }, + "dependencies": { + "@strudel/web": "workspace:*" + } +} diff --git a/packages/web/package.json b/packages/web/package.json new file mode 100644 index 00000000..11e9153e --- /dev/null +++ b/packages/web/package.json @@ -0,0 +1,46 @@ +{ + "name": "@strudel/web", + "version": "0.8.0", + "description": "Easy to setup, opiniated bundle of Strudel for the browser.", + "main": "repl.mjs", + "publishConfig": { + "main": "dist/index.js", + "module": "dist/index.mjs" + }, + "scripts": { + "build": "vite build", + "prepublishOnly": "npm run build" + }, + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/tidalcycles/strudel.git" + }, + "keywords": [ + "tidalcycles", + "strudel", + "pattern", + "livecoding", + "algorave" + ], + "author": "Felix Roos ", + "contributors": [ + "Alex McLean " + ], + "license": "AGPL-3.0-or-later", + "bugs": { + "url": "https://github.com/tidalcycles/strudel/issues" + }, + "homepage": "https://github.com/tidalcycles/strudel#readme", + "dependencies": { + "@strudel.cycles/core": "workspace:*", + "@strudel.cycles/webaudio": "workspace:*", + "@strudel.cycles/soundfonts": "workspace:*", + "@strudel.cycles/mini": "workspace:*", + "@strudel.cycles/tonal": "workspace:*", + "@strudel.cycles/transpiler": "workspace:*" + }, + "devDependencies": { + "vite": "^4.3.3" + } +} diff --git a/packages/web/repl.mjs b/packages/web/repl.mjs new file mode 100644 index 00000000..f86459b1 --- /dev/null +++ b/packages/web/repl.mjs @@ -0,0 +1,38 @@ +export * from '@strudel.cycles/core'; +export * from '@strudel.cycles/webaudio'; +export * from '@strudel.cycles/soundfonts'; +export * from '@strudel.cycles/transpiler'; +export * from '@strudel.cycles/mini'; +export * from '@strudel.cycles/tonal'; +export * from '@strudel.cycles/webaudio'; +import { repl as _repl, evalScope, controls } from '@strudel.cycles/core'; +import { initAudioOnFirstClick, getAudioContext, registerSynthSounds, webaudioOutput } from '@strudel.cycles/webaudio'; +import { registerSoundfonts } from '@strudel.cycles/soundfonts'; +import { transpiler } from '@strudel.cycles/transpiler'; + +async function prebake(userPrebake) { + const loadModules = evalScope( + evalScope, + controls, + import('@strudel.cycles/core'), + import('@strudel.cycles/mini'), + import('@strudel.cycles/tonal'), + import('@strudel.cycles/webaudio'), + ); + await Promise.all([loadModules, registerSynthSounds(), registerSoundfonts(), userPrebake?.()]); +} + +export function repl(options = {}) { + const prebaked = prebake(options?.prebake); + initAudioOnFirstClick(); + return _repl({ + defaultOutput: webaudioOutput, + getTime: () => getAudioContext().currentTime, + transpiler, + ...options, + beforeEval: async (args) => { + options?.beforeEval?.(args); + await prebaked; + }, + }); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 596351fa..ee27ce0d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -471,6 +471,41 @@ importers: specifier: ^0.28.0 version: 0.28.0(@vitest/ui@0.28.0) + packages/web: + dependencies: + '@strudel.cycles/core': + specifier: workspace:* + version: link:../core + '@strudel.cycles/mini': + specifier: workspace:* + version: link:../mini + '@strudel.cycles/soundfonts': + specifier: workspace:* + version: link:../soundfonts + '@strudel.cycles/tonal': + specifier: workspace:* + version: link:../tonal + '@strudel.cycles/transpiler': + specifier: workspace:* + version: link:../transpiler + '@strudel.cycles/webaudio': + specifier: workspace:* + version: link:../webaudio + devDependencies: + vite: + specifier: ^4.3.3 + version: 4.3.3(@types/node@18.16.3) + + packages/web/examples/repl-example: + dependencies: + '@strudel/web': + specifier: workspace:* + version: link:../.. + devDependencies: + vite: + specifier: ^4.3.2 + version: 4.3.3(@types/node@18.16.3) + packages/webaudio: dependencies: '@strudel.cycles/core': diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 4b821d33..984f2447 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,4 +4,5 @@ packages: - "website/" - "packages/core/examples/vite-vanilla-repl" - "packages/core/examples/vite-vanilla-repl-cm6" - - "packages/react/examples/nano-repl" \ No newline at end of file + - "packages/react/examples/nano-repl" + - "packages/web/examples/repl-example"