move repl web component to new repl package
+ use it in /vanilla + /vanilla/mini
This commit is contained in:
parent
d4afbc63e2
commit
f0c3d38ea7
12 changed files with 204 additions and 164 deletions
3
packages/repl/README.md
Normal file
3
packages/repl/README.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# @strudel/repl
|
||||
|
||||
The Strudel REPL as a web component.
|
||||
1
packages/repl/index.mjs
Normal file
1
packages/repl/index.mjs
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from './repl-component.mjs';
|
||||
49
packages/repl/package.json
Normal file
49
packages/repl/package.json
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
"name": "@strudel/repl",
|
||||
"version": "0.9.0",
|
||||
"description": "Strudel REPL as a Web Component",
|
||||
"main": "index.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 <flix91@gmail.com>",
|
||||
"contributors": [
|
||||
"Alex McLean <alex@slab.org>"
|
||||
],
|
||||
"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/mini": "workspace:*",
|
||||
"@strudel.cycles/tonal": "workspace:*",
|
||||
"@strudel.cycles/transpiler": "workspace:*",
|
||||
"@strudel.cycles/webaudio": "workspace:*",
|
||||
"@strudel/codemirror": "workspace:*",
|
||||
"@strudel/hydra": "workspace:*",
|
||||
"@strudel.cycles/soundfonts": "workspace:*",
|
||||
"@strudel.cycles/midi": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^4.3.3"
|
||||
}
|
||||
}
|
||||
34
packages/repl/prebake.mjs
Normal file
34
packages/repl/prebake.mjs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import { controls, evalScope } from '@strudel.cycles/core';
|
||||
import { registerSoundfonts } from '@strudel.cycles/soundfonts';
|
||||
import { registerSynthSounds, registerZZFXSounds, samples } from '@strudel.cycles/webaudio';
|
||||
|
||||
export async function prebake() {
|
||||
const modulesLoading = evalScope(
|
||||
import('@strudel.cycles/core'),
|
||||
import('@strudel.cycles/mini'),
|
||||
import('@strudel.cycles/tonal'),
|
||||
import('@strudel.cycles/webaudio'),
|
||||
import('@strudel/codemirror'),
|
||||
import('@strudel/hydra'),
|
||||
import('@strudel.cycles/soundfonts'),
|
||||
import('@strudel.cycles/midi'),
|
||||
// import('@strudel.cycles/xen'),
|
||||
// import('@strudel.cycles/serial'),
|
||||
// import('@strudel.cycles/csound'),
|
||||
// import('@strudel.cycles/osc'),
|
||||
controls, // sadly, this cannot be exported from core directly (yet)
|
||||
);
|
||||
// load samples
|
||||
const ds = 'https://raw.githubusercontent.com/felixroos/dough-samples/main/';
|
||||
await Promise.all([
|
||||
modulesLoading,
|
||||
registerSynthSounds(),
|
||||
registerZZFXSounds(),
|
||||
registerSoundfonts(),
|
||||
samples(`${ds}/tidal-drum-machines.json`),
|
||||
samples(`${ds}/piano.json`),
|
||||
samples(`${ds}/Dirt-Samples.json`),
|
||||
samples(`${ds}/EmuSP12.json`),
|
||||
samples(`${ds}/vcsl.json`),
|
||||
]);
|
||||
}
|
||||
98
packages/repl/repl-component.mjs
Normal file
98
packages/repl/repl-component.mjs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
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 './prebake.mjs';
|
||||
|
||||
function camelToKebab(camelCaseString) {
|
||||
return camelCaseString.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
}
|
||||
function kebabToCamel(kebabCaseString) {
|
||||
return kebabCaseString.replace(/-([a-z])/g, function (match, group) {
|
||||
return group.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
const initialSettings = {
|
||||
keybindings: 'strudelTheme',
|
||||
isLineNumbersDisplayed: true,
|
||||
isActiveLineHighlighted: true,
|
||||
isAutoCompletionEnabled: false,
|
||||
isPatternHighlightingEnabled: true,
|
||||
isFlashEnabled: true,
|
||||
isTooltipEnabled: false,
|
||||
isLineWrappingEnabled: false,
|
||||
theme: 'teletext',
|
||||
fontFamily: 'monospace',
|
||||
fontSize: 18,
|
||||
};
|
||||
const settingAttributes = Object.keys(initialSettings).map(camelToKebab);
|
||||
const parseAttribute = (name, value) => {
|
||||
const camel = kebabToCamel(name);
|
||||
const type = typeof initialSettings[camel];
|
||||
// console.log('type', type, name);
|
||||
if (type === 'boolean') {
|
||||
return ['1', 'true'].includes(value);
|
||||
}
|
||||
if (type === 'number') {
|
||||
return Number(value);
|
||||
}
|
||||
return value;
|
||||
};
|
||||
// console.log('attributes', settingAttributes);
|
||||
class StrudelRepl extends HTMLElement {
|
||||
static observedAttributes = ['code', ...settingAttributes];
|
||||
settings = initialSettings;
|
||||
editor = null;
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
onReady(listener) {
|
||||
this.readyListener = listener;
|
||||
}
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
if (name === 'code') {
|
||||
this.code = newValue;
|
||||
this.editor?.setCode(initialCode);
|
||||
} else if (settingAttributes.includes(name)) {
|
||||
const camel = kebabToCamel(name);
|
||||
this.settings[camel] = parseAttribute(name, newValue);
|
||||
// console.log('name', name, newValue, camel, this.settings[camel]);
|
||||
this.editor?.updateSettings(this.settings);
|
||||
}
|
||||
}
|
||||
connectedCallback() {
|
||||
const drawContext = getDrawContext();
|
||||
const drawTime = [-2, 2];
|
||||
this.editor = new StrudelMirror({
|
||||
defaultOutput: webaudioOutput,
|
||||
getTime: () => getAudioContext().currentTime,
|
||||
transpiler,
|
||||
root: this,
|
||||
initialCode: '// LOADING',
|
||||
pattern: silence,
|
||||
settings: this.settings,
|
||||
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,
|
||||
afterEval: ({ code }) => {
|
||||
// window.location.hash = '#' + code2hash(code);
|
||||
},
|
||||
});
|
||||
// init settings
|
||||
this.editor.updateSettings(this.settings);
|
||||
this.editor.setCode(this.code);
|
||||
this.readyListener?.(this);
|
||||
// settingsMap.listen((settings, key) => editor.changeSetting(key, settings[key]));
|
||||
// onEvent('strudel-toggle-play', () => this.editor.toggle());
|
||||
}
|
||||
// Element functionality written in here
|
||||
}
|
||||
|
||||
customElements.define('strudel-editor', StrudelRepl);
|
||||
Loading…
Add table
Add a link
Reference in a new issue