(time, event) => {
{ line: start.line - 1, ch: start.column },
{ line: end.line - 1, ch: end.column },
//{ css: 'background-color: #FFCA28; color: black' } // background-color is now used by parent marking
- { css: 'outline: 1px solid #FFCA28; box-sizing:border-box' }
+ { css: 'outline: 2px solid #FFCA28; box-sizing:border-box' }
)
);
//Tone.Transport.schedule(() => { // problem: this can be cleared by scheduler...
@@ -51,7 +51,7 @@ export const markParens = (editor, data) => {
const v = editor.getDoc().getValue();
const marked = getCurrentParenArea(v, data);
parenMark?.clear();
- parenMark = editor.getDoc().markText(...marked, { css: 'background-color: #00000020' }); //
+ parenMark = editor.getDoc().markText(...marked, { css: 'background-color: #0000dd20' }); //
};
// returns { line, ch } from absolute character offset
diff --git a/repl/src/evaluate.ts b/repl/src/evaluate.ts
index 546433c1..dc59383f 100644
--- a/repl/src/evaluate.ts
+++ b/repl/src/evaluate.ts
@@ -8,6 +8,7 @@ import './tune.mjs';
import './tune.mjs';
import './pianoroll.mjs';
import './draw.mjs';
+import * as uiHelpers from './ui.mjs';
import * as drawHelpers from './draw.mjs';
import gist from './gist.js';
import shapeshifter from './shapeshifter';
@@ -35,7 +36,7 @@ hackLiteral(String, ['mini', 'm'], bootstrapped.mini); // comment out this line
hackLiteral(String, ['pure', 'p'], bootstrapped.pure); // comment out this line if you panic
// this will add everything to global scope, which is accessed by eval
-Object.assign(globalThis, bootstrapped, Tone, toneHelpers, voicingHelpers, drawHelpers, { gist });
+Object.assign(globalThis, bootstrapped, Tone, toneHelpers, voicingHelpers, drawHelpers, uiHelpers, { gist });
export const evaluate: any = async (code: string) => {
const shapeshifted = shapeshifter(code); // transform syntactically correct js code to semantically usable code
diff --git a/repl/src/ui.mjs b/repl/src/ui.mjs
new file mode 100644
index 00000000..b95dc764
--- /dev/null
+++ b/repl/src/ui.mjs
@@ -0,0 +1,42 @@
+import * as Tone from 'tone';
+
+export const hideHeader = () => {
+ document.getElementById('header').style = 'display:none';
+};
+
+function frame(callback) {
+ if (window.strudelAnimation) {
+ cancelAnimationFrame(window.strudelAnimation);
+ }
+ const animate = (animationTime) => {
+ const toneTime = Tone.getTransport().seconds;
+ callback(animationTime, toneTime);
+ window.strudelAnimation = requestAnimationFrame(animate);
+ };
+ requestAnimationFrame(animate);
+}
+
+export const backgroundImage = function (src, animateOptions) {
+ const container = document.getElementById('code');
+ const bg = 'background-image:url(' + src + ');background-size:contain;';
+ container.style = bg;
+ const { className: initialClassName } = container;
+ const handleOption = (option, value) => {
+ ({
+ style: () => (container.style = bg + ';' + value),
+ className: () => (container.className = value + ' ' + initialClassName),
+ }[option]());
+ };
+ const funcOptions = Object.entries(animateOptions).filter(([_, v]) => typeof v === 'function');
+ const stringOptions = Object.entries(animateOptions).filter(([_, v]) => typeof v === 'string');
+ stringOptions.forEach(([option, value]) => handleOption(option, value));
+
+ if (funcOptions.length === 0) {
+ return;
+ }
+ frame((_, t) =>
+ funcOptions.forEach(([option, value]) => {
+ handleOption(option, value(t));
+ })
+ );
+};