Compare commits

..

3 Commits

Author SHA1 Message Date
Felix Roos c21bc161d6 some osc helper functions 2024-02-18 20:41:06 +01:00
Felix Roos 8d65092c97 update osc readme 2024-02-15 10:00:01 +01:00
Felix Roos b6a9943b5a use es6 import 2024-02-15 09:59:52 +01:00
454 changed files with 34951 additions and 45356 deletions
+24
View File
@@ -0,0 +1,24 @@
krill-parser.js
krill.pegjs
.eslintrc.json
server.js
tidal-sniffer.js
*.jsx
tunejs.js
out/**
postcss.config.js
postcss.config.cjs
tailwind.config.js
tailwind.config.cjs
vite.config.js
/**/dist/**/*
!**/*.mjs
**/*.tsx
**/*.ts
**/*.json
**/dev-dist
**/dist
/src-tauri/target/**/*
reverbGen.mjs
hydra.mjs
jsdoc-synonyms.js
+1 -3
View File
@@ -1,6 +1,5 @@
{ {
"env": { "env": {
"node": true,
"browser": true, "browser": true,
"es2021": true "es2021": true
}, },
@@ -14,6 +13,5 @@
"rules": { "rules": {
"no-unused-vars": ["warn", { "destructuredArrayIgnorePattern": ".", "ignoreRestSiblings": false }], "no-unused-vars": ["warn", { "destructuredArrayIgnorePattern": ".", "ignoreRestSiblings": false }],
"import/no-extraneous-dependencies": ["error", {"devDependencies": true}] "import/no-extraneous-dependencies": ["error", {"devDependencies": true}]
}, }
"files": ["**/*.mjs", "**/*.js"]
} }
+5 -5
View File
@@ -22,10 +22,10 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }} url: ${{ steps.deployment.outputs.page_url }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v2
with: with:
version: 9.12.2 version: 8.11.0
- uses: actions/setup-node@v4 - uses: actions/setup-node@v3
with: with:
node-version: 20 node-version: 20
cache: "pnpm" cache: "pnpm"
@@ -39,11 +39,11 @@ jobs:
uses: actions/configure-pages@v2 uses: actions/configure-pages@v2
- name: Upload artifact - name: Upload artifact
uses: actions/upload-pages-artifact@v3 uses: actions/upload-pages-artifact@v1
with: with:
# Upload entire repository # Upload entire repository
path: "./website/dist" path: "./website/dist"
- name: Deploy to GitHub Pages - name: Deploy to GitHub Pages
id: deployment id: deployment
uses: actions/deploy-pages@v4 uses: actions/deploy-pages@v1
+3 -3
View File
@@ -11,10 +11,10 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v2
with: with:
version: 9.12.2 version: 8.11.0
- uses: actions/setup-node@v4 - uses: actions/setup-node@v3
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
-3
View File
@@ -127,6 +127,3 @@ fabric.properties
.idea/caches/build_file_checksums.ser .idea/caches/build_file_checksums.ser
# END JetBrains -> BEGIN JetBrains # END JetBrains -> BEGIN JetBrains
samples/*
!samples/README.md
-2
View File
@@ -11,5 +11,3 @@ pnpm-lock.yaml
pnpm-workspace.yaml pnpm-workspace.yaml
**/dev-dist **/dev-dist
website/.astro website/.astro
!tidal-drum-machines.json
!tidal-drum-machines-alias.json
+6 -12
View File
@@ -130,26 +130,20 @@ npx lerna version --no-private
# publish all packages inside /packages using pnpm! don't use lerna to publish!! # publish all packages inside /packages using pnpm! don't use lerna to publish!!
pnpm --filter "./packages/**" publish --dry-run pnpm --filter "./packages/**" publish --dry-run
# the last command was only a dry-run. if everything looks ok, run this: # the last command was only a dry-run, make sure everything looks ok, if yes, run the same command without flag
pnpm --filter "./packages/**" publish --access public
``` ```
To manually publish a single package, increase the version in the `package.json`, then run `pnpm publish`. To manually publish a single package, increase the version in the `package.json`, then run `pnpm publish`.
Important: Always publish with `pnpm`, as `npm` does not support overriding main files in `publishConfig`, which is done in all the packages. Important: Always publish with `pnpm`, as `npm` does not support overriding main files in `publishConfig`, which is done in all the packages.
### New Packages
To add a new package, you have to publish it manually the first time, using:
## useful commands
```sh ```sh
#regenerate the test snapshots (ex: when updating or creating new pattern functions) cd packages/<package-name> && pnpm publish --access public
pnpm snapshot
#start the OSC server
pnpm run osc
#build the standalone version
pnpm tauri build
``` ```
## Have Fun ## Have Fun
Remember to have fun, and that this project is driven by the passion of volunteers! Remember to have fun, and that this project is driven by the passion of volunteers!
+14 -14
View File
@@ -1,6 +1,6 @@
# strudel # strudel
[![Strudel test status](https://github.com/tidalcycles/strudel/actions/workflows/test.yml/badge.svg)](https://github.com/tidalcycles/strudel/actions) [![DOI](https://zenodo.org/badge/450927247.svg)](https://doi.org/10.5281/zenodo.6659278) [![Strudel test status](https://github.com/tidalcycles/strudel/actions/workflows/test.yml/badge.svg)](https://github.com/tidalcycles/strudel/actions)
An experiment in making a [Tidal](https://github.com/tidalcycles/tidal/) using web technologies. This software is a bit more stable now, but please continue to tread carefully. An experiment in making a [Tidal](https://github.com/tidalcycles/tidal/) using web technologies. This software is a bit more stable now, but please continue to tread carefully.
@@ -14,26 +14,26 @@ An experiment in making a [Tidal](https://github.com/tidalcycles/tidal/) using w
After cloning the project, you can run the REPL locally: After cloning the project, you can run the REPL locally:
1. Install [Node.js](https://nodejs.org/)
2. Install [pnpm](https://pnpm.io/installation)
3. Install dependencies by running the following command:
```bash ```bash
pnpm i pnpm run setup
``` pnpm run repl
4. Run the development server:
```bash
pnpm dev
``` ```
## Using Strudel In Your Project ## Using Strudel In Your Project
This project is organized into many [packages](./packages), which are also available on [npm](https://www.npmjs.com/search?q=%40strudel). There are multiple npm packages you can use to use strudel, or only parts of it, in your project:
Read more about how to use these in your own project [here](https://strudel.cc/technical-manual/project-start). - [`core`](./packages/core/): tidal pattern engine
- [`mini`](./packages/mini): mini notation parser + core binding
- [`transpiler`](./packages/transpiler): user code transpiler
- [`webaudio`](./packages/webaudio): webaudio output
- [`osc`](./packages/osc): bindings to communicate via OSC
- [`midi`](./packages/midi): webmidi bindings
- [`serial`](./packages/serial): webserial bindings
- [`tonal`](./packages/tonal): tonal functions
- ... [and there are more](./packages/)
You will need to abide by the terms of the [GNU Affero Public Licence v3](LICENSE.md). As such, Strudel code can only be shared within free/open source projects under the same license -- see the license for details. Click on the package names to find out more about each one.
Licensing info for the default sound banks can be found over on the [dough-samples](https://github.com/felixroos/dough-samples/blob/main/README.md) repository.
## Contributing ## Contributing
-22
View File
@@ -1,22 +0,0 @@
import { queryCode, testCycles } from '../test/runtime.mjs';
import * as tunes from '../website/src/repl/tunes.mjs';
import { describe, bench } from 'vitest';
import { calculateSteps } from '../packages/core/index.mjs';
const tuneKeys = Object.keys(tunes);
describe('renders tunes', () => {
tuneKeys.forEach((key) => {
describe(key, () => {
calculateSteps(true);
bench(`+steps`, async () => {
await queryCode(tunes[key], testCycles[key] || 1);
});
calculateSteps(false);
bench(`-steps`, async () => {
await queryCode(tunes[key], testCycles[key] || 1);
});
calculateSteps(true);
});
});
});
-86
View File
@@ -1,86 +0,0 @@
import _import from 'eslint-plugin-import';
import { fixupPluginRules } from '@eslint/compat';
import globals from 'globals';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import js from '@eslint/js';
import { FlatCompat } from '@eslint/eslintrc';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});
export default [
{
ignores: [
'**/krill-parser.js',
'**/krill.pegjs',
'**/.eslintrc.json',
'**/server.js',
'**/tidal-sniffer.js',
'**/*.jsx',
'**/tunejs.js',
'out/**/*',
'**/postcss.config.js',
'**/postcss.config.cjs',
'**/tailwind.config.js',
'**/tailwind.config.cjs',
'**/vite.config.js',
'**/dist/**/*',
'!**/*.mjs',
'**/*.tsx',
'**/*.ts',
'**/*.json',
'**/dev-dist',
'**/dist',
'src-tauri/target/**/*',
'**/reverbGen.mjs',
'**/hydra.mjs',
'**/jsdoc-synonyms.js',
'packages/hs2js/src/hs2js.mjs',
'**/samples',
],
},
...compat.extends('eslint:recommended').map((config) => ({
...config,
files: ['**/*.mjs', '**/*.js'],
})),
{
files: ['**/*.mjs', '**/*.js'],
plugins: {
import: fixupPluginRules(_import),
},
languageOptions: {
globals: {
...globals.node,
...globals.browser,
},
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
'no-unused-vars': [
'warn',
{
destructuredArrayIgnorePattern: '.',
ignoreRestSiblings: false,
},
],
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: true,
},
],
},
},
];
+5 -26
View File
@@ -1,31 +1,10 @@
<!doctype html> <!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<!-- <script src="../../packages/web/dist/index.js"></script> -->
<script src="https://unpkg.com/@strudel/web@1.0.3"></script>
</head>
<body style="background: #222">
<button id="play">play</button> <button id="play">play</button>
<button id="stop">stop</button> <button id="stop">stop</button>
<script> <script type="module">
strudel.initStrudel(); import { initStrudel } from 'https://cdn.skypack.dev/@strudel/web@0.8.2';
document.getElementById('play').addEventListener('click', () =>
evaluate(`
//@title washover @by Switch Angel
//@social https://www.instagram.com/_switch_angel/
n("{0 1 3 5 2 }%16") initStrudel();
.add(n(tri.range(0, 6).slow(3))) document.getElementById('play').addEventListener('click', () => evaluate('note("c a f e").jux(rev)'));
.scale("C4:pentatonic") document.getElementById('play').addEventListener('stop', () => hush());
.sound("sawtooth").att(saw.range(0, 0.05).fast(6))
.release(3).pan(rand).decay(rand.range(0.1, 0.3))
.lpf(tri.range(200, 8000).slow(5)).lpq(0)
.gain(.4).vib(1).vibmod(.1)
.scope({pos:.5})
`),
);
document.getElementById('stop').addEventListener('click', () => strudel.hush());
</script> </script>
</body>
</html>
+3 -11
View File
@@ -1,18 +1,12 @@
<!doctype html> <!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<!-- <script src="../../packages/web/dist/index.js"></script> -->
<script src="https://unpkg.com/@strudel/web@1.0.3"></script>
</head>
<body style="background: #222">
<button id="a">A</button> <button id="a">A</button>
<button id="b">B</button> <button id="b">B</button>
<button id="c">C</button> <button id="c">C</button>
<button id="stop">stop</button> <button id="stop">stop</button>
<script> <script type="module">
import { initStrudel } from 'https://cdn.skypack.dev/@strudel/web@0.8.2';
initStrudel({ initStrudel({
prebake: () => samples('github:tidalcycles/dirt-samples'), prebake: () => samples('github:tidalcycles/Dirt-Samples/master'),
}); });
const click = (id, action) => document.getElementById(id).addEventListener('click', action); const click = (id, action) => document.getElementById(id).addEventListener('click', action);
click('a', () => evaluate(`s('bd,jvbass(3,8)').jux(rev)`)); click('a', () => evaluate(`s('bd,jvbass(3,8)').jux(rev)`));
@@ -20,5 +14,3 @@
click('c', () => s('bd*2,hh(3,4),jvbass:[0 4](5,8,1)').jux(rev).stack(s('~ sd')).play()); click('c', () => s('bd*2,hh(3,4),jvbass:[0 4](5,8,1)').jux(rev).stack(s('~ sd')).play());
click('stop', () => hush()); click('stop', () => hush());
</script> </script>
</body>
</html>
-9
View File
@@ -1,9 +0,0 @@
<script src="https://unpkg.com/hs2js@0.0.4"></script>
<button id="hello">hello</button>
<script>
hs2js.setBase('https://unpkg.com/hs2js@0.0.4/dist/');
hs2js.loadParser();
document.getElementById('hello').addEventListener('click', () => {
hs2js.evaluate('alert "hello from haskell!"');
});
</script>
+2 -3
View File
@@ -16,7 +16,6 @@
</div> </div>
<div id="output"></div> <div id="output"></div>
<script type="module"> <script type="module">
// TODO: refactor to use newer version without controls import
import { controls, repl, evalScope } from 'https://cdn.skypack.dev/@strudel/core@0.11.0'; import { controls, repl, evalScope } from 'https://cdn.skypack.dev/@strudel/core@0.11.0';
import { mini } from 'https://cdn.skypack.dev/@strudel/mini@0.11.0'; import { mini } from 'https://cdn.skypack.dev/@strudel/mini@0.11.0';
import { transpiler } from 'https://cdn.skypack.dev/@strudel/transpiler@0.11.0'; import { transpiler } from 'https://cdn.skypack.dev/@strudel/transpiler@0.11.0';
@@ -53,8 +52,8 @@
}); });
function getTune() { function getTune() {
return `samples('github:tidalcycles/dirt-samples') return `await samples('github:tidalcycles/Dirt-Samples/master')
setcps(1);
stack( stack(
// amen // amen
n("0 1 2 3 4 5 6 7") n("0 1 2 3 4 5 6 7")
-98
View File
@@ -1,98 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>tidal.html</title>
</head>
<body style="margin: 0; padding: 0">
<textarea id="code" style="width: 100%; height: 200px"></textarea>
<pre id="result"></pre>
<script src="https://unpkg.com/hs2js@0.0.8"></script>
<script src="https://unpkg.com/@strudel/web@1.0.3"></script>
<script>
const { initStrudel } = strudel;
const { run, parse, setBase, loadParser } = hs2js;
setBase('https://unpkg.com/hs2js@0.0.4/dist/');
const ready = loadParser();
initStrudel({
prebake: () => samples('github:tidalcycles/dirt-samples'),
});
const textarea = document.getElementById('code');
if (window.location.hash) {
textarea.value = atob(window.location.hash.slice(1));
} else {
textarea.value = 'd1 $ s "jvbass(3,8)"';
}
textarea.addEventListener('input', (e) => {
window.location.hash = btoa(e.target.value);
update();
});
update();
function getInfixOperators() {
let operators = {
'>': 'set',
'#': 'set',
'+': 'add',
'-': 'sub',
'*': 'mul',
'/': 'div',
};
let alignments = {
in: (s) => '|' + s,
out: (s) => s + '|',
mix: (s) => '|' + s + '|',
};
let ops = {};
Object.entries(operators).forEach(([o, name]) => {
// operator without alignment
ops[o] = (l, r) => reify(l)[name](reify(r));
Object.entries(alignments).forEach(([a, getSymbol]) => {
// get symbol with alignment
let symbol = getSymbol(o);
ops[symbol] = (l, r) => reify(l)[name][a](reify(r));
});
});
ops['~>'] = (l, r) => reify(l).late(reify(r));
ops['<~'] = (l, r) => reify(l).early(reify(r));
ops['<$>'] = (l, r) => reify(r).fmap(l).outerJoin(); // is this right?
return ops;
}
const ops = getInfixOperators();
async function update() {
let result, tree;
await ready;
try {
tree = parse(textarea.value);
} catch (err) {
console.warn('parse error');
console.error(err);
}
console.log('parsed tree');
console.log(tree.rootNode.toString());
try {
let patterns = {};
window.p = (name, pattern) => {
patterns[name] = pattern;
};
window.d1 = (pat) => window.p(1, pat);
window.d2 = (pat) => window.p(2, pat);
window.d3 = (pat) => window.p(3, pat);
window.rot = late;
result = run(tree.rootNode, window, ops);
if (Object.values(patterns).length) {
stack(...Object.values(patterns)).play();
}
} catch (err) {
console.warn('eval error');
console.error(err);
result = 'ERROR: ' + err.message;
}
document.getElementById('result').innerHTML = 'Result: ' + result;
}
</script>
</body>
</html>
@@ -1,4 +1,4 @@
<script src="https://unpkg.com/@strudel/repl@1.0.2"></script> <script src="https://unpkg.com/@strudel/repl@0.9.4"></script>
<strudel-editor> <strudel-editor>
<!-- <!--
// @date 23-08-15 // @date 23-08-15
-8
View File
@@ -1,8 +0,0 @@
<script src="https://unpkg.com/@strudel/web@1.0.3"></script>
<button id="play">PLAY</button>
<script>
initStrudel({
prebake: () => samples('github:tidalcycles/dirt-samples'),
});
document.getElementById('play').addEventListener('click', () => s('bd sd').play());
</script>
+2 -3
View File
@@ -1,7 +1,6 @@
import { StrudelMirror } from '@strudel/codemirror'; import { StrudelMirror } from '@strudel/codemirror';
import { funk42 } from './tunes'; import { funk42 } from './tunes';
import { evalScope } from '@strudel/core'; import { drawPianoroll, evalScope, controls } from '@strudel/core';
import { drawPianoroll } from '@strudel/draw';
import './style.css'; import './style.css';
import { initAudioOnFirstClick } from '@strudel/webaudio'; import { initAudioOnFirstClick } from '@strudel/webaudio';
import { transpiler } from '@strudel/transpiler'; import { transpiler } from '@strudel/transpiler';
@@ -26,8 +25,8 @@ const editor = new StrudelMirror({
prebake: async () => { prebake: async () => {
initAudioOnFirstClick(); // needed to make the browser happy (don't await this here..) initAudioOnFirstClick(); // needed to make the browser happy (don't await this here..)
const loadModules = evalScope( const loadModules = evalScope(
controls,
import('@strudel/core'), import('@strudel/core'),
import('@strudel/draw'),
import('@strudel/mini'), import('@strudel/mini'),
import('@strudel/tonal'), import('@strudel/tonal'),
import('@strudel/webaudio'), import('@strudel/webaudio'),
+1 -2
View File
@@ -9,12 +9,11 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"devDependencies": { "devDependencies": {
"vite": "^6.0.11" "vite": "^5.0.10"
}, },
"dependencies": { "dependencies": {
"@strudel/codemirror": "workspace:*", "@strudel/codemirror": "workspace:*",
"@strudel/core": "workspace:*", "@strudel/core": "workspace:*",
"@strudel/draw": "workspace:*",
"@strudel/mini": "workspace:*", "@strudel/mini": "workspace:*",
"@strudel/soundfonts": "workspace:*", "@strudel/soundfonts": "workspace:*",
"@strudel/tonal": "workspace:*", "@strudel/tonal": "workspace:*",
+6 -6
View File
@@ -1,6 +1,6 @@
export const bumpStreet = `// froos - "22 bump street", licensed with CC BY-NC-SA 4.0 export const bumpStreet = `// froos - "22 bump street", licensed with CC BY-NC-SA 4.0
samples('github:felixroos/samples') await samples('github:felixroos/samples/main')
samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/') await samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/')
"<[0,<6 7 9>,13,<17 20 22 26>]!2>/2" "<[0,<6 7 9>,13,<17 20 22 26>]!2>/2"
// make it 22 edo // make it 22 edo
@@ -33,8 +33,8 @@ samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-dru
export const trafficFlam = `// froos - "traffic flam", licensed with CC BY-NC-SA 4.0 export const trafficFlam = `// froos - "traffic flam", licensed with CC BY-NC-SA 4.0
samples('github:felixroos/samples') await samples('github:felixroos/samples/main')
samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/') await samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/')
addVoicings('hip', { addVoicings('hip', {
m11: ['2M 3m 4P 7m'], m11: ['2M 3m 4P 7m'],
@@ -69,8 +69,8 @@ export const funk42 = `// froos - how to funk in 42 lines of code
// adapted from "how to funk in two minutes" by marc rebillet https://www.youtube.com/watch?v=3vBwRfQbXkg // adapted from "how to funk in two minutes" by marc rebillet https://www.youtube.com/watch?v=3vBwRfQbXkg
// thanks to peach for the transcription: https://www.youtube.com/watch?v=8eiPXvIgda4 // thanks to peach for the transcription: https://www.youtube.com/watch?v=8eiPXvIgda4
samples('github:felixroos/samples') await samples('github:felixroos/samples/main')
samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/') await samples('https://strudel.cc/tidal-drum-machines.json', 'github:ritchse/tidal-drum-machines/main/machines/')
setcps(.5) setcps(.5)
+1 -1
View File
@@ -15,7 +15,7 @@
<script type="module"> <script type="module">
import { initStrudel } from '@strudel/web'; import { initStrudel } from '@strudel/web';
initStrudel({ initStrudel({
prebake: () => samples('github:tidalcycles/dirt-samples'), prebake: () => samples('github:tidalcycles/Dirt-Samples/master'),
}); });
const click = (id, action) => document.getElementById(id).addEventListener('click', action); const click = (id, action) => document.getElementById(id).addEventListener('click', action);
+1 -1
View File
@@ -10,7 +10,7 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"devDependencies": { "devDependencies": {
"vite": "^6.0.11" "vite": "^5.0.10"
}, },
"dependencies": { "dependencies": {
"@strudel/web": "workspace:*" "@strudel/web": "workspace:*"
+9 -4
View File
@@ -1,5 +1,5 @@
import { repl, evalScope } from '@strudel/core'; import { controls, repl, evalScope } from '@strudel/core';
import { getAudioContext, webaudioOutput, initAudioOnFirstClick, registerSynthSounds } from '@strudel/webaudio'; import { getAudioContext, webaudioOutput, initAudioOnFirstClick } from '@strudel/webaudio';
import { transpiler } from '@strudel/transpiler'; import { transpiler } from '@strudel/transpiler';
import tune from './tune.mjs'; import tune from './tune.mjs';
@@ -7,9 +7,14 @@ const ctx = getAudioContext();
const input = document.getElementById('text'); const input = document.getElementById('text');
input.innerHTML = tune; input.innerHTML = tune;
initAudioOnFirstClick(); initAudioOnFirstClick();
registerSynthSounds();
evalScope(import('@strudel/core'), import('@strudel/mini'), import('@strudel/webaudio'), import('@strudel/tonal')); evalScope(
controls,
import('@strudel/core'),
import('@strudel/mini'),
import('@strudel/webaudio'),
import('@strudel/tonal'),
);
const { evaluate } = repl({ const { evaluate } = repl({
defaultOutput: webaudioOutput, defaultOutput: webaudioOutput,
+1 -1
View File
@@ -10,7 +10,7 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"devDependencies": { "devDependencies": {
"vite": "^6.0.11" "vite": "^5.0.10"
}, },
"dependencies": { "dependencies": {
"@strudel/core": "workspace:*", "@strudel/core": "workspace:*",
+2 -2
View File
@@ -1,5 +1,5 @@
export default `samples('github:tidalcycles/dirt-samples') export default `await samples('github:tidalcycles/Dirt-Samples/master')
setcps(1)
stack( stack(
// amen // amen
n("0 1 2 3 4 5 6 7") n("0 1 2 3 4 5 6 7")
+1 -1
View File
@@ -12,7 +12,7 @@
const init = Promise.all([ const init = Promise.all([
initAudioOnFirstClick(), initAudioOnFirstClick(),
samples('github:tidalcycles/dirt-samples'), samples('github:tidalcycles/Dirt-Samples/master'),
registerSynthSounds(), registerSynthSounds(),
]); ]);
+1 -1
View File
@@ -12,6 +12,6 @@
"superdough": "workspace:*" "superdough": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"vite": "^6.0.11" "vite": "^5.0.10"
} }
} }
-27
View File
@@ -1,27 +0,0 @@
# 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?
public/tree-sitter.wasm
public/tree-sitter-haskell.wasm
-10
View File
@@ -1,10 +0,0 @@
# @strudel/tidal
This is an experiment in implementing tree-sitter for parsing haskell.
```sh
pnpm i
cd haskell
pnpm copy-wasm
pnpm dev
```
-32
View File
@@ -1,32 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tree sitter test</title>
<style>
body {
background-color: #121213;
color: white;
}
textarea {
padding: 10px;
color: white;
background-color: transparent;
outline: none;
}
a {
color: white;
}
</style>
</head>
<body style="margin: 0; padding: 0">
<textarea id="code" style="width: 100%; height: 200px"></textarea>
<pre id="result"></pre>
<script
type="module"
src="/main.js
"
></script>
</body>
</html>
-83
View File
@@ -1,83 +0,0 @@
import { run, parse, loadParser } from 'hs2js';
import { initStrudel, reify, late, samples, stack } from '@strudel/web';
initStrudel({
prebake: () => samples('github:tidalcycles/dirt-samples'),
});
const ready = loadParser();
const textarea = document.getElementById('code');
if (window.location.hash) {
textarea.value = atob(window.location.hash.slice(1));
} else {
textarea.value = 'd1 $ s "jvbass(3,8)"';
}
textarea.addEventListener('input', (e) => {
window.location.hash = btoa(e.target.value);
update();
});
update();
function getInfixOperators() {
let operators = {
'>': 'set',
'#': 'set',
'+': 'add',
'-': 'sub',
'*': 'mul',
'/': 'div',
};
let alignments = {
in: (s) => '|' + s,
out: (s) => s + '|',
mix: (s) => '|' + s + '|',
};
let ops = {};
Object.entries(operators).forEach(([o, name]) => {
// operator without alignment
ops[o] = (l, r) => reify(l)[name](reify(r));
Object.entries(alignments).forEach(([a, getSymbol]) => {
// get symbol with alignment
let symbol = getSymbol(o);
ops[symbol] = (l, r) => reify(l)[name][a](reify(r));
});
});
ops['~>'] = (l, r) => reify(l).late(reify(r));
ops['<~'] = (l, r) => reify(l).early(reify(r));
ops['<$>'] = (l, r) => reify(r).fmap(l).outerJoin(); // is this right?
return ops;
}
const ops = getInfixOperators();
async function update() {
let result, tree;
await ready;
try {
tree = parse(textarea.value);
} catch (err) {
console.warn('parse error');
console.error(err);
}
console.log('parsed tree');
console.log(tree.rootNode.toString());
try {
let patterns = {};
window.p = (name, pattern) => {
patterns[name] = pattern;
};
window.d1 = (pat) => window.p(1, pat);
window.d2 = (pat) => window.p(2, pat);
window.d3 = (pat) => window.p(3, pat);
window.rot = late;
result = run(tree.rootNode, window, ops);
if (Object.values(patterns).length) {
stack(...Object.values(patterns)).play();
}
} catch (err) {
console.warn('eval error');
console.error(err);
result = 'ERROR: ' + err.message;
}
document.getElementById('result').innerHTML = 'Result: ' + result;
}
-36
View File
@@ -1,36 +0,0 @@
{
"name": "tidal-repl",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite",
"build": "pnpm copy-wasm && vite build",
"preview": "vite preview",
"copy-wasm": "cp node_modules/hs2js/dist/tree-sitter.wasm public && cp node_modules/hs2js/dist/tree-sitter-haskell.wasm public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tidalcycles/strudel.git"
},
"keywords": [
"titdalcycles",
"strudel",
"pattern",
"livecoding",
"algorave"
],
"author": "Felix Roos <flix91@gmail.com>",
"license": "AGPL-3.0-or-later",
"bugs": {
"url": "https://github.com/tidalcycles/strudel/issues"
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel/web": "workspace:*",
"hs2js": "workspace:*"
},
"devDependencies": {
"vite": "^6.0.11"
}
}
-3
View File
@@ -1,3 +0,0 @@
# public
this file is just here to make sure the public folder exists
+2 -7
View File
@@ -1,20 +1,15 @@
// this barrel export is currently only used to find undocumented exports // this barrel export is currently only used to find undocumented exports
export * from './packages/codemirror/index.mjs';
export * from './packages/core/index.mjs'; export * from './packages/core/index.mjs';
export * from './packages/csound/index.mjs'; export * from './packages/csound/index.mjs';
export * from './packages/desktopbridge/index.mjs';
export * from './packages/draw/index.mjs';
export * from './packages/embed/index.mjs'; export * from './packages/embed/index.mjs';
export * from './packages/hydra/index.mjs'; export * from './packages/desktopbridge/index.mjs';
export * from './packages/midi/index.mjs'; export * from './packages/midi/index.mjs';
export * from './packages/mini/index.mjs'; export * from './packages/mini/index.mjs';
export * from './packages/osc/index.mjs'; export * from './packages/osc/index.mjs';
export * from './packages/repl/index.mjs'; export * from './packages/react/index.mjs';
export * from './packages/serial/index.mjs'; export * from './packages/serial/index.mjs';
export * from './packages/soundfonts/index.mjs'; export * from './packages/soundfonts/index.mjs';
export * from './packages/superdough/index.mjs';
export * from './packages/tonal/index.mjs'; export * from './packages/tonal/index.mjs';
export * from './packages/transpiler/index.mjs'; export * from './packages/transpiler/index.mjs';
export * from './packages/web/index.mjs';
export * from './packages/webaudio/index.mjs'; export * from './packages/webaudio/index.mjs';
export * from './packages/xen/index.mjs'; export * from './packages/xen/index.mjs';
+13 -18
View File
@@ -11,7 +11,6 @@
"test": "npm run pretest && vitest run --version", "test": "npm run pretest && vitest run --version",
"test-ui": "npm run pretest && vitest --ui", "test-ui": "npm run pretest && vitest --ui",
"test-coverage": "npm run pretest && vitest --coverage", "test-coverage": "npm run pretest && vitest --coverage",
"bench": "npm run pretest && vitest bench",
"snapshot": "npm run pretest && vitest run -u --silent", "snapshot": "npm run pretest && vitest run -u --silent",
"repl": "npm run prestart && cd website && npm run dev", "repl": "npm run prestart && cd website && npm run dev",
"start": "npm run prestart && cd website && npm run dev", "start": "npm run prestart && cd website && npm run dev",
@@ -21,12 +20,11 @@
"osc": "cd packages/osc && npm run server", "osc": "cd packages/osc && npm run server",
"jsdoc": "jsdoc packages/ -c jsdoc/jsdoc.config.json", "jsdoc": "jsdoc packages/ -c jsdoc/jsdoc.config.json",
"jsdoc-json": "jsdoc packages/ --template ./node_modules/jsdoc-json --destination doc.json -c jsdoc/jsdoc.config.json", "jsdoc-json": "jsdoc packages/ --template ./node_modules/jsdoc-json --destination doc.json -c jsdoc/jsdoc.config.json",
"lint": "eslint . --quiet", "lint": "eslint . --ext mjs,js --quiet",
"codeformat": "prettier --write .", "codeformat": "prettier --write .",
"format-check": "prettier --check .", "format-check": "prettier --check .",
"report-undocumented": "npm run jsdoc-json && node jsdoc/undocumented.mjs > undocumented.json", "report-undocumented": "npm run jsdoc-json && node jsdoc/undocumented.mjs > undocumented.json",
"check": "npm run format-check && npm run lint && npm run test", "check": "npm run format-check && npm run lint && npm run test",
"sampler": "cd samples && node ../packages/sampler/sample-server.mjs",
"iclc": "cd paper && pandoc --template=pandoc/iclc.html --citeproc --number-sections iclc2023.md -o iclc2023.html && pandoc --template=pandoc/iclc.latex --citeproc --number-sections iclc2023.md -o iclc2023.pdf" "iclc": "cd paper && pandoc --template=pandoc/iclc.html --citeproc --number-sections iclc2023.md -o iclc2023.html && pandoc --template=pandoc/iclc.latex --citeproc --number-sections iclc2023.md -o iclc2023.pdf"
}, },
"repository": { "repository": {
@@ -55,22 +53,19 @@
"@strudel/xen": "workspace:*" "@strudel/xen": "workspace:*"
}, },
"devDependencies": { "devDependencies": {
"@eslint/compat": "^1.2.5", "dependency-tree": "^10.0.9",
"@eslint/eslintrc": "^3.2.0", "@tauri-apps/cli": "^1.5.9",
"@eslint/js": "^9.19.0", "@vitest/ui": "^1.1.0",
"@tauri-apps/cli": "^2.2.7", "canvas": "^2.11.2",
"@vitest/coverage-v8": "3.0.4", "eslint": "^8.56.0",
"@vitest/ui": "^3.0.4", "eslint-plugin-import": "^2.29.1",
"acorn": "^8.14.0",
"dependency-tree": "^11.0.1",
"eslint": "^9.19.0",
"eslint-plugin-import": "^2.31.0",
"events": "^3.3.0", "events": "^3.3.0",
"globals": "^15.14.0", "jsdoc": "^4.0.2",
"jsdoc": "^4.0.4",
"jsdoc-json": "^2.0.2", "jsdoc-json": "^2.0.2",
"lerna": "^8.1.9", "jsdoc-to-markdown": "^8.0.0",
"prettier": "^3.4.2", "lerna": "^8.0.1",
"vitest": "^3.0.4" "prettier": "^3.1.1",
"rollup-plugin-visualizer": "^5.12.0",
"vitest": "^1.1.0"
} }
} }
+35 -66
View File
@@ -1,9 +1,8 @@
import { closeBrackets } from '@codemirror/autocomplete'; import { closeBrackets } from '@codemirror/autocomplete';
export { toggleComment, toggleBlockComment, toggleLineComment, toggleBlockCommentByLine } from '@codemirror/commands';
// import { search, highlightSelectionMatches } from '@codemirror/search'; // import { search, highlightSelectionMatches } from '@codemirror/search';
import { history } from '@codemirror/commands'; import { history } from '@codemirror/commands';
import { javascript } from '@codemirror/lang-javascript'; import { javascript } from '@codemirror/lang-javascript';
import { defaultHighlightStyle, syntaxHighlighting, bracketMatching } from '@codemirror/language'; import { defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language';
import { Compartment, EditorState, Prec } from '@codemirror/state'; import { Compartment, EditorState, Prec } from '@codemirror/state';
import { import {
EditorView, EditorView,
@@ -13,22 +12,18 @@ import {
lineNumbers, lineNumbers,
drawSelection, drawSelection,
} from '@codemirror/view'; } from '@codemirror/view';
import { repl, registerControl } from '@strudel/core'; import { Pattern, Drawer, repl, cleanupDraw } from '@strudel/core';
import { Drawer, cleanupDraw } from '@strudel/draw';
import { isAutoCompletionEnabled } from './autocomplete.mjs'; import { isAutoCompletionEnabled } from './autocomplete.mjs';
import { isTooltipEnabled } from './tooltip.mjs'; import { isTooltipEnabled } from './tooltip.mjs';
import { flash, isFlashEnabled } from './flash.mjs'; import { flash, isFlashEnabled } from './flash.mjs';
import { highlightMiniLocations, isPatternHighlightingEnabled, updateMiniLocations } from './highlight.mjs'; import { highlightMiniLocations, isPatternHighlightingEnabled, updateMiniLocations } from './highlight.mjs';
import { keybindings } from './keybindings.mjs'; import { keybindings } from './keybindings.mjs';
import { initTheme, activateTheme, theme } from './themes.mjs'; import { initTheme, activateTheme, theme } from './themes.mjs';
import { sliderPlugin, updateSliderWidgets } from './slider.mjs'; import { updateWidgets, sliderPlugin } from './slider.mjs';
import { widgetPlugin, updateWidgets } from './widget.mjs';
import { persistentAtom } from '@nanostores/persistent'; import { persistentAtom } from '@nanostores/persistent';
const extensions = { const extensions = {
isLineWrappingEnabled: (on) => (on ? EditorView.lineWrapping : []), isLineWrappingEnabled: (on) => (on ? EditorView.lineWrapping : []),
isBracketMatchingEnabled: (on) => (on ? bracketMatching({ brackets: '()[]{}<>' }) : []),
isBracketClosingEnabled: (on) => (on ? closeBrackets() : []),
isLineNumbersDisplayed: (on) => (on ? lineNumbers() : []), isLineNumbersDisplayed: (on) => (on ? lineNumbers() : []),
theme, theme,
isAutoCompletionEnabled, isAutoCompletionEnabled,
@@ -42,8 +37,6 @@ const compartments = Object.fromEntries(Object.keys(extensions).map((key) => [ke
export const defaultSettings = { export const defaultSettings = {
keybindings: 'codemirror', keybindings: 'codemirror',
isBracketMatchingEnabled: false,
isBracketClosingEnabled: true,
isLineNumbersDisplayed: true, isLineNumbersDisplayed: true,
isActiveLineHighlighted: false, isActiveLineHighlighted: false,
isAutoCompletionEnabled: false, isAutoCompletionEnabled: false,
@@ -67,7 +60,6 @@ export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, roo
const initialSettings = Object.keys(compartments).map((key) => const initialSettings = Object.keys(compartments).map((key) =>
compartments[key].of(extensions[key](parseBooleans(settings[key]))), compartments[key].of(extensions[key](parseBooleans(settings[key]))),
); );
initTheme(settings.theme); initTheme(settings.theme);
let state = EditorState.create({ let state = EditorState.create({
doc: initialCode, doc: initialCode,
@@ -77,9 +69,9 @@ export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, roo
...initialSettings, ...initialSettings,
javascript(), javascript(),
sliderPlugin, sliderPlugin,
widgetPlugin,
// indentOnInput(), // works without. already brought with javascript extension? // indentOnInput(), // works without. already brought with javascript extension?
// bracketMatching(), // does not do anything // bracketMatching(), // does not do anything
closeBrackets(),
syntaxHighlighting(defaultHighlightStyle), syntaxHighlighting(defaultHighlightStyle),
history(), history(),
EditorView.updateListener.of((v) => onChange(v)), EditorView.updateListener.of((v) => onChange(v)),
@@ -100,8 +92,10 @@ export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, roo
}, },
{ {
key: 'Alt-.', key: 'Alt-.',
preventDefault: true, run: (_, e) => {
run: () => onStop?.(), e.preventDefault();
onStop?.();
},
}, },
/* { /* {
key: 'Ctrl-Shift-.', key: 'Ctrl-Shift-.',
@@ -129,55 +123,60 @@ export class StrudelMirror {
id, id,
initialCode = '', initialCode = '',
onDraw, onDraw,
drawContext,
drawTime = [0, 0], drawTime = [0, 0],
autodraw, autodraw,
prebake, prebake,
bgFill = true, bgFill = true,
solo = true,
...replOptions ...replOptions
} = options; } = options;
this.code = initialCode; this.code = initialCode;
this.root = root; this.root = root;
this.miniLocations = []; this.miniLocations = [];
this.widgets = []; this.widgets = [];
this.painters = [];
this.drawTime = drawTime; this.drawTime = drawTime;
this.drawContext = drawContext; this.onDraw = onDraw;
this.onDraw = onDraw || this.draw; const self = this;
this.id = id || s4(); this.id = id || s4();
this.solo = solo;
this.drawer = new Drawer((haps, time, _, painters) => { this.drawer = new Drawer((haps, time) => {
const currentFrame = haps.filter((hap) => hap.isActive(time)); const currentFrame = haps.filter((hap) => time >= hap.whole.begin && time <= hap.endClipped);
this.highlight(currentFrame, time); this.highlight(currentFrame, time);
this.onDraw(haps, time, painters); this.onDraw?.(haps, time, currentFrame, this.painters);
}, drawTime); }, drawTime);
// this approach does not work with multiple repls on screen
// TODO: refactor onPaint usages + find fix, maybe remove painters here?
Pattern.prototype.onPaint = function (onPaint) {
self.painters.push(onPaint);
return this;
};
this.prebaked = prebake(); this.prebaked = prebake();
autodraw && this.drawFirstFrame(); autodraw && this.drawFirstFrame();
this.repl = repl({ this.repl = repl({
...replOptions, ...replOptions,
id,
onToggle: (started) => { onToggle: (started) => {
replOptions?.onToggle?.(started); replOptions?.onToggle?.(started);
if (started) { if (started) {
this.adjustDrawTime();
this.drawer.start(this.repl.scheduler); this.drawer.start(this.repl.scheduler);
if (this.solo) {
// stop other repls when this one is started // stop other repls when this one is started
document.dispatchEvent( document.dispatchEvent(
new CustomEvent('start-repl', { new CustomEvent('start-repl', {
detail: this.id, detail: this.id,
}), }),
); );
}
} else { } else {
this.drawer.stop(); this.drawer.stop();
updateMiniLocations(this.editor, []); updateMiniLocations(this.editor, []);
cleanupDraw(true, id); cleanupDraw(false);
} }
}, },
beforeEval: async () => { beforeEval: async () => {
cleanupDraw(true, id); cleanupDraw();
this.painters = [];
await this.prebaked; await this.prebaked;
await replOptions?.beforeEval?.(); await replOptions?.beforeEval?.();
}, },
@@ -185,17 +184,11 @@ export class StrudelMirror {
// remember for when highlighting is toggled on // remember for when highlighting is toggled on
this.miniLocations = options.meta?.miniLocations; this.miniLocations = options.meta?.miniLocations;
this.widgets = options.meta?.widgets; this.widgets = options.meta?.widgets;
const sliders = this.widgets.filter((w) => w.type === 'slider'); updateWidgets(this.editor, this.widgets);
updateSliderWidgets(this.editor, sliders);
const widgets = this.widgets.filter((w) => w.type !== 'slider');
updateWidgets(this.editor, widgets);
updateMiniLocations(this.editor, this.miniLocations); updateMiniLocations(this.editor, this.miniLocations);
replOptions?.afterEval?.(options); replOptions?.afterEval?.(options);
// if no painters are set (.onPaint was not called), then we only need the present moment (for highlighting) this.adjustDrawTime();
const drawTime = options.pattern.getPainters().length ? this.drawTime : [0, 0]; this.drawer.invalidate();
this.drawer.setDrawTime(drawTime);
// invalidate drawer after we've set the appropriate drawTime
this.drawer.invalidate(this.repl.scheduler);
}, },
}); });
this.editor = initEditor({ this.editor = initEditor({
@@ -224,14 +217,16 @@ export class StrudelMirror {
// stop this repl when another repl is started // stop this repl when another repl is started
this.onStartRepl = (e) => { this.onStartRepl = (e) => {
if (this.solo && e.detail !== this.id) { if (e.detail !== this.id) {
this.stop(); this.stop();
} }
}; };
document.addEventListener('start-repl', this.onStartRepl); document.addEventListener('start-repl', this.onStartRepl);
} }
draw(haps, time, painters) { // adjusts draw time depending on if there are painters
painters?.forEach((painter) => painter(this.drawContext, time, haps, this.drawTime)); adjustDrawTime() {
// when no painters are set, [0,0] is enough (just highlighting)
this.drawer.setDrawTime(this.painters.length ? this.drawTime : [0, 0]);
} }
async drawFirstFrame() { async drawFirstFrame() {
if (!this.onDraw) { if (!this.onDraw) {
@@ -243,7 +238,7 @@ export class StrudelMirror {
await this.repl.evaluate(this.code, false); await this.repl.evaluate(this.code, false);
this.drawer.invalidate(this.repl.scheduler, -0.001); this.drawer.invalidate(this.repl.scheduler, -0.001);
// draw at -0.001 to avoid haps at 0 to be visualized as active // draw at -0.001 to avoid haps at 0 to be visualized as active
this.onDraw?.(this.drawer.visibleHaps, -0.001, this.drawer.painters); this.onDraw?.(this.drawer.visibleHaps, -0.001, [], this.painters);
} catch (err) { } catch (err) {
console.warn('first frame could not be painted'); console.warn('first frame could not be painted');
} }
@@ -295,15 +290,9 @@ export class StrudelMirror {
setLineWrappingEnabled(enabled) { setLineWrappingEnabled(enabled) {
this.reconfigureExtension('isLineWrappingEnabled', enabled); this.reconfigureExtension('isLineWrappingEnabled', enabled);
} }
setBracketMatchingEnabled(enabled) {
this.reconfigureExtension('isBracketMatchingEnabled', enabled);
}
setLineNumbersDisplayed(enabled) { setLineNumbersDisplayed(enabled) {
this.reconfigureExtension('isLineNumbersDisplayed', enabled); this.reconfigureExtension('isLineNumbersDisplayed', enabled);
} }
setBracketClosingEnabled(enabled) {
this.reconfigureExtension('isBracketClosingEnabled', enabled);
}
setTheme(theme) { setTheme(theme) {
this.reconfigureExtension('theme', theme); this.reconfigureExtension('theme', theme);
} }
@@ -336,17 +325,6 @@ export class StrudelMirror {
clear() { clear() {
this.onStartRepl && document.removeEventListener('start-repl', this.onStartRepl); this.onStartRepl && document.removeEventListener('start-repl', this.onStartRepl);
} }
getCursorLocation() {
return this.editor.state.selection.main.head;
}
setCursorLocation(col) {
return this.editor.dispatch({ selection: { anchor: col } });
}
appendCode(code) {
const cursor = this.getCursorLocation();
this.setCode(this.code + code);
this.setCursorLocation(cursor);
}
} }
function parseBooleans(value) { function parseBooleans(value) {
@@ -359,12 +337,3 @@ function s4() {
.toString(16) .toString(16)
.substring(1); .substring(1);
} }
/**
* Overrides the css of highlighted events. Make sure to use single quotes!
* @name markcss
* @example
* note("c a f e")
* .markcss('text-decoration:underline')
*/
export const markcss = registerControl('markcss');
+1 -3
View File
@@ -11,9 +11,7 @@ export const flashField = StateField.define({
for (let e of tr.effects) { for (let e of tr.effects) {
if (e.is(setFlash)) { if (e.is(setFlash)) {
if (e.value && tr.newDoc.length > 0) { if (e.value && tr.newDoc.length > 0) {
const mark = Decoration.mark({ const mark = Decoration.mark({ attributes: { style: `background-color: #FFCA2880` } });
attributes: { style: `background-color: rgba(255,255,255, .4); filter: invert(10%)` },
});
flash = Decoration.set([mark.range(0, tr.newDoc.length)]); flash = Decoration.set([mark.range(0, tr.newDoc.length)]);
} else { } else {
flash = Decoration.set([]); flash = Decoration.set([]);
+2 -3
View File
@@ -92,8 +92,7 @@ const miniLocationHighlights = EditorView.decorations.compute([miniLocations, vi
if (haps.has(id)) { if (haps.has(id)) {
const hap = haps.get(id); const hap = haps.get(id);
const color = hap.value?.color ?? 'var(--foreground)'; const color = hap.context.color ?? 'var(--foreground)';
const style = hap.value?.markcss || `outline: solid 2px ${color}`;
// Get explicit channels for color values // Get explicit channels for color values
/* /*
const swatch = document.createElement('div'); const swatch = document.createElement('div');
@@ -115,7 +114,7 @@ const miniLocationHighlights = EditorView.decorations.compute([miniLocations, vi
to, to,
Decoration.mark({ Decoration.mark({
// attributes: { style: `outline: solid 2px rgba(${channels.join(', ')})` }, // attributes: { style: `outline: solid 2px rgba(${channels.join(', ')})` },
attributes: { style }, attributes: { style: `outline: solid 2px ${color}` },
}), }),
); );
} }
-1
View File
@@ -3,4 +3,3 @@ export * from './highlight.mjs';
export * from './flash.mjs'; export * from './flash.mjs';
export * from './slider.mjs'; export * from './slider.mjs';
export * from './themes.mjs'; export * from './themes.mjs';
export * from './widget.mjs';
+16 -16
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel/codemirror", "name": "@strudel/codemirror",
"version": "1.2.0", "version": "1.0.1",
"description": "Codemirror Extensions for Strudel", "description": "Codemirror Extensions for Strudel",
"main": "index.mjs", "main": "index.mjs",
"publishConfig": { "publishConfig": {
@@ -32,24 +32,24 @@
}, },
"homepage": "https://github.com/tidalcycles/strudel#readme", "homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": { "dependencies": {
"@codemirror/autocomplete": "^6.18.4", "@codemirror/autocomplete": "^6.11.1",
"@codemirror/commands": "^6.8.0", "@codemirror/commands": "^6.3.3",
"@codemirror/lang-javascript": "^6.2.2", "@codemirror/lang-javascript": "^6.2.1",
"@codemirror/language": "^6.10.8", "@codemirror/language": "^6.10.0",
"@codemirror/search": "^6.5.8", "@codemirror/search": "^6.5.5",
"@codemirror/state": "^6.5.1", "@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.36.2", "@codemirror/view": "^6.23.0",
"@lezer/highlight": "^1.2.1", "@lezer/highlight": "^1.2.0",
"@nanostores/persistent": "^0.10.2", "@nanostores/persistent": "^0.9.1",
"@replit/codemirror-emacs": "^6.1.0", "@replit/codemirror-emacs": "^6.0.1",
"@replit/codemirror-vim": "^6.2.1", "@replit/codemirror-vim": "^6.1.0",
"@replit/codemirror-vscode-keymap": "^6.0.2", "@replit/codemirror-vscode-keymap": "^6.0.2",
"@strudel/core": "workspace:*", "@strudel/core": "workspace:*",
"@strudel/draw": "workspace:*", "@uiw/codemirror-themes": "^4.21.21",
"@strudel/transpiler": "workspace:*", "@uiw/codemirror-themes-all": "^4.21.21",
"nanostores": "^0.11.3" "nanostores": "^0.9.5"
}, },
"devDependencies": { "devDependencies": {
"vite": "^6.0.11" "vite": "^5.0.10"
} }
} }
+8 -10
View File
@@ -1,6 +1,6 @@
import { ref, pure } from '@strudel/core'; import { ref, pure } from '@strudel/core';
import { WidgetType, ViewPlugin, Decoration } from '@codemirror/view'; import { WidgetType, ViewPlugin, Decoration } from '@codemirror/view';
import { StateEffect } from '@codemirror/state'; import { StateEffect, StateField } from '@codemirror/state';
export let sliderValues = {}; export let sliderValues = {};
const getSliderID = (from) => `slider_${from}`; const getSliderID = (from) => `slider_${from}`;
@@ -60,16 +60,14 @@ export class SliderWidget extends WidgetType {
} }
} }
export const setSliderWidgets = StateEffect.define(); export const setWidgets = StateEffect.define();
export const updateSliderWidgets = (view, widgets) => { export const updateWidgets = (view, widgets) => {
view.dispatch({ effects: setSliderWidgets.of(widgets) }); view.dispatch({ effects: setWidgets.of(widgets) });
}; };
function getSliders(widgetConfigs, view) { function getWidgets(widgetConfigs, view) {
return widgetConfigs return widgetConfigs.map(({ from, to, value, min, max, step }) => {
.filter((w) => w.type === 'slider')
.map(({ from, to, value, min, max, step }) => {
return Decoration.widget({ return Decoration.widget({
widget: new SliderWidget(value, min, max, from, to, step, view), widget: new SliderWidget(value, min, max, from, to, step, view),
side: 0, side: 0,
@@ -101,8 +99,8 @@ export const sliderPlugin = ViewPlugin.fromClass(
} }
} }
for (let e of tr.effects) { for (let e of tr.effects) {
if (e.is(setSliderWidgets)) { if (e.is(setWidgets)) {
this.decorations = Decoration.set(getSliders(e.value, update.view)); this.decorations = Decoration.set(getWidgets(e.value, update.view));
} }
} }
}); });
+410 -89
View File
@@ -1,117 +1,439 @@
import strudelTheme, { settings as strudelThemeSettings } from './themes/strudel-theme.mjs'; import {
import bluescreen, { settings as bluescreenSettings } from './themes/bluescreen.mjs'; abcdef,
import blackscreen, { settings as blackscreenSettings } from './themes/blackscreen.mjs';
import whitescreen, { settings as whitescreenSettings } from './themes/whitescreen.mjs';
import teletext, { settings as teletextSettings } from './themes/teletext.mjs';
import algoboy, { settings as algoboySettings } from './themes/algoboy.mjs';
import CutiePi, { settings as CutiePiSettings } from './themes/CutiePi.mjs';
import sonicPink, { settings as sonicPinkSettings } from './themes/sonic-pink.mjs';
import redText, { settings as redTextSettings } from './themes/red-text.mjs';
import greenText, { settings as greenTextSettings } from './themes/green-text.mjs';
import androidstudio, { settings as androidstudioSettings } from './themes/androidstudio.mjs';
import atomone, { settings as atomOneSettings } from './themes/atomone.mjs';
import aura, { settings as auraSettings } from './themes/aura.mjs';
import darcula, { settings as darculaSettings } from './themes/darcula.mjs';
import dracula, { settings as draculaSettings } from './themes/dracula.mjs';
import duotoneDark, { settings as duotoneDarkSettings } from './themes/duotoneDark.mjs';
import eclipse, { settings as eclipseSettings } from './themes/eclipse.mjs';
import githubDark, { settings as githubDarkSettings } from './themes/githubDark.mjs';
import githubLight, { settings as githubLightSettings } from './themes/githubLight.mjs';
import gruvboxDark, { settings as gruvboxDarkSettings } from './themes/gruvboxDark.mjs';
import gruvboxLight, { settings as gruvboxLightSettings } from './themes/gruvboxLight.mjs';
import materialDark, { settings as materialDarkSettings } from './themes/materialDark.mjs';
import materialLight, { settings as materialLightSettings } from './themes/materialLight.mjs';
import nord, { settings as nordSettings } from './themes/nord.mjs';
import monokai, { settings as monokaiSettings } from './themes/monokai.mjs';
import solarizedDark, { settings as solarizedDarkSettings } from './themes/solarizedDark.mjs';
import solarizedLight, { settings as solarizedLightSettings } from './themes/solarizedLight.mjs';
import sublime, { settings as sublimeSettings } from './themes/sublime.mjs';
import tokyoNight, { settings as tokyoNightSettings } from './themes/tokyoNight.mjs';
import tokyoNightStorm, { settings as tokyoNightStormSettings } from './themes/tokioNightStorm.mjs';
import tokyoNightDay, { settings as tokyoNightDaySettings } from './themes/tokyoNightDay.mjs';
import vscodeDark, { settings as vscodeDarkSettings } from './themes/vscodeDark.mjs';
import vscodeLight, { settings as vscodeLightSettings } from './themes/vscodeLight.mjs';
import xcodeLight, { settings as xcodeLightSettings } from './themes/xcodeLight.mjs';
import bbedit, { settings as bbeditSettings } from './themes/bbedit.mjs';
import noctisLilac, { settings as noctisLilacSettings } from './themes/noctisLilac.mjs';
import { setTheme } from '@strudel/draw';
export const themes = {
strudelTheme,
algoboy,
androidstudio, androidstudio,
atomone, atomone,
aura, aura,
bbedit, bespin,
blackscreen,
bluescreen,
CutiePi,
darcula, darcula,
dracula, dracula,
duotoneDark, duotoneDark,
eclipse, eclipse,
githubDark, githubDark,
githubLight,
greenText,
gruvboxDark, gruvboxDark,
gruvboxLight,
sonicPink,
materialDark, materialDark,
materialLight,
monokai,
noctisLilac,
nord, nord,
redText, okaidia,
solarizedDark, solarizedDark,
solarizedLight,
sublime, sublime,
teletext,
tokyoNight, tokyoNight,
tokyoNightDay,
tokyoNightStorm, tokyoNightStorm,
vscodeDark, vscodeDark,
vscodeLight, xcodeDark,
bbedit,
duotoneLight,
githubLight,
gruvboxLight,
materialLight,
noctisLilac,
solarizedLight,
tokyoNightDay,
xcodeLight,
} from '@uiw/codemirror-themes-all';
import strudelTheme from './themes/strudel-theme';
import bluescreen, { settings as bluescreenSettings } from './themes/bluescreen';
import blackscreen, { settings as blackscreenSettings } from './themes/blackscreen';
import whitescreen, { settings as whitescreenSettings } from './themes/whitescreen';
import teletext, { settings as teletextSettings } from './themes/teletext';
import algoboy, { settings as algoboySettings } from './themes/algoboy';
import terminal, { settings as terminalSettings } from './themes/terminal';
export const themes = {
strudelTheme,
bluescreen,
blackscreen,
whitescreen, whitescreen,
teletext,
algoboy,
terminal,
abcdef,
androidstudio,
atomone,
aura,
bespin,
darcula,
dracula,
duotoneDark,
eclipse,
githubDark,
gruvboxDark,
materialDark,
nord,
okaidia,
solarizedDark,
sublime,
tokyoNight,
tokyoNightStorm,
vscodeDark,
xcodeDark,
bbedit,
duotoneLight,
githubLight,
gruvboxLight,
materialLight,
noctisLilac,
solarizedLight,
tokyoNightDay,
xcodeLight, xcodeLight,
}; };
// lineBackground is background with 50% opacity, to make sure the selection below is visible
export const settings = { export const settings = {
strudelTheme: strudelThemeSettings, strudelTheme: {
background: '#222',
lineBackground: '#22222299',
foreground: '#fff',
// foreground: '#75baff',
caret: '#ffcc00',
selection: 'rgba(128, 203, 196, 0.5)',
selectionMatch: '#036dd626',
// lineHighlight: '#8a91991a', // original
lineHighlight: '#00000050',
gutterBackground: 'transparent',
// gutterForeground: '#8a919966',
gutterForeground: '#8a919966',
},
bluescreen: bluescreenSettings, bluescreen: bluescreenSettings,
blackscreen: blackscreenSettings, blackscreen: blackscreenSettings,
whitescreen: whitescreenSettings, whitescreen: whitescreenSettings,
teletext: teletextSettings, teletext: teletextSettings,
algoboy: algoboySettings, algoboy: algoboySettings,
androidstudio: androidstudioSettings, terminal: terminalSettings,
atomone: atomOneSettings, abcdef: {
aura: auraSettings, background: '#0f0f0f',
bbedit: bbeditSettings, lineBackground: '#0f0f0f99',
darcula: darculaSettings, foreground: '#defdef',
dracula: draculaSettings, caret: '#00FF00',
duotoneDark: duotoneDarkSettings, selection: '#515151',
eclipse: eclipseSettings, selectionMatch: '#515151',
CutiePi: CutiePiSettings, gutterBackground: '#555',
sonicPink: sonicPinkSettings, gutterForeground: '#FFFFFF',
githubLight: githubLightSettings, lineHighlight: '#314151',
githubDark: githubDarkSettings, },
greenText: greenTextSettings, androidstudio: {
gruvboxDark: gruvboxDarkSettings, background: '#282b2e',
gruvboxLight: gruvboxLightSettings, lineBackground: '#282b2e99',
materialDark: materialDarkSettings, foreground: '#a9b7c6',
materialLight: materialLightSettings, caret: '#00FF00',
noctisLilac: noctisLilacSettings, selection: '#343739',
nord: nordSettings, selectionMatch: '#343739',
monokai: monokaiSettings, lineHighlight: '#343739',
redText: redTextSettings, },
solarizedLight: solarizedLightSettings, atomone: {
solarizedDark: solarizedDarkSettings, background: '#272C35',
sublime: sublimeSettings, lineBackground: '#272C3599',
tokyoNight: tokyoNightSettings, foreground: '#9d9b97',
tokyoNightStorm: tokyoNightStormSettings, caret: '#797977',
vscodeDark: vscodeDarkSettings, selection: '#ffffff30',
vscodeLight: vscodeLightSettings, selectionMatch: '#2B323D',
xcodeLight: xcodeLightSettings, gutterBackground: '#272C35',
tokyoNightDay: tokyoNightDaySettings, gutterForeground: '#465063',
gutterBorder: 'transparent',
lineHighlight: '#2B323D',
},
aura: {
background: '#21202e',
lineBackground: '#21202e99',
foreground: '#edecee',
caret: '#a277ff',
selection: '#3d375e7f',
selectionMatch: '#3d375e7f',
gutterBackground: '#21202e',
gutterForeground: '#edecee',
gutterBorder: 'transparent',
lineHighlight: '#a394f033',
},
bbedit: {
light: true,
background: '#FFFFFF',
lineBackground: '#FFFFFF99',
foreground: '#000000',
caret: '#FBAC52',
selection: '#FFD420',
selectionMatch: '#FFD420',
gutterBackground: '#f5f5f5',
gutterForeground: '#4D4D4C',
gutterBorder: 'transparent',
lineHighlight: '#00000012',
},
bespin: {
background: '#28211c',
lineBackground: '#28211c99',
foreground: '#9d9b97',
caret: '#797977',
selection: '#36312e',
selectionMatch: '#4f382b',
gutterBackground: '#28211c',
gutterForeground: '#666666',
lineHighlight: 'rgba(255, 255, 255, 0.1)',
},
darcula: {
background: '#2B2B2B',
lineBackground: '#2B2B2B99',
foreground: '#f8f8f2',
caret: '#FFFFFF',
selection: 'rgba(255, 255, 255, 0.1)',
selectionMatch: 'rgba(255, 255, 255, 0.2)',
gutterBackground: 'rgba(255, 255, 255, 0.1)',
gutterForeground: '#999',
gutterBorder: 'transparent',
lineHighlight: 'rgba(255, 255, 255, 0.1)',
},
dracula: {
background: '#282a36',
lineBackground: '#282a3699',
foreground: '#f8f8f2',
caret: '#f8f8f0',
selection: 'rgba(255, 255, 255, 0.1)',
selectionMatch: 'rgba(255, 255, 255, 0.2)',
gutterBackground: '#282a36',
gutterForeground: '#6D8A88',
gutterBorder: 'transparent',
lineHighlight: 'rgba(255, 255, 255, 0.1)',
},
duotoneLight: {
light: true,
background: '#faf8f5',
lineBackground: '#faf8f599',
foreground: '#b29762',
caret: '#93abdc',
selection: '#e3dcce',
selectionMatch: '#e3dcce',
gutterBackground: '#faf8f5',
gutterForeground: '#cdc4b1',
gutterBorder: 'transparent',
lineHighlight: '#EFEFEF',
},
duotoneDark: {
background: '#2a2734',
lineBackground: '#2a273499',
foreground: '#6c6783',
caret: '#ffad5c',
selection: 'rgba(255, 255, 255, 0.1)',
gutterBackground: '#2a2734',
gutterForeground: '#545167',
lineHighlight: '#36334280',
},
eclipse: {
light: true,
background: '#fff',
lineBackground: '#ffffff99',
foreground: '#000',
caret: '#FFFFFF',
selection: '#d7d4f0',
selectionMatch: '#d7d4f0',
gutterBackground: '#f7f7f7',
gutterForeground: '#999',
lineHighlight: '#e8f2ff',
gutterBorder: 'transparent',
},
githubLight: {
light: true,
background: '#fff',
lineBackground: '#ffffff99',
foreground: '#24292e',
selection: '#BBDFFF',
selectionMatch: '#BBDFFF',
gutterBackground: '#fff',
gutterForeground: '#6e7781',
},
githubDark: {
background: '#0d1117',
lineBackground: '#0d111799',
foreground: '#c9d1d9',
caret: '#c9d1d9',
selection: '#003d73',
selectionMatch: '#003d73',
lineHighlight: '#36334280',
},
gruvboxDark: {
background: '#282828',
lineBackground: '#28282899',
foreground: '#ebdbb2',
caret: '#ebdbb2',
selection: '#bdae93',
selectionMatch: '#bdae93',
lineHighlight: '#3c3836',
gutterBackground: '#282828',
gutterForeground: '#7c6f64',
},
gruvboxLight: {
light: true,
background: '#fbf1c7',
lineBackground: '#fbf1c799',
foreground: '#3c3836',
caret: '#af3a03',
selection: '#ebdbb2',
selectionMatch: '#bdae93',
lineHighlight: '#ebdbb2',
gutterBackground: '#ebdbb2',
gutterForeground: '#665c54',
gutterBorder: 'transparent',
},
materialDark: {
background: '#2e3235',
lineBackground: '#2e323599',
foreground: '#bdbdbd',
caret: '#a0a4ae',
selection: '#d7d4f0',
selectionMatch: '#d7d4f0',
gutterBackground: '#2e3235',
gutterForeground: '#999',
gutterActiveForeground: '#4f5b66',
lineHighlight: '#545b61',
},
materialLight: {
light: true,
background: '#FAFAFA',
lineBackground: '#FAFAFA99',
foreground: '#90A4AE',
caret: '#272727',
selection: '#80CBC440',
selectionMatch: '#FAFAFA',
gutterBackground: '#FAFAFA',
gutterForeground: '#90A4AE',
gutterBorder: 'transparent',
lineHighlight: '#CCD7DA50',
},
noctisLilac: {
light: true,
background: '#f2f1f8',
lineBackground: '#f2f1f899',
foreground: '#0c006b',
caret: '#5c49e9',
selection: '#d5d1f2',
selectionMatch: '#d5d1f2',
gutterBackground: '#f2f1f8',
gutterForeground: '#0c006b70',
lineHighlight: '#e1def3',
},
nord: {
background: '#2e3440',
lineBackground: '#2e344099',
foreground: '#FFFFFF',
caret: '#FFFFFF',
selection: '#3b4252',
selectionMatch: '#e5e9f0',
gutterBackground: '#2e3440',
gutterForeground: '#4c566a',
gutterActiveForeground: '#d8dee9',
lineHighlight: '#4c566a',
},
okaidia: {
background: '#272822',
lineBackground: '#27282299',
foreground: '#FFFFFF',
caret: '#FFFFFF',
selection: '#49483E',
selectionMatch: '#49483E',
gutterBackground: '#272822',
gutterForeground: '#FFFFFF70',
lineHighlight: '#00000059',
},
solarizedLight: {
light: true,
background: '#fdf6e3',
lineBackground: '#fdf6e399',
foreground: '#657b83',
caret: '#586e75',
selection: '#dfd9c8',
selectionMatch: '#dfd9c8',
gutterBackground: '#00000010',
gutterForeground: '#657b83',
lineHighlight: '#dfd9c8',
},
solarizedDark: {
background: '#002b36',
lineBackground: '#002b3699',
foreground: '#93a1a1',
caret: '#839496',
selection: '#173541',
selectionMatch: '#aafe661a',
gutterBackground: '#00252f',
gutterForeground: '#839496',
lineHighlight: '#173541',
},
sublime: {
background: '#303841',
lineBackground: '#30384199',
foreground: '#FFFFFF',
caret: '#FBAC52',
selection: '#4C5964',
selectionMatch: '#3A546E',
gutterBackground: '#303841',
gutterForeground: '#FFFFFF70',
lineHighlight: '#00000059',
},
tokyoNightDay: {
light: true,
background: '#e1e2e7',
lineBackground: '#e1e2e799',
foreground: '#3760bf',
caret: '#3760bf',
selection: '#99a7df',
selectionMatch: '#99a7df',
gutterBackground: '#e1e2e7',
gutterForeground: '#3760bf',
gutterBorder: 'transparent',
lineHighlight: '#5f5faf11',
},
tokyoNightStorm: {
background: '#24283b',
lineBackground: '#24283b99',
foreground: '#7982a9',
caret: '#c0caf5',
selection: '#6f7bb630',
selectionMatch: '#1f2335',
gutterBackground: '#24283b',
gutterForeground: '#7982a9',
gutterBorder: 'transparent',
lineHighlight: '#292e42',
},
tokyoNight: {
background: '#1a1b26',
lineBackground: '#1a1b2699',
foreground: '#787c99',
caret: '#c0caf5',
selection: '#515c7e40',
selectionMatch: '#16161e',
gutterBackground: '#1a1b26',
gutterForeground: '#787c99',
gutterBorder: 'transparent',
lineHighlight: '#1e202e',
},
vscodeDark: {
background: '#1e1e1e',
lineBackground: '#1e1e1e99',
foreground: '#9cdcfe',
caret: '#c6c6c6',
selection: '#6199ff2f',
selectionMatch: '#72a1ff59',
lineHighlight: '#ffffff0f',
gutterBackground: '#1e1e1e',
gutterForeground: '#838383',
gutterActiveForeground: '#fff',
},
xcodeLight: {
light: true,
background: '#fff',
lineBackground: '#ffffff99',
foreground: '#3D3D3D',
selection: '#BBDFFF',
selectionMatch: '#BBDFFF',
gutterBackground: '#fff',
gutterForeground: '#AFAFAF',
lineHighlight: '#EDF4FF',
},
xcodeDark: {
background: '#292A30',
lineBackground: '#292A3099',
foreground: '#CECFD0',
caret: '#fff',
selection: '#727377',
selectionMatch: '#727377',
lineHighlight: '#2F3239',
},
}; };
function getColors(str) { function getColors(str) {
@@ -191,7 +513,6 @@ export function activateTheme(name) {
.map(([key, value]) => `--${key}: ${value} !important;`) .map(([key, value]) => `--${key}: ${value} !important;`)
.join('\n')} .join('\n')}
}`; }`;
setTheme(themeSettings);
// tailwind dark mode // tailwind dark mode
if (themeSettings.light) { if (themeSettings.light) {
document.documentElement.classList.remove('dark'); document.documentElement.classList.remove('dark');
-45
View File
@@ -1,45 +0,0 @@
/**
* @name Cutie Pi
* by Switch Angel
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
const deepPurple = '#5c019a';
const yellowPink = '#fbeffc';
const grey = '#272C35';
const pinkAccent = '#fee1ff';
const lightGrey = '#465063';
const bratGreen = '#9acd3f';
const lighterGrey = '#97a1b7';
const pink = '#f6a6fd';
export const settings = {
background: 'white',
lineBackground: 'transparent',
foreground: deepPurple,
caret: '#797977',
selection: yellowPink,
selectionMatch: '#2B323D',
gutterBackground: grey,
gutterForeground: lightGrey,
gutterBorder: 'transparent',
lineHighlight: pinkAccent,
};
export default createTheme({
theme: 'light',
settings,
styles: [
{
tag: [t.function(t.variableName), t.function(t.propertyName), t.url, t.processingInstruction],
color: deepPurple,
},
{ tag: [t.tagName, t.heading], color: settings.foreground },
{ tag: t.comment, color: lighterGrey },
{ tag: [t.variableName, t.propertyName, t.labelName], color: pink },
{ tag: [t.attributeName, t.number], color: '#d19a66' },
{ tag: t.className, color: grey },
{ tag: t.keyword, color: deepPurple },
{ tag: [t.string, t.regexp, t.special(t.propertyName)], color: bratGreen },
],
});
+31 -51
View File
@@ -1,61 +1,41 @@
import { tags as t } from '@lezer/highlight'; import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs'; import { createTheme } from '@uiw/codemirror-themes';
const palettes = {
// https://www.deviantart.com/advancedfan2020/art/Game-Boy-Palette-Set-Color-HEX-Part-09-920495662
'Central Florida A': ['#FFF630', '#B3AC22', '#666213', '#191905'],
'Central Florida B': ['#38CEBA', '#279082', '#16524A', '#061513'],
'Central Florida C': ['#FF8836', '#B35F26', '#663616', '#190E05'],
'Central Florida D': ['#E07070', '#9D4E4E', '#5A2D2D', '#160B0B'],
'Central Florida E': ['#7AA4CB', '#55738E', '#314251', '#0C1014'],
'Feminine Energy A': ['#DC5686', '#9A415E', '#582536', '#16090D'],
'Feminine Energy B': ['#D0463C', '#92312A', '#531c18', '#150706'],
'Feminine Energy C': ['#D86918', '#974A11', '#562A0A', '#160A02'],
'Feminine Energy D': ['#EFC54F', '#A78A36', '#604F20', '#181408'],
'Feminine Energy E': ['#866399', '#5e456b', '#36283d', '#0d0a0f'],
'Sour Watermelon A': ['#993366', '#6B2447', '#3D1429', '#0F050A'],
'Sour Watermelon B': ['#996666', '#6B4747', '#3D2929', '#0F0A0A'],
'Sour Watermelon C': ['#999966', '#686B47', '#3d3d29', '#0f0f0A'],
'Sour Watermelon D': ['#99cc66', '#6b8f47', '#3d5229', '#0f140a'],
'Sour Watermelon E': ['#99ff66', '#6bb347', '#3d6629', '#0f190a'],
//https://www.deviantart.com/advancedfan2020/art/Game-Boy-Palette-Set-Color-HEX-Part-02-920073260
'Peri Peaceful A': ['#909BE9', '#656DA3', '#3A3E5D', '#0e0f17'],
'Peri Peaceful B': ['#68628d', '#494563', '#2a2738', '#0a0a0e'], // pretty dim
'Peri Peaceful E': ['#b5a0a9', '#7f7076', '#484044', '#121011'],
'Hichem Palette B': ['#4fa3a5', '#377273', '#204142', '#081010'],
'Hichem Palette C': ['#Fe6f9b', '#b24e6d', '#662c3e', '#190b0f'],
'Hichem Palette D': ['#ffbb5a', '#b3833f', '#664b24', '#191309'],
'JSR2 A': ['#E0EFC0', '#9da786', '#5a604d', '#161813'],
};
const palette = palettes['Sour Watermelon B'];
export const settings = { export const settings = {
background: palette[3], background: '#9bbc0f',
foreground: palette[1], foreground: '#0f380f', // whats that?
caret: palette[0], caret: '#0f380f',
selection: palette[0], selection: '#306230',
selectionMatch: palette[1], selectionMatch: '#ffffff26',
lineHighlight: palette[3], lineHighlight: '#8bac0f',
lineBackground: palette[3] + '90', lineBackground: '#9bbc0f50',
//lineBackground: 'transparent', //lineBackground: 'transparent',
gutterBackground: 'transparent', gutterBackground: 'transparent',
gutterForeground: palette[0], gutterForeground: '#0f380f',
light: false, light: true,
// customStyle: '.cm-line { line-height: 1 }', customStyle: '.cm-line { line-height: 1 }',
}; };
export default createTheme({ export default createTheme({
theme: 'dark', theme: 'light',
settings, settings,
styles: [ styles: [
{ tag: t.comment, color: palette[2] }, { tag: t.keyword, color: '#0f380f' },
{ tag: t.string, color: palette[1] }, { tag: t.operator, color: '#0f380f' },
{ tag: [t.atom, t.number], color: palette[1] }, { tag: t.special(t.variableName), color: '#0f380f' },
{ tag: [t.meta, t.labelName, t.variableName], color: palette[0] }, { tag: t.typeName, color: '#0f380f' },
{ { tag: t.atom, color: '#0f380f' },
tag: [t.keyword, t.tagName, t.arithmeticOperator], { tag: t.number, color: '#0f380f' },
color: palette[1], { tag: t.definition(t.variableName), color: '#0f380f' },
}, { tag: t.string, color: '#0f380f' },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: palette[0] }, { tag: t.special(t.string), color: '#0f380f' },
{ tag: [t.function(t.variableName), t.propertyName], color: palette[0] }, { tag: t.comment, color: '#0f380f' },
{ tag: t.atom, color: palette[1] }, { tag: t.variableName, color: '#0f380f' },
{ tag: t.tagName, color: '#0f380f' },
{ tag: t.bracket, color: '#0f380f' },
{ tag: t.meta, color: '#0f380f' },
{ tag: t.attributeName, color: '#0f380f' },
{ tag: t.propertyName, color: '#0f380f' },
{ tag: t.className, color: '#0f380f' },
{ tag: t.invalid, color: '#0f380f' },
{ tag: [t.unit, t.punctuation], color: '#0f380f' },
], ],
}); });
-43
View File
@@ -1,43 +0,0 @@
/**
* @name androidstudio
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#282b2e',
lineBackground: '#282b2e99',
foreground: '#a9b7c6',
caret: '#00FF00',
selection: '#343739',
selectionMatch: '#343739',
lineHighlight: '#343739',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#282b2e',
foreground: '#a9b7c6',
caret: '#00FF00',
selection: '#4e5254',
selectionMatch: '#4e5254',
gutterForeground: '#cccccc50',
lineHighlight: '#7f85891f',
},
styles: [
{ tag: t.labelName, color: 'inherit' },
{ tag: [t.keyword, t.deleted, t.className], color: '#a9b7c6' },
{ tag: [t.number, t.literal], color: '#6897bb' },
//{ tag: [t.link, t.variableName], color: '#629755' },
{ tag: [t.link, t.variableName], color: '#a9b7c6' },
{ tag: [t.comment, t.quote], color: 'grey' },
{ tag: [t.meta, t.documentMeta], color: '#bbb529' },
//{ tag: [t.string, t.propertyName, t.attributeValue], color: '#6a8759' },
{ tag: [t.propertyName, t.attributeValue], color: '#a9b7c6' },
{ tag: [t.string], color: '#6a8759' },
{ tag: [t.heading, t.typeName], color: '#ffc66d' },
{ tag: [t.attributeName], color: '#a9b7c6' },
{ tag: [t.emphasis], fontStyle: 'italic' },
],
});
-51
View File
@@ -1,51 +0,0 @@
/**
* @name Atom One
* Atom One dark syntax theme
*
* https://github.com/atom/one-dark-syntax
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#272C35',
lineBackground: '#272C3599',
foreground: 'hsl(220, 14%, 71%)',
caret: '#797977',
selection: '#ffffff30',
selectionMatch: '#2B323D',
gutterBackground: '#272C35',
gutterForeground: '#465063',
gutterBorder: 'transparent',
lineHighlight: '#2B323D',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#272C35',
foreground: '#9d9b97',
caret: '#797977',
selection: '#3d4c64',
selectionMatch: '#3d4c64',
gutterBackground: '#272C35',
gutterForeground: '#465063',
gutterBorder: 'transparent',
lineHighlight: '#2e3f5940',
},
styles: [
{
tag: [t.function(t.variableName), t.function(t.propertyName), t.url, t.processingInstruction],
color: 'hsl(207, 82%, 66%)',
},
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: 'hsl( 29, 54%, 61%)' },
{ tag: [t.tagName, t.heading], color: '#e06c75' },
{ tag: t.comment, color: '#54636D' },
{ tag: [t.variableName, t.propertyName, t.labelName], color: 'hsl(220, 14%, 71%)' },
{ tag: [t.attributeName, t.number], color: 'hsl( 29, 54%, 61%)' },
{ tag: t.className, color: 'hsl( 39, 67%, 69%)' },
{ tag: t.keyword, color: 'hsl(286, 60%, 67%)' },
{ tag: [t.string, t.regexp, t.special(t.propertyName)], color: '#98c379' },
],
});
-51
View File
@@ -1,51 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#21202e',
lineBackground: '#21202e99',
foreground: '#edecee',
caret: '#a277ff',
selection: '#3d375e7f',
selectionMatch: '#3d375e7f',
gutterBackground: '#21202e',
gutterForeground: '#edecee',
gutterBorder: 'transparent',
lineHighlight: '#a394f033',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#21202e',
foreground: '#edecee',
caret: '#a277ff',
selection: '#5a51898f',
selectionMatch: '#5a51898f',
gutterBackground: '#21202e',
gutterForeground: '#edecee',
gutterBorder: 'transparent',
lineHighlight: '#a394f033',
},
styles: [
{ tag: t.keyword, color: '#a277ff' },
{ tag: [t.name, t.deleted, t.character, t.macroName], color: '#edecee' },
{ tag: [t.propertyName], color: '#ffca85' },
{ tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: '#61ffca' },
{ tag: [t.function(t.variableName), t.labelName], color: '#ffca85' },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: '#61ffca' },
{ tag: [t.definition(t.name), t.separator], color: '#edecee' },
{ tag: [t.className], color: '#82e2ff' },
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: '#61ffca' },
{ tag: [t.typeName], color: '#82e2ff' },
{ tag: [t.operator, t.operatorKeyword], color: '#a277ff' },
{ tag: [t.url, t.escape, t.regexp, t.link], color: '#61ffca' },
{ tag: [t.meta, t.comment], color: '#6d6d6d' },
{ tag: t.strong, fontWeight: 'bold' },
{ tag: t.emphasis, fontStyle: 'italic' },
{ tag: t.link, textDecoration: 'underline' },
{ tag: t.heading, fontWeight: 'bold', color: '#a277ff' },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#edecee' },
{ tag: t.invalid, color: '#ff6767' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
],
});
-46
View File
@@ -1,46 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
light: true,
background: '#FFFFFF',
lineBackground: '#FFFFFF99',
foreground: '#000000',
caret: '#FBAC52',
selection: '#FFD420',
selectionMatch: '#FFD420',
gutterBackground: '#f5f5f5',
gutterForeground: '#4D4D4C',
gutterBorder: 'transparent',
lineHighlight: '#00000012',
};
export default createTheme({
theme: 'light',
settings: {
background: '#FFFFFF',
foreground: '#000000',
caret: '#FBAC52',
selection: '#FFD420',
selectionMatch: '#FFD420',
gutterBackground: '#f5f5f5',
gutterForeground: '#4D4D4C',
gutterBorder: 'transparent',
lineHighlight: '#00000012',
},
styles: [
{ tag: [t.meta, t.comment], color: '#804000' },
{ tag: [t.keyword, t.strong], color: '#0000FF' },
{ tag: [t.number], color: '#FF0080' },
{ tag: [t.string], color: '#FF0080' },
{ tag: [t.variableName], color: '#006600' },
{ tag: [t.escape], color: '#33CC33' },
{ tag: [t.tagName], color: '#1C02FF' },
{ tag: [t.heading], color: '#0C07FF' },
{ tag: [t.quote], color: '#000000' },
{ tag: [t.list], color: '#B90690' },
{ tag: [t.documentMeta], color: '#888888' },
{ tag: [t.function(t.variableName)], color: '#0000A2' },
{ tag: [t.definition(t.typeName), t.typeName], color: '#6D79DE' },
],
});
+20 -21
View File
@@ -1,5 +1,5 @@
import { tags as t } from '@lezer/highlight'; import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs'; import { createTheme } from '@uiw/codemirror-themes';
export const settings = { export const settings = {
background: 'black', background: 'black',
foreground: 'white', // whats that? foreground: 'white', // whats that?
@@ -15,25 +15,24 @@ export default createTheme({
theme: 'dark', theme: 'dark',
settings, settings,
styles: [ styles: [
{ tag: t.labelName, color: 'inherit' }, { tag: t.keyword, color: 'white' },
{ tag: t.keyword, color: 'inherit' }, { tag: t.operator, color: 'white' },
{ tag: t.operator, color: 'inherit' }, { tag: t.special(t.variableName), color: 'white' },
{ tag: t.special(t.variableName), color: 'inherit' }, { tag: t.typeName, color: 'white' },
{ tag: t.typeName, color: 'inherit' }, { tag: t.atom, color: 'white' },
{ tag: t.atom, color: 'inherit' }, { tag: t.number, color: 'white' },
{ tag: t.number, color: 'inherit' }, { tag: t.definition(t.variableName), color: 'white' },
{ tag: t.definition(t.variableName), color: 'inherit' }, { tag: t.string, color: 'white' },
{ tag: t.string, color: 'inherit' }, { tag: t.special(t.string), color: 'white' },
{ tag: t.special(t.string), color: 'inherit' }, { tag: t.comment, color: 'white' },
{ tag: t.comment, color: 'inherit' }, { tag: t.variableName, color: 'white' },
{ tag: t.variableName, color: 'inherit' }, { tag: t.tagName, color: 'white' },
{ tag: t.tagName, color: 'inherit' }, { tag: t.bracket, color: 'white' },
{ tag: t.bracket, color: 'inherit' }, { tag: t.meta, color: 'white' },
{ tag: t.meta, color: 'inherit' }, { tag: t.attributeName, color: 'white' },
{ tag: t.attributeName, color: 'inherit' }, { tag: t.propertyName, color: 'white' },
{ tag: t.propertyName, color: 'inherit' }, { tag: t.className, color: 'white' },
{ tag: t.className, color: 'inherit' }, { tag: t.invalid, color: 'white' },
{ tag: t.invalid, color: 'inherit' }, { tag: [t.unit, t.punctuation], color: 'white' },
{ tag: [t.unit, t.punctuation], color: 'inherit' },
], ],
}); });
+20 -21
View File
@@ -1,5 +1,5 @@
import { tags as t } from '@lezer/highlight'; import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs'; import { createTheme } from '@uiw/codemirror-themes';
export const settings = { export const settings = {
background: '#051DB5', background: '#051DB5',
lineBackground: '#051DB550', lineBackground: '#051DB550',
@@ -18,25 +18,24 @@ export default createTheme({
theme: 'dark', theme: 'dark',
settings, settings,
styles: [ styles: [
{ tag: t.labelName, color: 'inherit' }, { tag: t.keyword, color: 'white' },
{ tag: t.keyword, color: 'inherit' }, { tag: t.operator, color: 'white' },
{ tag: t.operator, color: 'inherit' }, { tag: t.special(t.variableName), color: 'white' },
{ tag: t.special(t.variableName), color: 'inherit' }, { tag: t.typeName, color: 'white' },
{ tag: t.typeName, color: 'inherit' }, { tag: t.atom, color: 'white' },
{ tag: t.atom, color: 'inherit' }, { tag: t.number, color: 'white' },
{ tag: t.number, color: 'inherit' }, { tag: t.definition(t.variableName), color: 'white' },
{ tag: t.definition(t.variableName), color: 'inherit' }, { tag: t.string, color: 'white' },
{ tag: t.string, color: 'inherit' }, { tag: t.special(t.string), color: 'white' },
{ tag: t.special(t.string), color: 'inherit' }, { tag: t.comment, color: 'white' },
{ tag: t.comment, color: 'inherit' }, { tag: t.variableName, color: 'white' },
{ tag: t.variableName, color: 'inherit' }, { tag: t.tagName, color: 'white' },
{ tag: t.tagName, color: 'inherit' }, { tag: t.bracket, color: 'white' },
{ tag: t.bracket, color: 'inherit' }, { tag: t.meta, color: 'white' },
{ tag: t.meta, color: 'inherit' }, { tag: t.attributeName, color: 'white' },
{ tag: t.attributeName, color: 'inherit' }, { tag: t.propertyName, color: 'white' },
{ tag: t.propertyName, color: 'inherit' }, { tag: t.className, color: 'white' },
{ tag: t.className, color: 'inherit' }, { tag: t.invalid, color: 'white' },
{ tag: t.invalid, color: 'inherit' }, { tag: [t.unit, t.punctuation], color: 'white' },
{ tag: [t.unit, t.punctuation], color: 'inherit' },
], ],
}); });
-48
View File
@@ -1,48 +0,0 @@
/**
* @name darcula
* @author darcula
* Name: IntelliJ IDEA darcula theme
* From IntelliJ IDEA by JetBrains
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#242424',
lineBackground: '#24242499',
foreground: '#f8f8f2',
caret: '#FFFFFF',
selection: 'rgba(255, 255, 255, 0.1)',
selectionMatch: 'rgba(255, 255, 255, 0.2)',
gutterBackground: 'rgba(255, 255, 255, 0.1)',
gutterForeground: '#999',
gutterBorder: 'transparent',
lineHighlight: 'rgba(255, 255, 255, 0.1)',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#242424',
foreground: '#f8f8f2',
caret: '#FFFFFF',
selection: 'rgba(255, 255, 255, 0.1)',
selectionMatch: 'rgba(255, 255, 255, 0.2)',
gutterBackground: 'transparent',
gutterForeground: '#999',
gutterBorder: 'transparent',
lineHighlight: 'rgba(255, 255, 255, 0.1)',
},
styles: [
{ tag: t.labelName, color: '#CCCCCC' },
{ tag: [t.atom, t.number], color: '#7A9EC2' },
{ tag: [t.comment], color: '#707070' },
{ tag: [t.string], color: '#6A8759' },
{ tag: [t.variableName, t.operator], color: '#CCCCCC' },
{ tag: [t.function(t.variableName), t.propertyName], color: '#FFC66D' },
{ tag: [t.meta, t.className], color: '#FFC66D' },
{ tag: [t.propertyName], color: '#FFC66D' },
{ tag: [t.keyword], color: '#CC7832' },
{ tag: [t.tagName], color: '#ff79c6' },
{ tag: [t.typeName], color: '#ffb86c' },
],
});
-51
View File
@@ -1,51 +0,0 @@
/**
* @name dracula
* @author dracula
* Michael Kaminsky (http://github.com/mkaminsky11)
* Original dracula color scheme by Zeno Rocha (https://github.com/zenorocha/dracula-theme)
*/
// this is different from https://thememirror.net/dracula
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#282a36',
lineBackground: '#282a3699',
foreground: '#f8f8f2',
caret: '#f8f8f0',
selection: 'rgba(255, 255, 255, 0.1)',
selectionMatch: 'rgba(255, 255, 255, 0.2)',
gutterBackground: '#282a36',
gutterForeground: '#6272a4',
gutterBorder: 'transparent',
lineHighlight: 'rgba(255, 255, 255, 0.1)',
};
const purple = '#BD93F9';
export default createTheme({
theme: 'dark',
settings: {
background: '#282a36',
foreground: '#f8f8f2',
caret: '#f8f8f0',
selection: 'rgba(255, 255, 255, 0.1)',
selectionMatch: 'rgba(255, 255, 255, 0.2)',
gutterBackground: '#282a36',
gutterForeground: '#6272a4',
gutterBorder: 'transparent',
lineHighlight: 'rgba(255, 255, 255, 0.1)',
},
styles: [
{ tag: t.comment, color: '#6272a4' },
{ tag: t.string, color: '#f1fa8c' },
{ tag: [t.atom, t.number], color: purple },
{ tag: [t.meta, t.labelName, t.variableName], color: '#f8f8f2' },
{
tag: [t.keyword, t.tagName, t.arithmeticOperator],
color: '#ff79c6',
},
{ tag: [t.function(t.variableName), t.propertyName], color: '#50fa7b' },
{ tag: t.atom, color: '#bd93f9' },
],
});
-42
View File
@@ -1,42 +0,0 @@
/**
* @name duotone
* @author Bram de Haan
* by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes)
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#2a2734',
lineBackground: '#2a273499',
foreground: '#eeebff',
caret: '#ffad5c',
selection: 'rgba(255, 255, 255, 0.1)',
gutterBackground: '#2a2734',
gutterForeground: '#545167',
lineHighlight: '#36334280',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#2a2734',
foreground: '#6c6783',
caret: '#ffad5c',
selection: '#9a86fd',
selectionMatch: '#9a86fd',
gutterBackground: '#2a2734',
gutterForeground: '#545167',
lineHighlight: '#36334280',
},
styles: [
{ tag: [t.comment, t.bracket, t.operator], color: '#6c6783' },
{ tag: [t.atom, t.number, t.keyword, t.link, t.attributeName, t.quote], color: '#ffcc99' },
{ tag: [t.emphasis, t.heading, t.tagName, t.propertyName, t.className, t.variableName], color: '#eeebff' },
{ tag: [t.typeName, t.url], color: '#eeebff' },
{ tag: t.string, color: '#ffb870' },
/* { tag: [t.propertyName], color: '#9a86fd' }, */
{ tag: [t.propertyName], color: '#eeebff' },
{ tag: t.labelName, color: '#eeebff' },
],
});
-45
View File
@@ -1,45 +0,0 @@
/**
* @name duotone
* @author Bram de Haan
* by Bram de Haan, adapted from DuoTone themes by Simurai (http://simurai.com/projects/2016/01/01/duotone-themes)
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
light: true,
background: '#faf8f5',
lineBackground: '#faf8f599',
foreground: '#b29762',
caret: '#93abdc',
selection: '#e3dcce',
selectionMatch: '#e3dcce',
gutterBackground: '#faf8f5',
gutterForeground: '#cdc4b1',
gutterBorder: 'transparent',
lineHighlight: '#EFEFEF',
};
export default createTheme({
theme: 'light',
settings: {
background: '#faf8f5',
foreground: '#b29762',
caret: '#93abdc',
selection: '#e3dcce',
selectionMatch: '#e3dcce',
gutterBackground: '#faf8f5',
gutterForeground: '#cdc4b1',
gutterBorder: 'transparent',
lineHighlight: '#ddceb154',
},
styles: [
{ tag: [t.comment, t.bracket], color: '#b6ad9a' },
{ tag: [t.atom, t.number, t.keyword, t.link, t.attributeName, t.quote], color: '#063289' },
{ tag: [t.emphasis, t.heading, t.tagName, t.propertyName, t.variableName], color: '#2d2006' },
{ tag: [t.typeName, t.url, t.string], color: '#896724' },
{ tag: [t.operator, t.string], color: '#1659df' },
{ tag: [t.propertyName], color: '#b29762' },
{ tag: [t.unit, t.punctuation], color: '#063289' },
],
});
-46
View File
@@ -1,46 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
light: true,
background: '#fff',
lineBackground: '#ffffff99',
foreground: '#000',
caret: '#FFFFFF',
selection: '#d7d4f0',
selectionMatch: '#d7d4f0',
gutterBackground: '#f7f7f7',
gutterForeground: '#999',
lineHighlight: '#e8f2ff',
gutterBorder: 'transparent',
};
export default createTheme({
theme: 'light',
settings: {
background: '#fff',
foreground: '#000',
caret: '#FFFFFF',
selection: '#d7d4f0',
selectionMatch: '#d7d4f0',
gutterBackground: '#f7f7f7',
gutterForeground: '#999',
lineHighlight: '#006fff1c',
gutterBorder: 'transparent',
},
styles: [
{ tag: [t.comment], color: '#3F7F5F' },
{ tag: [t.documentMeta], color: '#FF1717' },
{ tag: t.keyword, color: '#7F0055', fontWeight: 'bold' },
{ tag: t.atom, color: '#00f' },
{ tag: t.number, color: '#164' },
{ tag: t.propertyName, color: '#164' },
{ tag: [t.variableName, t.definition(t.variableName)], color: '#0000C0' },
{ tag: t.function(t.variableName), color: '#0000C0' },
{ tag: t.string, color: '#2A00FF' },
{ tag: t.operator, color: 'black' },
{ tag: t.tagName, color: '#170' },
{ tag: t.attributeName, color: '#00c' },
{ tag: t.link, color: '#219' },
],
});
-45
View File
@@ -1,45 +0,0 @@
/**
* @name github
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#0d1117',
lineBackground: '#0d111799',
foreground: '#c9d1d9',
caret: '#c9d1d9',
selection: '#003d73',
selectionMatch: '#003d73',
lineHighlight: '#36334280',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#0d1117',
foreground: '#c9d1d9',
caret: '#c9d1d9',
selection: '#003d73',
selectionMatch: '#003d73',
lineHighlight: '#36334280',
},
styles: [
{ tag: t.labelName, color: '#d2a8ff' },
{ tag: [t.standard(t.tagName), t.tagName], color: '#7ee787' },
{ tag: [t.comment, t.bracket], color: '#8b949e' },
{ tag: [t.className, t.propertyName], color: '#d2a8ff' },
{ tag: [t.variableName, t.attributeName], color: '#d2a8ff' },
{ tag: [t.number, t.operator], color: '#79c0ff' },
{ tag: [t.keyword, t.typeName, t.typeOperator, t.typeName], color: '#ff7b72' },
{ tag: [t.string, t.meta, t.regexp], color: '#a5d6ff' },
{ tag: [t.name, t.quote], color: '#7ee787' },
{ tag: [t.heading, t.strong], color: '#d2a8ff', fontWeight: 'bold' },
{ tag: [t.emphasis], color: '#d2a8ff', fontStyle: 'italic' },
{ tag: [t.deleted], color: '#ffdcd7', backgroundColor: 'ffeef0' },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#ffab70' },
{ tag: t.link, textDecoration: 'underline' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
{ tag: t.invalid, color: '#f97583' },
],
});
-45
View File
@@ -1,45 +0,0 @@
/**
* @name github
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
light: true,
background: '#fff',
lineBackground: '#ffffff99',
foreground: '#24292e',
selection: '#BBDFFF',
selectionMatch: '#BBDFFF',
gutterBackground: '#fff',
gutterForeground: '#6e7781',
};
export default createTheme({
theme: 'light',
settings: {
background: '#fff',
foreground: '#24292e',
selection: '#BBDFFF',
selectionMatch: '#BBDFFF',
gutterBackground: '#fff',
gutterForeground: '#6e7781',
},
styles: [
{ tag: [t.standard(t.tagName), t.tagName], color: '#116329' },
{ tag: [t.comment, t.bracket], color: '#6a737d' },
{ tag: [t.className, t.propertyName], color: '#6f42c1' },
{ tag: [t.variableName, t.attributeName, t.number, t.operator], color: '#005cc5' },
{ tag: [t.keyword, t.typeName, t.typeOperator, t.typeName], color: '#d73a49' },
{ tag: [t.string, t.meta, t.regexp], color: '#032f62' },
{ tag: [t.name, t.quote], color: '#22863a' },
{ tag: [t.heading, t.strong], color: '#24292e', fontWeight: 'bold' },
{ tag: [t.emphasis], color: '#24292e', fontStyle: 'italic' },
{ tag: [t.deleted], color: '#b31d28', backgroundColor: 'ffeef0' },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#e36209' },
{ tag: [t.url, t.escape, t.regexp, t.link], color: '#032f62' },
{ tag: t.link, textDecoration: 'underline' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
{ tag: t.invalid, color: '#cb2431' },
],
});
-39
View File
@@ -1,39 +0,0 @@
/**
* @name Atom One
* Atom One dark syntax theme
*
* https://github.com/atom/one-dark-syntax
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
const hex = ['#000000', '#8ed675', '#56bd2a', '#54636D', '#171717'];
export const settings = {
background: hex[0],
lineBackground: 'transparent',
foreground: hex[2],
selection: hex[4],
selectionMatch: hex[0],
gutterBackground: hex[0],
gutterForeground: hex[3],
gutterBorder: 'transparent',
lineHighlight: hex[0],
};
export default createTheme({
theme: 'dark',
settings,
styles: [
{
tag: [t.function(t.variableName), t.function(t.propertyName), t.url, t.processingInstruction],
color: hex[2],
},
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: hex[1] },
{ tag: t.comment, color: hex[3] },
{ tag: [t.variableName, t.propertyName, t.labelName], color: hex[2] },
{ tag: [t.attributeName, t.number], color: hex[1] },
{ tag: t.keyword, color: hex[2] },
{ tag: [t.string, t.regexp, t.special(t.propertyName)], color: hex[1] },
],
});
-83
View File
@@ -1,83 +0,0 @@
/**
* @name gruvbox-dark
* @author morhetz
* Name: Gruvbox
* From github.com/codemirror/codemirror5/blob/master/theme/gruvbox-dark.css
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#282828',
lineBackground: '#28282899',
foreground: '#ebdbb2',
caret: '#ebdbb2',
selection: '#bdae93',
selectionMatch: '#bdae93',
lineHighlight: '#3c3836',
gutterBackground: '#282828',
gutterForeground: '#7c6f64',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#282828',
foreground: '#ebdbb2',
caret: '#ebdbb2',
selection: '#b99d555c',
selectionMatch: '#b99d555c',
lineHighlight: '#baa1602b',
gutterBackground: '#282828',
gutterForeground: '#7c6f64',
},
styles: [
{ tag: t.keyword, color: '#fb4934' },
{ tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName], color: '#8ec07c' },
{ tag: [t.variableName], color: '#83a598' },
{ tag: [t.function(t.variableName)], color: '#8ec07c', fontStyle: 'bold' },
{ tag: [t.labelName], color: '#ebdbb2' },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: '#d3869b' },
{ tag: [t.definition(t.name), t.separator], color: '#ebdbb2' },
{ tag: [t.brace], color: '#ebdbb2' },
{ tag: [t.annotation], color: '#fb4934d' },
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: '#d3869b' },
{ tag: [t.typeName, t.className], color: '#fabd2f' },
{ tag: [t.operatorKeyword], color: '#fb4934' },
{
tag: [t.tagName],
color: '#8ec07c',
fontStyle: 'bold',
},
{ tag: [t.squareBracket], color: '#fe8019' },
{ tag: [t.angleBracket], color: '#83a598' },
{ tag: [t.attributeName], color: '#8ec07c' },
{ tag: [t.regexp], color: '#8ec07c' },
{ tag: [t.quote], color: '#928374' },
{ tag: [t.string], color: '#ebdbb2' },
{
tag: t.link,
color: '#a89984',
textDecoration: 'underline',
textUnderlinePosition: 'under',
},
{ tag: [t.url, t.escape, t.special(t.string)], color: '#d3869b' },
{ tag: [t.meta], color: '#fabd2f' },
{ tag: [t.comment], color: '#928374', fontStyle: 'italic' },
{ tag: t.strong, fontWeight: 'bold', color: '#fe8019' },
{ tag: t.emphasis, fontStyle: 'italic', color: '#b8bb26' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
{ tag: t.heading, fontWeight: 'bold', color: '#b8bb26' },
{ tag: [t.heading1, t.heading2], fontWeight: 'bold', color: '#b8bb26' },
{
tag: [t.heading3, t.heading4],
fontWeight: 'bold',
color: '#fabd2f',
},
{ tag: [t.heading5, t.heading6], color: '#fabd2f' },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#d3869b' },
{ tag: [t.processingInstruction, t.inserted], color: '#83a598' },
{ tag: [t.contentSeparator], color: '#fb4934' },
{ tag: t.invalid, color: '#fe8019', borderBottom: `1px dotted #fb4934d` },
],
});
-131
View File
@@ -1,131 +0,0 @@
/**
* @name gruvbox-light
* @author morhetz
* Name: Gruvbox
* From github.com/codemirror/codemirror5/blob/master/theme/gruvbox-light.css
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
light: true,
background: '#fbf1c7',
lineBackground: '#fbf1c799',
foreground: '#3c3836',
caret: '#af3a03',
selection: '#ebdbb2',
selectionMatch: '#bdae93',
lineHighlight: '#ebdbb2',
gutterBackground: '#ebdbb2',
gutterForeground: '#665c54',
gutterBorder: 'transparent',
};
export default createTheme({
theme: 'light',
settings: {
background: '#fbf1c7',
foreground: '#3c3836',
caret: '#af3a03',
selection: '#bdae9391',
selectionMatch: '#bdae9391',
lineHighlight: '#a37f2238',
gutterBackground: '#ebdbb2',
gutterForeground: '#665c54',
gutterBorder: 'transparent',
},
styles: [
{ tag: t.keyword, color: '#9d0006' },
{
tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName],
color: '#427b58',
},
{ tag: [t.variableName], color: '#076678' },
{ tag: [t.function(t.variableName)], color: '#79740e', fontStyle: 'bold' },
{ tag: [t.labelName], color: '#3c3836' },
{
tag: [t.color, t.constant(t.name), t.standard(t.name)],
color: '#8f3f71',
},
{ tag: [t.definition(t.name), t.separator], color: '#3c3836' },
{ tag: [t.brace], color: '#3c3836' },
{
tag: [t.annotation],
color: '#9d0006',
},
{
tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace],
color: '#8f3f71',
},
{
tag: [t.typeName, t.className],
color: '#b57614',
},
{
tag: [t.operator, t.operatorKeyword],
color: '#9d0006',
},
{
tag: [t.tagName],
color: '#427b58',
fontStyle: 'bold',
},
{
tag: [t.squareBracket],
color: '#af3a03',
},
{
tag: [t.angleBracket],
color: '#076678',
},
{
tag: [t.attributeName],
color: '#427b58',
},
{
tag: [t.regexp],
color: '#427b58',
},
{
tag: [t.quote],
color: '#928374',
},
{ tag: [t.string], color: '#3c3836' },
{
tag: t.link,
color: '#7c6f64',
textDecoration: 'underline',
textUnderlinePosition: 'under',
},
{
tag: [t.url, t.escape, t.special(t.string)],
color: '#8f3f71',
},
{ tag: [t.meta], color: '#b57614' },
{ tag: [t.comment], color: '#928374', fontStyle: 'italic' },
{ tag: t.strong, fontWeight: 'bold', color: '#af3a03' },
{ tag: t.emphasis, fontStyle: 'italic', color: '#79740e' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
{ tag: t.heading, fontWeight: 'bold', color: '#79740e' },
{ tag: [t.heading1, t.heading2], fontWeight: 'bold', color: '#79740e' },
{
tag: [t.heading3, t.heading4],
fontWeight: 'bold',
color: '#b57614',
},
{
tag: [t.heading5, t.heading6],
color: '#b57614',
},
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#8f3f71' },
{
tag: [t.processingInstruction, t.inserted],
color: '#076678',
},
{
tag: [t.contentSeparator],
color: '#9d0006',
},
{ tag: t.invalid, color: '#af3a03', borderBottom: `1px dotted #9d0006` },
],
});
-77
View File
@@ -1,77 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#212121',
lineBackground: '#21212199',
foreground: '#bdbdbd',
caret: '#a0a4ae',
selection: '#d7d4f0',
selectionMatch: '#d7d4f0',
gutterBackground: '#212121',
gutterForeground: '#999',
gutterActiveForeground: '#4f5b66',
lineHighlight: '#111111',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#212121',
foreground: '#bdbdbd',
caret: '#a0a4ae',
selection: '#d7d4f063',
selectionMatch: '#d7d4f063',
gutterBackground: '#212121',
gutterForeground: '#999',
gutterActiveForeground: '#4f5b66',
lineHighlight: '#333333',
},
styles: [
{ tag: t.keyword, color: '#cf6edf' },
{ tag: [t.name, t.deleted, t.character, t.macroName], color: '#56c8d8' },
{ tag: [t.propertyName], color: '#82AAFF' },
{ tag: [t.variableName], color: '#bdbdbd' },
{ tag: [t.function(t.variableName)], color: '#82AAFF' },
{ tag: [t.labelName], color: '#cf6edf' },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: '#facf4e' },
{ tag: [t.definition(t.name), t.separator], color: '#56c8d8' },
{ tag: [t.brace], color: '#cf6edf' },
{ tag: [t.annotation], color: '#f07178' },
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: '#f07178' },
{ tag: [t.typeName, t.className], color: '#f07178' },
{ tag: [t.operator, t.operatorKeyword], color: '#82AAFF' },
{ tag: [t.tagName], color: '#99d066' },
{ tag: [t.squareBracket], color: '#f07178' },
{ tag: [t.angleBracket], color: '#606f7a' },
{ tag: [t.attributeName], color: '#bdbdbd' },
{ tag: [t.regexp], color: '#f07178' },
{ tag: [t.quote], color: '#6abf69' },
{ tag: [t.string], color: '#99d066' },
{
tag: t.link,
color: '#56c8d8',
textDecoration: 'underline',
textUnderlinePosition: 'under',
},
{ tag: [t.url, t.escape, t.special(t.string)], color: '#facf4e' },
{ tag: [t.meta], color: '#707d8b' },
{ tag: [t.comment], color: '#707d8b', fontStyle: 'italic' },
{ tag: t.monospace, color: '#bdbdbd' },
{ tag: t.strong, fontWeight: 'bold', color: '#f07178' },
{ tag: t.emphasis, fontStyle: 'italic', color: '#99d066' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
{ tag: t.heading, fontWeight: 'bold', color: '#facf4e' },
{ tag: t.heading1, fontWeight: 'bold', color: '#facf4e' },
{
tag: [t.heading2, t.heading3, t.heading4],
fontWeight: 'bold',
color: '#facf4e',
},
{ tag: [t.heading5, t.heading6], color: '#facf4e' },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#56c8d8' },
{ tag: [t.processingInstruction, t.inserted], color: '#f07178' },
{ tag: [t.contentSeparator], color: '#56c8d8' },
{ tag: t.invalid, color: '#606f7a', borderBottom: `1px dotted #f07178` },
],
});
-52
View File
@@ -1,52 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
light: true,
background: '#FAFAFA',
lineBackground: '#FAFAFA99',
foreground: '#90A4AE',
caret: '#272727',
selection: '#80CBC440',
selectionMatch: '#FAFAFA',
gutterBackground: '#FAFAFA',
gutterForeground: '#90A4AE',
gutterBorder: 'transparent',
lineHighlight: '#CCD7DA50',
};
export default createTheme({
theme: 'light',
settings: {
background: '#FAFAFA',
foreground: '#90A4AE',
caret: '#272727',
selection: '#80CBC440',
selectionMatch: '#80CBC440',
gutterBackground: '#FAFAFA',
gutterForeground: '#90A4AE',
gutterBorder: 'transparent',
lineHighlight: '#CCD7DA50',
},
styles: [
{ tag: t.keyword, color: '#39ADB5' },
{ tag: [t.name, t.deleted, t.character, t.macroName], color: '#90A4AE' },
{ tag: [t.propertyName], color: '#6182B8' },
{ tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: '#91B859' },
{ tag: [t.function(t.variableName), t.labelName], color: '#6182B8' },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: '#39ADB5' },
{ tag: [t.definition(t.name), t.separator], color: '#90A4AE' },
{ tag: [t.className], color: '#E2931D' },
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: '#F76D47' },
{ tag: [t.typeName], color: '#E2931D', fontStyle: '#E2931D' },
{ tag: [t.operator, t.operatorKeyword], color: '#39ADB5' },
{ tag: [t.url, t.escape, t.regexp, t.link], color: '#91B859' },
{ tag: [t.meta, t.comment], color: '#90A4AE' },
{ tag: t.strong, fontWeight: 'bold' },
{ tag: t.emphasis, fontStyle: 'italic' },
{ tag: t.link, textDecoration: 'underline' },
{ tag: t.heading, fontWeight: 'bold', color: '#39ADB5' },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#90A4AE' },
{ tag: t.invalid, color: '#E5393570' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
],
});
-45
View File
@@ -1,45 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#272822',
lineBackground: '#27282299',
foreground: '#FFFFFF',
caret: '#FFFFFF',
selection: '#49483E',
selectionMatch: '#49483E',
gutterBackground: '#272822',
gutterForeground: '#FFFFFF70',
lineHighlight: '#00000059',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#272822',
foreground: '#FFFFFF',
caret: '#FFFFFF',
selection: '#49483E',
selectionMatch: '#49483E',
gutterBackground: '#272822',
gutterForeground: '#FFFFFF70',
lineHighlight: '#0000003b',
},
styles: [
{ tag: t.labelName, color: '#bababa' },
{ tag: [t.comment, t.documentMeta], color: '#8292a2' },
{ tag: [t.number, t.bool, t.null, t.atom], color: '#ae81ff' },
{ tag: [t.attributeValue, t.className, t.name], color: '#e6db74' },
{ tag: [t.propertyName, t.attributeName], color: '#a6e22e' },
{ tag: [t.variableName], color: '#9effff' },
{ tag: [t.squareBracket], color: '#bababa' },
{ tag: [t.string, t.special(t.brace)], color: '#e6db74' },
{ tag: [t.regexp, t.className, t.typeName, t.definition(t.typeName)], color: '#66d9ef' },
{
tag: [t.definition(t.variableName), t.definition(t.propertyName), t.function(t.variableName)],
color: '#a6e22e',
},
// { tag: t.keyword, color: '#f92672' },
{ tag: [t.keyword, t.definitionKeyword, t.modifier, t.tagName, t.angleBracket], color: '#f92672' },
],
});
-50
View File
@@ -1,50 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
light: true,
background: '#f2f1f8',
lineBackground: '#f2f1f899',
foreground: '#0c006b',
caret: '#5c49e9',
selection: '#d5d1f2',
selectionMatch: '#d5d1f2',
gutterBackground: '#f2f1f8',
gutterForeground: '#0c006b70',
lineHighlight: '#e1def3',
};
export default createTheme({
theme: 'light',
settings: {
background: '#f2f1f8',
foreground: '#0c006b',
caret: '#5c49e9',
selection: '#d5d1f2',
selectionMatch: '#d5d1f2',
gutterBackground: '#f2f1f8',
gutterForeground: '#0c006b70',
lineHighlight: '#16067911',
},
styles: [
{ tag: t.comment, color: '#9995b7' },
{
tag: t.keyword,
color: '#ff5792',
fontWeight: 'bold',
},
{ tag: [t.definitionKeyword, t.modifier], color: '#ff5792' },
{ tag: [t.className, t.tagName, t.definition(t.typeName)], color: '#0094f0' },
{ tag: [t.number, t.bool, t.null, t.special(t.brace)], color: '#5842ff' },
{ tag: [t.definition(t.propertyName), t.function(t.variableName)], color: '#0095a8' },
{ tag: t.typeName, color: '#b3694d' },
{ tag: [t.propertyName, t.variableName], color: '#fa8900' },
{ tag: t.operator, color: '#ff5792' },
{ tag: t.self, color: '#e64100' },
{ tag: [t.string, t.regexp], color: '#00b368' },
{ tag: [t.paren, t.bracket], color: '#0431fa' },
{ tag: t.labelName, color: '#00bdd6' },
{ tag: t.attributeName, color: '#e64100' },
{ tag: t.angleBracket, color: '#9995b7' },
],
});
-78
View File
@@ -1,78 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#2e3440',
lineBackground: '#2e344099',
foreground: '#FFFFFF',
caret: '#FFFFFF',
selection: '#3b4252',
selectionMatch: '#e5e9f0',
gutterBackground: '#2e3440',
gutterForeground: '#4c566a',
gutterActiveForeground: '#d8dee9',
lineHighlight: '#4c566a',
};
// Colors from https://www.nordtheme.com/docs/colors-and-palettes
export default createTheme({
theme: 'dark',
settings: {
background: '#2e3440',
foreground: '#FFFFFF',
caret: '#FFFFFF',
selection: '#00000073',
selectionMatch: '#00000073',
gutterBackground: '#2e3440',
gutterForeground: '#4c566a',
gutterActiveForeground: '#d8dee9',
lineHighlight: '#4c566a29',
},
styles: [
{ tag: t.keyword, color: '#5e81ac' },
{ tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName], color: '#88c0d0' },
{ tag: [t.variableName], color: '#8fbcbb' },
{ tag: [t.function(t.variableName)], color: '#8fbcbb' },
{ tag: [t.labelName], color: '#81a1c1' },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: '#5e81ac' },
{ tag: [t.definition(t.name), t.separator], color: '#a3be8c' },
{ tag: [t.brace], color: '#8fbcbb' },
{ tag: [t.annotation], color: '#d30102' },
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: '#b48ead' },
{ tag: [t.typeName, t.className], color: '#ebcb8b' },
{ tag: [t.operator, t.operatorKeyword], color: '#a3be8c' },
{ tag: [t.tagName], color: '#b48ead' },
{ tag: [t.squareBracket], color: '#bf616a' },
{ tag: [t.angleBracket], color: '#d08770' },
{ tag: [t.attributeName], color: '#ebcb8b' },
{ tag: [t.regexp], color: '#5e81ac' },
{ tag: [t.quote], color: '#b48ead' },
{ tag: [t.string], color: '#a3be8c' },
{
tag: t.link,
color: '#a3be8c',
textDecoration: 'underline',
textUnderlinePosition: 'under',
},
{ tag: [t.url, t.escape, t.special(t.string)], color: '#8fbcbb' },
{ tag: [t.meta], color: '#88c0d0' },
{ tag: [t.monospace], color: '#d8dee9', fontStyle: 'italic' },
{ tag: [t.comment], color: '#4c566a', fontStyle: 'italic' },
{ tag: t.strong, fontWeight: 'bold', color: '#5e81ac' },
{ tag: t.emphasis, fontStyle: 'italic', color: '#5e81ac' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
{ tag: t.heading, fontWeight: 'bold', color: '#5e81ac' },
{ tag: t.special(t.heading1), fontWeight: 'bold', color: '#5e81ac' },
{ tag: t.heading1, fontWeight: 'bold', color: '#5e81ac' },
{
tag: [t.heading2, t.heading3, t.heading4],
fontWeight: 'bold',
color: '#5e81ac',
},
{ tag: [t.heading5, t.heading6], color: '#5e81ac' },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#d08770' },
{ tag: [t.processingInstruction, t.inserted], color: '#8fbcbb' },
{ tag: [t.contentSeparator], color: '#ebcb8b' },
{ tag: t.invalid, color: '#434c5e', borderBottom: `1px dotted #d30102` },
],
});
-39
View File
@@ -1,39 +0,0 @@
/**
* @name Atom One
* Atom One dark syntax theme
*
* https://github.com/atom/one-dark-syntax
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
const hex = ['#000000', '#ff5356', '#bd312a', '#54636D', '#171717'];
export const settings = {
background: hex[0],
lineBackground: 'transparent',
foreground: hex[2],
selection: hex[4],
selectionMatch: hex[0],
gutterBackground: hex[0],
gutterForeground: hex[3],
gutterBorder: 'transparent',
lineHighlight: hex[0],
};
export default createTheme({
theme: 'dark',
settings,
styles: [
{
tag: [t.function(t.variableName), t.function(t.propertyName), t.url, t.processingInstruction],
color: hex[2],
},
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: hex[1] },
{ tag: t.comment, color: hex[3] },
{ tag: [t.variableName, t.propertyName, t.labelName], color: hex[2] },
{ tag: [t.attributeName, t.number], color: hex[1] },
{ tag: t.keyword, color: hex[2] },
{ tag: [t.string, t.regexp, t.special(t.propertyName)], color: hex[1] },
],
});
-79
View File
@@ -1,79 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#002b36',
lineBackground: '#002b3699',
foreground: '#93a1a1',
caret: '#839496',
selection: '#173541',
selectionMatch: '#aafe661a',
gutterBackground: '#00252f',
gutterForeground: '#839496',
lineHighlight: '#173541',
};
const c = {
background: '#002B36',
foreground: '#839496',
selection: '#004454AA',
selectionMatch: '#005A6FAA',
cursor: '#D30102',
dropdownBackground: '#00212B',
dropdownBorder: '#2AA19899',
activeLine: '#00cafe11',
matchingBracket: '#073642',
keyword: '#859900',
storage: '#93A1A1',
variable: '#268BD2',
parameter: '#268BD2',
function: '#268BD2',
string: '#2AA198',
constant: '#CB4B16',
type: '#859900',
class: '#268BD2',
number: '#D33682',
comment: '#586E75',
heading: '#268BD2',
invalid: '#DC322F',
regexp: '#DC322F',
tag: '#268BD2',
};
export default createTheme({
theme: 'dark',
settings: {
background: c.background,
foreground: c.foreground,
caret: c.cursor,
selection: c.selection,
selectionMatch: c.selection,
gutterBackground: c.background,
gutterForeground: c.foreground,
gutterBorder: 'transparent',
lineHighlight: c.activeLine,
},
styles: [
{ tag: t.keyword, color: c.keyword },
{ tag: [t.name, t.deleted, t.character, t.macroName], color: c.variable },
{ tag: [t.propertyName], color: c.function },
{ tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: c.string },
{ tag: [t.function(t.variableName), t.labelName], color: c.function },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: c.constant },
{ tag: [t.definition(t.name), t.separator], color: c.variable },
{ tag: [t.className], color: c.class },
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: c.number },
{ tag: [t.typeName], color: c.type, fontStyle: c.type },
{ tag: [t.operator, t.operatorKeyword], color: c.keyword },
{ tag: [t.url, t.escape, t.regexp, t.link], color: c.regexp },
{ tag: [t.meta, t.comment], color: c.comment },
{ tag: t.tagName, color: c.tag },
{ tag: t.strong, fontWeight: 'bold' },
{ tag: t.emphasis, fontStyle: 'italic' },
{ tag: t.link, textDecoration: 'underline' },
{ tag: t.heading, fontWeight: 'bold', color: c.heading },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: c.variable },
{ tag: t.invalid, color: c.invalid },
{ tag: t.strikethrough, textDecoration: 'line-through' },
],
});
-82
View File
@@ -1,82 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
// this is slightly different from https://thememirror.net/solarized-light
export const settings = {
light: true,
background: '#fdf6e3',
lineBackground: '#fdf6e399',
foreground: '#657b83',
caret: '#586e75',
selection: '#dfd9c8',
selectionMatch: '#dfd9c8',
gutterBackground: '#00000010',
gutterForeground: '#657b83',
lineHighlight: '#dfd9c8',
};
const c = {
background: '#FDF6E3',
foreground: '#657B83',
selection: '#EEE8D5',
selectionMatch: '#EEE8D5',
cursor: '#657B83',
dropdownBackground: '#EEE8D5',
dropdownBorder: '#D3AF86',
activeLine: '#3d392d11',
matchingBracket: '#EEE8D5',
keyword: '#859900',
storage: '#586E75',
variable: '#268BD2',
parameter: '#268BD2',
function: '#268BD2',
string: '#2AA198',
constant: '#CB4B16',
type: '#859900',
class: '#268BD2',
number: '#D33682',
comment: '#93A1A1',
heading: '#268BD2',
invalid: '#DC322F',
regexp: '#DC322F',
tag: '#268BD2',
};
export default createTheme({
theme: 'light',
settings: {
background: c.background,
foreground: c.foreground,
caret: c.cursor,
selection: c.selection,
selectionMatch: c.selectionMatch,
gutterBackground: c.background,
gutterForeground: c.foreground,
gutterBorder: 'transparent',
lineHighlight: c.activeLine,
},
styles: [
{ tag: t.keyword, color: c.keyword },
{ tag: [t.name, t.deleted, t.character, t.macroName], color: c.variable },
{ tag: [t.propertyName], color: c.function },
{ tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: c.string },
{ tag: [t.function(t.variableName), t.labelName], color: c.function },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: c.constant },
{ tag: [t.definition(t.name), t.separator], color: c.variable },
{ tag: [t.className], color: c.class },
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: c.number },
{ tag: [t.typeName], color: c.type, fontStyle: c.type },
{ tag: [t.operator, t.operatorKeyword], color: c.keyword },
{ tag: [t.url, t.escape, t.regexp, t.link], color: c.regexp },
{ tag: [t.meta, t.comment], color: c.comment },
{ tag: t.tagName, color: c.tag },
{ tag: t.strong, fontWeight: 'bold' },
{ tag: t.emphasis, fontStyle: 'italic' },
{ tag: t.link, textDecoration: 'underline' },
{ tag: t.heading, fontWeight: 'bold', color: c.heading },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: c.variable },
{ tag: t.invalid, color: c.invalid },
{ tag: t.strikethrough, textDecoration: 'line-through' },
],
});
-39
View File
@@ -1,39 +0,0 @@
/**
* @name Atom One
* Atom One dark syntax theme
*
* https://github.com/atom/one-dark-syntax
*/
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
const hex = ['#1e1e1e', '#fbde2d', '#ff1493', '#4c83ff', '#ededed', '#cccccc', '#ffffff30', '#dc2f8c'];
export const settings = {
background: '#000000',
lineBackground: 'transparent',
foreground: hex[4],
selection: hex[6],
gutterBackground: hex[0],
gutterForeground: hex[5],
gutterBorder: 'transparent',
lineHighlight: hex[0],
};
export default createTheme({
theme: 'dark',
settings,
styles: [
{
tag: [t.function(t.variableName), t.function(t.propertyName), t.url, t.processingInstruction],
color: hex[4],
},
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: hex[3] },
{ tag: t.comment, color: '#54636D' },
{ tag: [t.variableName, t.propertyName, t.labelName], color: hex[4] },
{ tag: [t.attributeName, t.number], color: hex[3] },
{ tag: t.keyword, color: hex[1] },
{ tag: [t.string, t.regexp, t.special(t.propertyName)], color: hex[2] },
],
});
+8 -12
View File
@@ -1,24 +1,20 @@
import { tags as t } from '@lezer/highlight'; import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs'; import { createTheme } from '@uiw/codemirror-themes';
export default createTheme({
export const settings = { theme: 'dark',
settings: {
background: '#222', background: '#222',
lineBackground: '#22222299', foreground: '#75baff', // whats that?
foreground: '#fff',
caret: '#ffcc00', caret: '#ffcc00',
selection: 'rgba(128, 203, 196, 0.5)', selection: 'rgba(128, 203, 196, 0.5)',
selectionMatch: '#036dd626', selectionMatch: '#036dd626',
// lineHighlight: '#8a91991a', // original
lineHighlight: '#00000050', lineHighlight: '#00000050',
gutterBackground: 'transparent', gutterBackground: 'transparent',
// gutterForeground: '#8a919966',
gutterForeground: '#8a919966', gutterForeground: '#8a919966',
}; },
export default createTheme({
theme: 'dark',
settings,
styles: [ styles: [
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#89ddff' },
{ tag: t.labelName, color: '#89ddff' },
{ tag: t.keyword, color: '#c792ea' }, { tag: t.keyword, color: '#c792ea' },
{ tag: t.operator, color: '#89ddff' }, { tag: t.operator, color: '#89ddff' },
{ tag: t.special(t.variableName), color: '#eeffff' }, { tag: t.special(t.variableName), color: '#eeffff' },
-43
View File
@@ -1,43 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#303841',
lineBackground: '#30384199',
foreground: '#FFFFFF',
caret: '#FBAC52',
selection: '#4C5964',
selectionMatch: '#3A546E',
gutterBackground: '#303841',
gutterForeground: '#FFFFFF70',
lineHighlight: '#00000059',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#303841',
foreground: '#FFFFFF',
caret: '#FBAC52',
selection: '#4C5964',
selectionMatch: '#3A546E',
gutterBackground: '#303841',
gutterForeground: '#FFFFFF70',
lineHighlight: '#00000059',
},
styles: [
{ tag: t.labelName, color: '#A2A9B5' },
{ tag: [t.meta, t.comment], color: '#A2A9B5' },
{ tag: [t.attributeName, t.keyword], color: '#B78FBA' },
{ tag: t.function(t.variableName), color: '#5AB0B0' },
{ tag: [t.string, t.regexp, t.attributeValue], color: '#99C592' },
{ tag: t.operator, color: '#f47954' },
// { tag: t.moduleKeyword, color: 'red' },
{ tag: [t.tagName, t.modifier], color: '#E35F63' },
{ tag: [t.number, t.definition(t.tagName), t.className, t.definition(t.variableName)], color: '#fbac52' },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#E35F63' },
{ tag: t.variableName, color: '#539ac4' },
{ tag: [t.propertyName, t.typeName], color: '#629ccd' },
{ tag: t.propertyName, color: '#36b7b5' },
],
});
+2 -3
View File
@@ -1,5 +1,5 @@
import { tags as t } from '@lezer/highlight'; import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs'; import { createTheme } from '@uiw/codemirror-themes';
let colorA = '#6edee4'; let colorA = '#6edee4';
//let colorB = 'magenta'; //let colorB = 'magenta';
@@ -17,7 +17,7 @@ export const settings = {
lineBackground: '#00000040', lineBackground: '#00000040',
gutterBackground: 'transparent', gutterBackground: 'transparent',
gutterForeground: '#8a919966', gutterForeground: '#8a919966',
// customStyle: '.cm-line { line-height: 1 }', customStyle: '.cm-line { line-height: 1 }',
}; };
let punctuation = colorD; let punctuation = colorD;
@@ -27,7 +27,6 @@ export default createTheme({
theme: 'dark', theme: 'dark',
settings, settings,
styles: [ styles: [
{ tag: t.labelName, color: colorB },
{ tag: t.keyword, color: colorA }, { tag: t.keyword, color: colorA },
{ tag: t.operator, color: mini }, { tag: t.operator, color: mini },
{ tag: t.special(t.variableName), color: colorA }, { tag: t.special(t.variableName), color: colorA },
+19 -20
View File
@@ -1,5 +1,5 @@
import { tags as t } from '@lezer/highlight'; import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs'; import { createTheme } from '@uiw/codemirror-themes';
export const settings = { export const settings = {
background: 'black', background: 'black',
foreground: '#41FF00', // whats that? foreground: '#41FF00', // whats that?
@@ -14,24 +14,23 @@ export default createTheme({
theme: 'dark', theme: 'dark',
settings, settings,
styles: [ styles: [
{ tag: t.labelName, color: 'inherit' }, { tag: t.keyword, color: '#41FF00' },
{ tag: t.keyword, color: 'inherit' }, { tag: t.operator, color: '#41FF00' },
{ tag: t.operator, color: 'inherit' }, { tag: t.special(t.variableName), color: '#41FF00' },
{ tag: t.special(t.variableName), color: 'inherit' }, { tag: t.typeName, color: '#41FF00' },
{ tag: t.typeName, color: 'inherit' }, { tag: t.atom, color: '#41FF00' },
{ tag: t.atom, color: 'inherit' }, { tag: t.number, color: '#41FF00' },
{ tag: t.number, color: 'inherit' }, { tag: t.definition(t.variableName), color: '#41FF00' },
{ tag: t.definition(t.variableName), color: 'inherit' }, { tag: t.string, color: '#41FF00' },
{ tag: t.string, color: 'inherit' }, { tag: t.special(t.string), color: '#41FF00' },
{ tag: t.special(t.string), color: 'inherit' }, { tag: t.comment, color: '#41FF00' },
{ tag: t.comment, color: 'inherit' }, { tag: t.variableName, color: '#41FF00' },
{ tag: t.variableName, color: 'inherit' }, { tag: t.tagName, color: '#41FF00' },
{ tag: t.tagName, color: 'inherit' }, { tag: t.bracket, color: '#41FF00' },
{ tag: t.bracket, color: 'inherit' }, { tag: t.meta, color: '#41FF00' },
{ tag: t.meta, color: 'inherit' }, { tag: t.attributeName, color: '#41FF00' },
{ tag: t.attributeName, color: 'inherit' }, { tag: t.propertyName, color: '#41FF00' },
{ tag: t.propertyName, color: 'inherit' }, { tag: t.className, color: '#41FF00' },
{ tag: t.className, color: 'inherit' }, { tag: t.invalid, color: '#41FF00' },
{ tag: t.invalid, color: 'inherit' },
], ],
}); });
-42
View File
@@ -1,42 +0,0 @@
import { EditorView } from '@codemirror/view';
import { syntaxHighlighting } from '@codemirror/language';
import { HighlightStyle } from '@codemirror/language';
export const createTheme = ({ theme, settings, styles }) => {
const _theme = EditorView.theme(
{
'&': {
color: settings.foreground,
backgroundColor: settings.background,
},
'.cm-gutters': {
backgroundColor: settings.gutterBackground,
color: settings.gutterForeground,
//borderRightColor: settings.gutterBorder
},
'.cm-content': {
caretColor: settings.caret,
},
'.cm-cursor, .cm-dropCursor': {
borderLeftColor: settings.caret,
},
'.cm-activeLineGutter': {
// color: settings.gutterActiveForeground
backgroundColor: settings.lineHighlight,
},
'.cm-activeLine': {
backgroundColor: settings.lineHighlight,
},
'&.cm-focused .cm-selectionBackground, & .cm-line::selection, & .cm-selectionLayer .cm-selectionBackground, .cm-content ::selection':
{
background: settings.selection + ' !important',
},
'& .cm-selectionMatch': {
backgroundColor: settings.selectionMatch,
},
},
{ dark: theme === 'dark' },
);
const highlightStyle = HighlightStyle.define(styles);
return [_theme, syntaxHighlighting(highlightStyle)];
};
-52
View File
@@ -1,52 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#24283b',
lineBackground: '#24283b99',
foreground: '#7982a9',
caret: '#c0caf5',
selection: '#6f7bb630',
selectionMatch: '#1f2335',
gutterBackground: '#24283b',
gutterForeground: '#7982a9',
gutterBorder: 'transparent',
lineHighlight: '#292e42',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#24283b',
foreground: '#7982a9',
caret: '#c0caf5',
selection: '#6f7bb630',
selectionMatch: '#343b5f',
gutterBackground: '#24283b',
gutterForeground: '#7982a9',
gutterBorder: 'transparent',
lineHighlight: '#292e427a',
},
styles: [
{ tag: t.keyword, color: '#bb9af7' },
{ tag: [t.name, t.deleted, t.character, t.macroName], color: '#c0caf5' },
{ tag: [t.propertyName], color: '#7aa2f7' },
{ tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: '#9ece6a' },
{ tag: [t.function(t.variableName), t.labelName], color: '#7aa2f7' },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: '#bb9af7' },
{ tag: [t.definition(t.name), t.separator], color: '#c0caf5' },
{ tag: [t.className], color: '#c0caf5' },
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: '#ff9e64' },
{ tag: [t.typeName], color: '#2ac3de', fontStyle: '#2ac3de' },
{ tag: [t.operator, t.operatorKeyword], color: '#bb9af7' },
{ tag: [t.url, t.escape, t.regexp, t.link], color: '#b4f9f8' },
{ tag: [t.meta, t.comment], color: '#565f89' },
{ tag: t.strong, fontWeight: 'bold' },
{ tag: t.emphasis, fontStyle: 'italic' },
{ tag: t.link, textDecoration: 'underline' },
{ tag: t.heading, fontWeight: 'bold', color: '#89ddff' },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#c0caf5' },
{ tag: t.invalid, color: '#ff5370' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
],
});
-52
View File
@@ -1,52 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#1a1b26',
lineBackground: '#1a1b2699',
foreground: '#787c99',
caret: '#c0caf5',
selection: '#515c7e40',
selectionMatch: '#16161e',
gutterBackground: '#1a1b26',
gutterForeground: '#787c99',
gutterBorder: 'transparent',
lineHighlight: '#1e202e',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#1a1b26',
foreground: '#787c99',
caret: '#c0caf5',
selection: '#515c7e40',
selectionMatch: '#16161e',
gutterBackground: '#1a1b26',
gutterForeground: '#787c99',
gutterBorder: 'transparent',
lineHighlight: '#474b6611',
},
styles: [
{ tag: t.keyword, color: '#bb9af7' },
{ tag: [t.name, t.deleted, t.character, t.macroName], color: '#c0caf5' },
{ tag: [t.propertyName], color: '#7aa2f7' },
{ tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: '#9ece6a' },
{ tag: [t.function(t.variableName), t.labelName], color: '#7aa2f7' },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: '#bb9af7' },
{ tag: [t.definition(t.name), t.separator], color: '#c0caf5' },
{ tag: [t.className], color: '#c0caf5' },
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: '#ff9e64' },
{ tag: [t.typeName], color: '#0db9d7' },
{ tag: [t.operator, t.operatorKeyword], color: '#bb9af7' },
{ tag: [t.url, t.escape, t.regexp, t.link], color: '#b4f9f8' },
{ tag: [t.meta, t.comment], color: '#444b6a' },
{ tag: t.strong, fontWeight: 'bold' },
{ tag: t.emphasis, fontStyle: 'italic' },
{ tag: t.link, textDecoration: 'underline' },
{ tag: t.heading, fontWeight: 'bold', color: '#89ddff' },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#c0caf5' },
{ tag: t.invalid, color: '#ff5370' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
],
});
-53
View File
@@ -1,53 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
light: true,
background: '#e1e2e7',
lineBackground: '#e1e2e799',
foreground: '#3760bf',
caret: '#3760bf',
selection: '#99a7df',
selectionMatch: '#99a7df',
gutterBackground: '#e1e2e7',
gutterForeground: '#3760bf',
gutterBorder: 'transparent',
lineHighlight: '#5f5faf11',
};
export default createTheme({
theme: 'light',
settings: {
background: '#e1e2e7',
foreground: '#3760bf',
caret: '#3760bf',
selection: '#99a7df',
selectionMatch: '#99a7df',
gutterBackground: '#e1e2e7',
gutterForeground: '#3760bf',
gutterBorder: 'transparent',
lineHighlight: '#5f5faf11',
},
styles: [
{ tag: t.keyword, color: '#007197' },
{ tag: [t.name, t.deleted, t.character, t.macroName], color: '#3760bf' },
{ tag: [t.propertyName], color: '#3760bf' },
{ tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: '#587539' },
{ tag: [t.function(t.variableName), t.labelName], color: '#3760bf' },
{ tag: [t.color, t.constant(t.name), t.standard(t.name)], color: '#3760bf' },
{ tag: [t.definition(t.name), t.separator], color: '#3760bf' },
{ tag: [t.className], color: '#3760bf' },
{ tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: '#b15c00' },
{ tag: [t.typeName], color: '#007197', fontStyle: '#007197' },
{ tag: [t.operator, t.operatorKeyword], color: '#007197' },
{ tag: [t.url, t.escape, t.regexp, t.link], color: '#587539' },
{ tag: [t.meta, t.comment], color: '#848cb5' },
{ tag: t.strong, fontWeight: 'bold' },
{ tag: t.emphasis, fontStyle: 'italic' },
{ tag: t.link, textDecoration: 'underline' },
{ tag: t.heading, fontWeight: 'bold', color: '#b15c00' },
{ tag: [t.atom, t.bool, t.special(t.variableName)], color: '#3760bf' },
{ tag: t.invalid, color: '#f52a65' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
],
});
-80
View File
@@ -1,80 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#1e1e1e',
lineBackground: '#1e1e1e99',
foreground: '#fff',
caret: '#c6c6c6',
selection: '#6199ff2f',
selectionMatch: '#72a1ff59',
lineHighlight: '#ffffff0f',
gutterBackground: '#1e1e1e',
gutterForeground: '#838383',
gutterActiveForeground: '#fff',
};
export default createTheme({
theme: 'dark',
settings: {
background: '#1e1e1e',
foreground: '#fff',
caret: '#c6c6c6',
selection: '#6199ff2f',
selectionMatch: '#72a1ff59',
lineHighlight: '#ffffff0f',
gutterBackground: '#1e1e1e',
gutterForeground: '#838383',
gutterActiveForeground: '#fff',
fontFamily: 'Menlo, Monaco, Consolas, "Andale Mono", "Ubuntu Mono", "Courier New", monospace',
},
styles: [
{
tag: [
t.keyword,
t.operatorKeyword,
t.modifier,
t.color,
t.constant(t.name),
t.standard(t.name),
t.standard(t.tagName),
t.special(t.brace),
t.atom,
t.bool,
t.special(t.variableName),
],
color: '#569cd6',
},
{ tag: [t.controlKeyword, t.moduleKeyword], color: '#c586c0' },
{
tag: [
t.name,
t.deleted,
t.character,
t.macroName,
t.propertyName,
t.variableName,
t.labelName,
t.definition(t.name),
],
color: '#9cdcfe',
},
{ tag: t.heading, fontWeight: 'bold', color: '#9cdcfe' },
{
tag: [t.typeName, t.className, t.tagName, t.number, t.changed, t.annotation, t.self, t.namespace],
color: '#4ec9b0',
},
{ tag: [t.function(t.variableName), t.function(t.propertyName)], color: '#dcdcaa' },
{ tag: [t.number], color: '#b5cea8' },
{ tag: [t.operator, t.punctuation, t.separator, t.url, t.escape, t.regexp], color: '#d4d4d4' },
{ tag: [t.regexp], color: '#d16969' },
{ tag: [t.special(t.string), t.processingInstruction, t.string, t.inserted], color: '#ce9178' },
{ tag: [t.angleBracket], color: '#808080' },
{ tag: t.strong, fontWeight: 'bold' },
{ tag: t.emphasis, fontStyle: 'italic' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
{ tag: [t.meta, t.comment], color: '#6a9955' },
{ tag: t.link, color: '#6a9955', textDecoration: 'underline' },
{ tag: t.invalid, color: '#ff0000' },
],
});
-81
View File
@@ -1,81 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
background: '#ffffff',
lineBackground: '#ffffff50',
foreground: '#383a42',
caret: '#000',
selection: '#add6ff',
selectionMatch: '#a8ac94',
lineHighlight: '#99999926',
gutterBackground: '#fff',
gutterForeground: '#237893',
gutterActiveForeground: '#0b216f',
fontFamily: 'Menlo, Monaco, Consolas, "Andale Mono", "Ubuntu Mono", "Courier New", monospace',
};
export default createTheme({
theme: 'light',
settings: {
background: '#ffffff',
foreground: '#383a42',
caret: '#000',
selection: '#add6ff',
selectionMatch: '#a8ac94',
lineHighlight: '#99999926',
gutterBackground: '#fff',
gutterForeground: '#237893',
gutterActiveForeground: '#0b216f',
fontFamily: 'Menlo, Monaco, Consolas, "Andale Mono", "Ubuntu Mono", "Courier New", monospace',
},
styles: [
{
tag: [
t.keyword,
t.operatorKeyword,
t.modifier,
t.color,
t.constant(t.name),
t.standard(t.name),
t.standard(t.tagName),
t.special(t.brace),
t.atom,
t.bool,
t.special(t.variableName),
],
color: '#0000ff',
},
{ tag: [t.moduleKeyword, t.controlKeyword], color: '#af00db' },
{
tag: [
t.name,
t.deleted,
t.character,
t.macroName,
t.propertyName,
t.variableName,
t.labelName,
t.definition(t.name),
],
color: '#0070c1',
},
{ tag: t.heading, fontWeight: 'bold', color: '#0070c1' },
{
tag: [t.typeName, t.className, t.tagName, t.number, t.changed, t.annotation, t.self, t.namespace],
color: '#267f99',
},
{ tag: [t.function(t.variableName), t.function(t.propertyName)], color: '#795e26' },
{ tag: [t.number], color: '#098658' },
{ tag: [t.operator, t.punctuation, t.separator, t.url, t.escape, t.regexp], color: '#383a42' },
{ tag: [t.regexp], color: '#af00db' },
{ tag: [t.special(t.string), t.processingInstruction, t.string, t.inserted], color: '#a31515' },
{ tag: [t.angleBracket], color: '#383a42' },
{ tag: t.strong, fontWeight: 'bold' },
{ tag: t.emphasis, fontStyle: 'italic' },
{ tag: t.strikethrough, textDecoration: 'line-through' },
{ tag: [t.meta, t.comment], color: '#008000' },
{ tag: t.link, color: '#4078f2', textDecoration: 'underline' },
{ tag: t.invalid, color: '#e45649' },
],
});
+19 -20
View File
@@ -1,5 +1,5 @@
import { tags as t } from '@lezer/highlight'; import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs'; import { createTheme } from '@uiw/codemirror-themes';
export const settings = { export const settings = {
background: 'white', background: 'white',
foreground: 'black', // whats that? foreground: 'black', // whats that?
@@ -16,24 +16,23 @@ export default createTheme({
theme: 'light', theme: 'light',
settings, settings,
styles: [ styles: [
{ tag: t.labelName, color: 'inherit' }, { tag: t.keyword, color: 'black' },
{ tag: t.keyword, color: 'inherit' }, { tag: t.operator, color: 'black' },
{ tag: t.operator, color: 'inherit' }, { tag: t.special(t.variableName), color: 'black' },
{ tag: t.special(t.variableName), color: 'inherit' }, { tag: t.typeName, color: 'black' },
{ tag: t.typeName, color: 'inherit' }, { tag: t.atom, color: 'black' },
{ tag: t.atom, color: 'inherit' }, { tag: t.number, color: 'black' },
{ tag: t.number, color: 'inherit' }, { tag: t.definition(t.variableName), color: 'black' },
{ tag: t.definition(t.variableName), color: 'inherit' }, { tag: t.string, color: 'black' },
{ tag: t.string, color: 'inherit' }, { tag: t.special(t.string), color: 'black' },
{ tag: t.special(t.string), color: 'inherit' }, { tag: t.comment, color: 'black' },
{ tag: t.comment, color: 'inherit' }, { tag: t.variableName, color: 'black' },
{ tag: t.variableName, color: 'inherit' }, { tag: t.tagName, color: 'black' },
{ tag: t.tagName, color: 'inherit' }, { tag: t.bracket, color: 'black' },
{ tag: t.bracket, color: 'inherit' }, { tag: t.meta, color: 'black' },
{ tag: t.meta, color: 'inherit' }, { tag: t.attributeName, color: 'black' },
{ tag: t.attributeName, color: 'inherit' }, { tag: t.propertyName, color: 'black' },
{ tag: t.propertyName, color: 'inherit' }, { tag: t.className, color: 'black' },
{ tag: t.className, color: 'inherit' }, { tag: t.invalid, color: 'black' },
{ tag: t.invalid, color: 'inherit' },
], ],
}); });
-38
View File
@@ -1,38 +0,0 @@
import { tags as t } from '@lezer/highlight';
import { createTheme } from './theme-helper.mjs';
export const settings = {
light: true,
background: '#fff',
lineBackground: '#ffffff99',
foreground: '#3D3D3D',
selection: '#BBDFFF',
selectionMatch: '#BBDFFF',
gutterBackground: '#fff',
gutterForeground: '#AFAFAF',
lineHighlight: '#EDF4FF',
};
export default createTheme({
theme: 'light',
settings: {
background: '#fff',
foreground: '#3D3D3D',
selection: '#BBDFFF',
selectionMatch: '#BBDFFF',
gutterBackground: '#fff',
gutterForeground: '#AFAFAF',
lineHighlight: '#d5e6ff69',
},
styles: [
{ tag: [t.comment, t.quote], color: '#707F8D' },
{ tag: [t.typeName, t.typeOperator], color: '#aa0d91' },
{ tag: [t.keyword], color: '#aa0d91', fontWeight: 'bold' },
{ tag: [t.string, t.meta], color: '#D23423' },
{ tag: [t.name], color: '#032f62' },
{ tag: [t.typeName], color: '#522BB2' },
{ tag: [t.variableName], color: '#23575C' },
{ tag: [t.definition(t.variableName)], color: '#327A9E' },
{ tag: [t.regexp, t.link], color: '#0e0eff' },
],
});
-142
View File
@@ -1,142 +0,0 @@
import { StateEffect, StateField } from '@codemirror/state';
import { Decoration, EditorView, WidgetType } from '@codemirror/view';
import { getWidgetID, registerWidgetType } from '@strudel/transpiler';
import { Pattern } from '@strudel/core';
export const addWidget = StateEffect.define({
map: ({ from, to }, change) => {
return { from: change.mapPos(from), to: change.mapPos(to) };
},
});
export const updateWidgets = (view, widgets) => {
view.dispatch({ effects: addWidget.of(widgets) });
};
function getWidgets(widgetConfigs) {
return (
widgetConfigs
// codemirror throws an error if we don't sort
.sort((a, b) => a.to - b.to)
.map((widgetConfig) => {
return Decoration.widget({
widget: new BlockWidget(widgetConfig),
side: 0,
block: true,
}).range(widgetConfig.to);
})
);
}
const widgetField = StateField.define(
/* <DecorationSet> */ {
create() {
return Decoration.none;
},
update(widgets, tr) {
widgets = widgets.map(tr.changes);
for (let e of tr.effects) {
if (e.is(addWidget)) {
try {
widgets = widgets.update({
filter: () => false,
add: getWidgets(e.value),
});
} catch (error) {
console.log('err', error);
}
}
}
return widgets;
},
provide: (f) => EditorView.decorations.from(f),
},
);
const widgetElements = {};
export function setWidget(id, el) {
widgetElements[id] = el;
el.id = id;
}
export class BlockWidget extends WidgetType {
constructor(widgetConfig) {
super();
this.widgetConfig = widgetConfig;
}
eq() {
return true;
}
toDOM() {
const id = getWidgetID(this.widgetConfig);
const el = widgetElements[id];
return el;
}
ignoreEvent(e) {
return true;
}
}
export const widgetPlugin = [widgetField];
// widget implementer API to create a new widget type
export function registerWidget(type, fn) {
registerWidgetType(type);
if (fn) {
Pattern.prototype[type] = function (id, options = { fold: 1 }) {
// fn is expected to create a dom element and call setWidget(id, el);
// fn should also return the pattern
return fn(id, options, this);
};
}
}
// wire up @strudel/draw functions
function getCanvasWidget(id, options = {}) {
const { width = 500, height = 60, pixelRatio = window.devicePixelRatio } = options;
let canvas = document.getElementById(id) || document.createElement('canvas');
canvas.width = width * pixelRatio;
canvas.height = height * pixelRatio;
canvas.style.width = width + 'px';
canvas.style.height = height + 'px';
setWidget(id, canvas);
return canvas;
}
registerWidget('_pianoroll', (id, options = {}, pat) => {
const ctx = getCanvasWidget(id, options).getContext('2d');
return pat.tag(id).pianoroll({ fold: 1, ...options, ctx, id });
});
registerWidget('_punchcard', (id, options = {}, pat) => {
const ctx = getCanvasWidget(id, options).getContext('2d');
return pat.tag(id).punchcard({ fold: 1, ...options, ctx, id });
});
registerWidget('_spiral', (id, options = {}, pat) => {
let _size = options.size || 275;
options = { width: _size, height: _size, ...options, size: _size / 5 };
const ctx = getCanvasWidget(id, options).getContext('2d');
return pat.tag(id).spiral({ ...options, ctx, id });
});
registerWidget('_scope', (id, options = {}, pat) => {
options = { width: 500, height: 60, pos: 0.5, scale: 1, ...options };
const ctx = getCanvasWidget(id, options).getContext('2d');
return pat.tag(id).scope({ ...options, ctx, id });
});
registerWidget('_pitchwheel', (id, options = {}, pat) => {
let _size = options.size || 200;
options = { width: _size, height: _size, ...options, size: _size / 5 };
const ctx = getCanvasWidget(id, options).getContext('2d');
return pat.pitchwheel({ ...options, ctx, id });
});
registerWidget('_spectrum', (id, options = {}, pat) => {
let _size = options.size || 200;
options = { width: _size, height: _size, ...options, size: _size / 5 };
const ctx = getCanvasWidget(id, options).getContext('2d');
return pat.spectrum({ ...options, ctx, id });
});
@@ -1,14 +1,13 @@
import { Pattern, silence, register, pure, createParams } from '@strudel/core'; import { Pattern, getDrawContext, silence, register, pure } from './index.mjs';
import { getDrawContext } from './draw.mjs'; import controls from './controls.mjs'; // do not import from index.mjs as it breaks for some reason..
const { createParams } = controls;
let clearColor = '#22222210'; let clearColor = '#22222210';
Pattern.prototype.animate = function ({ callback, sync = false, smear = 0.5 } = {}) { Pattern.prototype.animate = function ({ callback, sync = false, smear = 0.5 } = {}) {
window.frame && cancelAnimationFrame(window.frame); window.frame && cancelAnimationFrame(window.frame);
const ctx = getDrawContext(); const ctx = getDrawContext();
let { clientWidth: ww, clientHeight: wh } = ctx.canvas; const { clientWidth: ww, clientHeight: wh } = ctx.canvas;
ww *= window.devicePixelRatio;
wh *= window.devicePixelRatio;
let smearPart = smear === 0 ? '99' : Number((1 - smear) * 100).toFixed(0); let smearPart = smear === 0 ? '99' : Number((1 - smear) * 100).toFixed(0);
smearPart = smearPart.length === 1 ? `0${smearPart}` : smearPart; smearPart = smearPart.length === 1 ? `0${smearPart}` : smearPart;
clearColor = `#200010${smearPart}`; clearColor = `#200010${smearPart}`;
-46
View File
@@ -1,46 +0,0 @@
import { describe, bench } from 'vitest';
import { calculateTactus, sequence, stack } from '../index.mjs';
const pat64 = sequence(...Array(64).keys());
describe('steps', () => {
calculateTactus(true);
bench(
'+tactus',
() => {
pat64.iter(64).fast(64).firstCycle();
},
{ time: 1000 },
);
calculateTactus(false);
bench(
'-tactus',
() => {
pat64.iter(64).fast(64).firstCycle();
},
{ time: 1000 },
);
});
describe('stack', () => {
calculateTactus(true);
bench(
'+tactus',
() => {
stack(pat64, pat64, pat64, pat64, pat64, pat64, pat64, pat64).fast(64).firstCycle();
},
{ time: 1000 },
);
calculateTactus(false);
bench(
'-tactus',
() => {
stack(pat64, pat64, pat64, pat64, pat64, pat64, pat64, pat64).fast(64).firstCycle();
},
{ time: 1000 },
);
});
calculateTactus(true);
-161
View File
@@ -1,161 +0,0 @@
// eslint-disable-next-line no-undef
// TODO: swap below line with above one when firefox supports esm imports in service workers
// see https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker?retiredLocale=de#browser_compatibility
// import createClock from './zyklus.mjs';
function getTime() {
const seconds = performance.now() * 0.001;
return seconds;
// return Math.round(seconds * precision) / precision;
}
let num_cycles_at_cps_change = 0;
let num_ticks_since_cps_change = 0;
let num_seconds_at_cps_change = 0;
let cps = 0.5;
// {id: {started: boolean}}
const clients = new Map();
const duration = 0.1;
const channel = new BroadcastChannel('strudeltick');
const sendMessage = (type, payload) => {
channel.postMessage({ type, payload });
};
const sendTick = (phase, duration, tick, time) => {
const num_seconds_since_cps_change = num_ticks_since_cps_change * duration;
const tickdeadline = phase - time;
const lastTick = time + tickdeadline;
const num_cycles_since_cps_change = num_seconds_since_cps_change * cps;
const begin = num_cycles_at_cps_change + num_cycles_since_cps_change;
const secondsSinceLastTick = time - lastTick - duration;
const eventLength = duration * cps;
const end = begin + eventLength;
const cycle = begin + secondsSinceLastTick * cps;
sendMessage('tick', {
begin,
end,
cps,
time,
cycle,
});
num_ticks_since_cps_change++;
};
//create clock method from zyklus
const clock = createClock(getTime, sendTick, duration);
let started = false;
const startClock = (id) => {
clients.set(id, { started: true });
if (started) {
return;
}
clock.start();
started = true;
};
const stopClock = async (id) => {
clients.set(id, { started: false });
const otherClientStarted = Array.from(clients.values()).some((c) => c.started);
//dont stop the clock if other instances are running...
if (!started || otherClientStarted) {
return;
}
clock.stop();
setCycle(0);
started = false;
};
const setCycle = (cycle) => {
num_ticks_since_cps_change = 0;
num_cycles_at_cps_change = cycle;
};
const processMessage = (message) => {
const { type, payload } = message;
switch (type) {
case 'cpschange': {
if (payload.cps !== cps) {
const num_seconds_since_cps_change = num_ticks_since_cps_change * duration;
num_cycles_at_cps_change = num_cycles_at_cps_change + num_seconds_since_cps_change * cps;
num_seconds_at_cps_change = num_seconds_at_cps_change + num_seconds_since_cps_change;
cps = payload.cps;
num_ticks_since_cps_change = 0;
}
break;
}
case 'setcycle': {
setCycle(payload.cycle);
break;
}
case 'toggle': {
if (payload.started) {
startClock(message.id);
} else {
stopClock(message.id);
}
break;
}
}
};
self.onconnect = function (e) {
// the incoming port
const port = e.ports[0];
port.addEventListener('message', function (e) {
processMessage(e.data);
});
port.start(); // Required when using addEventListener. Otherwise called implicitly by onmessage setter.
};
// used to consistently schedule events, for use in a service worker - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/clockworker.mjs>
function createClock(
getTime,
callback, // called slightly before each cycle
duration = 0.05, // duration of each cycle
interval = 0.1, // interval between callbacks
overlap = 0.1, // overlap between callbacks
) {
let tick = 0; // counts callbacks
let phase = 0; // next callback time
let precision = 10 ** 4; // used to round phase
let minLatency = 0.01;
const setDuration = (setter) => (duration = setter(duration));
overlap = overlap || interval / 2;
const onTick = () => {
const t = getTime();
const lookahead = t + interval + overlap; // the time window for this tick
if (phase === 0) {
phase = t + minLatency;
}
// callback as long as we're inside the lookahead
while (phase < lookahead) {
phase = Math.round(phase * precision) / precision;
phase >= t && callback(phase, duration, tick, t);
phase < t && console.log('TOO LATE', phase); // what if latency is added from outside?
phase += duration; // increment phase by duration
tick++;
}
};
let intervalID;
const start = () => {
clear(); // just in case start was called more than once
onTick();
intervalID = setInterval(onTick, interval * 1000);
};
const clear = () => intervalID !== undefined && clearInterval(intervalID);
const pause = () => clear();
const stop = () => {
tick = 0;
phase = 0;
clear();
};
const getPhase = () => phase;
// setCallback
return { setDuration, start, stop, pause, duration, interval, getPhase, minLatency };
}
+301 -619
View File
File diff suppressed because it is too large Load Diff
+23 -52
View File
@@ -1,5 +1,5 @@
/* /*
cyclist.mjs - event scheduler for a single strudel instance. for multi-instance scheduler, see - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/neocyclist.mjs> cyclist.mjs - <short description TODO>
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/cyclist.mjs> Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/cyclist.mjs>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@@ -8,70 +8,49 @@ import createClock from './zyklus.mjs';
import { logger } from './logger.mjs'; import { logger } from './logger.mjs';
export class Cyclist { export class Cyclist {
constructor({ constructor({ interval, onTrigger, onToggle, onError, getTime, latency = 0.1 }) {
interval,
onTrigger,
onToggle,
onError,
getTime,
latency = 0.1,
setInterval,
clearInterval,
beforeStart,
}) {
this.started = false; this.started = false;
this.beforeStart = beforeStart;
this.cps = 0.5; this.cps = 0.5;
this.num_ticks_since_cps_change = 0; this.num_ticks_since_cps_change = 0;
this.lastTick = 0; // absolute time when last tick (clock callback) happened this.lastTick = 0; // absolute time when last tick (clock callback) happened
this.lastBegin = 0; // query begin of last tick this.lastBegin = 0; // query begin of last tick
this.lastEnd = 0; // query end of last tick this.lastEnd = 0; // query end of last tick
this.getTime = getTime; // get absolute time this.getTime = getTime; // get absolute time
this.num_cycles_at_cps_change = 0; this.num_cycles_since_last_cps_change = 0;
this.seconds_at_cps_change; // clock phase when cps was changed
this.onToggle = onToggle; this.onToggle = onToggle;
this.latency = latency; // fixed trigger time offset this.latency = latency; // fixed trigger time offset
this.clock = createClock( this.clock = createClock(
getTime, getTime,
// called slightly before each cycle // called slightly before each cycle
(phase, duration, _, t) => { (phase, duration, tick) => {
if (tick === 0) {
this.origin = phase;
}
if (this.num_ticks_since_cps_change === 0) { if (this.num_ticks_since_cps_change === 0) {
this.num_cycles_at_cps_change = this.lastEnd; this.num_cycles_since_last_cps_change = this.lastEnd;
this.seconds_at_cps_change = phase;
} }
this.num_ticks_since_cps_change++; this.num_ticks_since_cps_change++;
const seconds_since_cps_change = this.num_ticks_since_cps_change * duration;
const num_cycles_since_cps_change = seconds_since_cps_change * this.cps;
try { try {
const time = getTime();
const begin = this.lastEnd; const begin = this.lastEnd;
this.lastBegin = begin; this.lastBegin = begin;
const end = this.num_cycles_at_cps_change + num_cycles_since_cps_change;
this.lastEnd = end;
this.lastTick = phase;
if (phase < t) { //convert ticks to cycles, so you can query the pattern for events
// avoid querying haps that are in the past anyway const eventLength = duration * this.cps;
console.log(`skip query: too late`); const end = this.num_cycles_since_last_cps_change + this.num_ticks_since_cps_change * eventLength;
return; this.lastEnd = end;
}
// query the pattern for events // query the pattern for events
const haps = this.pattern.queryArc(begin, end, { _cps: this.cps }); const haps = this.pattern.queryArc(begin, end, { _cps: this.cps });
const tickdeadline = phase - time; // time left until the phase is a whole number
this.lastTick = time + tickdeadline;
haps.forEach((hap) => { haps.forEach((hap) => {
if (hap.hasOnset()) { if (hap.part.begin.equals(hap.whole.begin)) {
const targetTime = const deadline = (hap.whole.begin - begin) / this.cps + tickdeadline + latency;
(hap.whole.begin - this.num_cycles_at_cps_change) / this.cps + this.seconds_at_cps_change + latency;
const duration = hap.duration / this.cps; const duration = hap.duration / this.cps;
// the following line is dumb and only here for backwards compatibility onTrigger?.(hap, deadline, duration, this.cps);
// see https://github.com/tidalcycles/strudel/pull/1004
const deadline = targetTime - phase;
onTrigger?.(hap, deadline, duration, this.cps, targetTime);
if (hap.value.cps !== undefined && this.cps != hap.value.cps) {
this.cps = hap.value.cps;
this.num_ticks_since_cps_change = 0;
}
} }
}); });
} catch (e) { } catch (e) {
@@ -80,16 +59,9 @@ export class Cyclist {
} }
}, },
interval, // duration of each cycle interval, // duration of each cycle
0.1,
0.1,
setInterval,
clearInterval,
); );
} }
now() { now() {
if (!this.started) {
return 0;
}
const secondsSinceLastTick = this.getTime() - this.lastTick - this.clock.duration; const secondsSinceLastTick = this.getTime() - this.lastTick - this.clock.duration;
return this.lastBegin + secondsSinceLastTick * this.cps; // + this.clock.minLatency; return this.lastBegin + secondsSinceLastTick * this.cps; // + this.clock.minLatency;
} }
@@ -97,10 +69,9 @@ export class Cyclist {
this.started = v; this.started = v;
this.onToggle?.(v); this.onToggle?.(v);
} }
async start() { start() {
await this.beforeStart?.();
this.num_ticks_since_cps_change = 0; this.num_ticks_since_cps_change = 0;
this.num_cycles_at_cps_change = 0; this.num_cycles_since_last_cps_change = 0;
if (!this.pattern) { if (!this.pattern) {
throw new Error('Scheduler: no pattern set! call .setPattern first.'); throw new Error('Scheduler: no pattern set! call .setPattern first.');
} }
@@ -119,10 +90,10 @@ export class Cyclist {
this.lastEnd = 0; this.lastEnd = 0;
this.setStarted(false); this.setStarted(false);
} }
async setPattern(pat, autostart = false) { setPattern(pat, autostart = false) {
this.pattern = pat; this.pattern = pat;
if (autostart && !this.started) { if (autostart && !this.started) {
await this.start(); this.start();
} }
} }
setCps(cps = 0.5) { setCps(cps = 0.5) {
@@ -1,96 +1,81 @@
/* /*
draw.mjs - <short description TODO> draw.mjs - <short description TODO>
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/canvas/draw.mjs> Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/draw.mjs>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { Pattern, getTime, State, TimeSpan } from '@strudel/core'; import { Pattern, getTime, State, TimeSpan } from './index.mjs';
export const getDrawContext = (id = 'test-canvas', options) => { export const getDrawContext = (id = 'test-canvas') => {
let { contextType = '2d', pixelated = false, pixelRatio = window.devicePixelRatio } = options || {};
let canvas = document.querySelector('#' + id); let canvas = document.querySelector('#' + id);
if (!canvas) { if (!canvas) {
const scale = 2; // 2 = crisp on retina screens
canvas = document.createElement('canvas'); canvas = document.createElement('canvas');
canvas.id = id; canvas.id = id;
canvas.width = window.innerWidth * pixelRatio; canvas.width = window.innerWidth * scale;
canvas.height = window.innerHeight * pixelRatio; canvas.height = window.innerHeight * scale;
canvas.style = 'pointer-events:none;width:100%;height:100%;position:fixed;top:0;left:0'; canvas.style = 'pointer-events:none;width:100%;height:100%;position:fixed;top:0;left:0';
pixelated && (canvas.style.imageRendering = 'pixelated');
document.body.prepend(canvas); document.body.prepend(canvas);
let timeout; let timeout;
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
timeout && clearTimeout(timeout); timeout && clearTimeout(timeout);
timeout = setTimeout(() => { timeout = setTimeout(() => {
canvas.width = window.innerWidth * pixelRatio; canvas.width = window.innerWidth * scale;
canvas.height = window.innerHeight * pixelRatio; canvas.height = window.innerHeight * scale;
}, 200); }, 200);
}); });
} }
return canvas.getContext(contextType, { willReadFrequently: true }); return canvas.getContext('2d');
}; };
let animationFrames = {}; Pattern.prototype.draw = function (callback, { from, to, onQuery } = {}) {
function stopAnimationFrame(id) {
if (animationFrames[id] !== undefined) {
cancelAnimationFrame(animationFrames[id]);
delete animationFrames[id];
}
}
function stopAllAnimations(replID) {
Object.keys(animationFrames).forEach((id) => (!replID || id.startsWith(replID)) && stopAnimationFrame(id));
}
let memory = {};
Pattern.prototype.draw = function (fn, options) {
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
return this; return this;
} }
let { id = 1, lookbehind = 0, lookahead = 0 } = options; if (window.strudelAnimation) {
let __t = Math.max(getTime(), 0); cancelAnimationFrame(window.strudelAnimation);
stopAnimationFrame(id); }
lookbehind = Math.abs(lookbehind); const ctx = getDrawContext();
// init memory, clear future haps of old pattern let cycle,
memory[id] = (memory[id] || []).filter((h) => !h.isInFuture(__t)); events = [];
let newFuture = this.queryArc(__t, __t + lookahead).filter((h) => h.hasOnset()); const animate = (time) => {
memory[id] = memory[id].concat(newFuture); const t = getTime();
if (from !== undefined && to !== undefined) {
let last; const currentCycle = Math.floor(t);
const animate = () => { if (cycle !== currentCycle) {
const _t = getTime(); cycle = currentCycle;
const t = _t + lookahead; const begin = currentCycle + from;
// filter out haps that are too far in the past const end = currentCycle + to;
memory[id] = memory[id].filter((h) => h.isInNearPast(lookbehind, _t)); setTimeout(() => {
// begin where we left off in last frame, but max -0.1s (inactive tab throttles to 1fps) events = this.query(new State(new TimeSpan(begin, end)))
let begin = Math.max(last || t, t - 1 / 10); .filter(Boolean)
const haps = this.queryArc(begin, t).filter((h) => h.hasOnset()); .filter((event) => event.part.begin.equals(event.whole.begin));
memory[id] = memory[id].concat(haps); onQuery?.(events);
last = t; // makes sure no haps are missed }, 0);
fn(memory[id], _t, t, this); }
animationFrames[id] = requestAnimationFrame(animate); }
callback(ctx, events, t, time);
window.strudelAnimation = requestAnimationFrame(animate);
}; };
animationFrames[id] = requestAnimationFrame(animate); requestAnimationFrame(animate);
return this; return this;
}; };
export const cleanupDraw = (clearScreen = true, id) => { export const cleanupDraw = (clearScreen = true) => {
const ctx = getDrawContext(); const ctx = getDrawContext();
clearScreen && ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); clearScreen && ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.width);
stopAllAnimations(id); if (window.strudelAnimation) {
}; cancelAnimationFrame(window.strudelAnimation);
}
Pattern.prototype.onPaint = function (painter) { if (window.strudelScheduler) {
return this.withState((state) => { clearInterval(window.strudelScheduler);
if (!state.controls.painters) {
state.controls.painters = [];
} }
state.controls.painters.push(painter);
});
}; };
Pattern.prototype.getPainters = function () { Pattern.prototype.onPaint = function (onPaint) {
let painters = []; // this is evil! TODO: add pattern.context
this.queryArc(0, 0, { painters }); this.context = { onPaint };
return painters; return this;
}; };
// const round = (x) => Math.round(x * 1000) / 1000; // const round = (x) => Math.round(x * 1000) / 1000;
@@ -129,7 +114,6 @@ export class Drawer {
this.visibleHaps = []; this.visibleHaps = [];
this.lastFrame = null; this.lastFrame = null;
this.drawTime = drawTime; this.drawTime = drawTime;
this.painters = [];
this.framer = new Framer( this.framer = new Framer(
() => { () => {
if (!this.scheduler) { if (!this.scheduler) {
@@ -150,11 +134,11 @@ export class Drawer {
this.lastFrame = phase; this.lastFrame = phase;
this.visibleHaps = (this.visibleHaps || []) this.visibleHaps = (this.visibleHaps || [])
// filter out haps that are too far in the past (think left edge of screen for pianoroll) // filter out haps that are too far in the past (think left edge of screen for pianoroll)
.filter((h) => h.endClipped >= phase - lookbehind - lookahead) .filter((h) => h.whole?.end >= phase - lookbehind - lookahead)
// add new haps with onset (think right edge bars scrolling in) // add new haps with onset (think right edge bars scrolling in)
.concat(haps.filter((h) => h.hasOnset())); .concat(haps.filter((h) => h.hasOnset()));
const time = phase - lookahead; const time = phase - lookahead;
onDraw(this.visibleHaps, time, this, this.painters); onDraw(this.visibleHaps, time, this);
}, },
(err) => { (err) => {
console.warn('draw error', err); console.warn('draw error', err);
@@ -172,13 +156,11 @@ export class Drawer {
t = t ?? scheduler.now(); t = t ?? scheduler.now();
this.scheduler = scheduler; this.scheduler = scheduler;
let [_, lookahead] = this.drawTime; let [_, lookahead] = this.drawTime;
// +0.1 = workaround for weird holes in query..
const [begin, end] = [Math.max(t, 0), t + lookahead + 0.1]; const [begin, end] = [Math.max(t, 0), t + lookahead + 0.1];
// remove all future haps // remove all future haps
this.visibleHaps = this.visibleHaps.filter((h) => h.whole.begin < t); this.visibleHaps = this.visibleHaps.filter((h) => h.whole.begin < t);
this.painters = []; // will get populated by .onPaint calls attached to the pattern
// query future haps // query future haps
const futureHaps = scheduler.pattern.queryArc(begin, end, { painters: this.painters }); const futureHaps = scheduler.pattern.queryArc(begin, end); // +0.1 = workaround for weird holes in query..
// append future haps // append future haps
this.visibleHaps = this.visibleHaps.concat(futureHaps); this.visibleHaps = this.visibleHaps.concat(futureHaps);
} }
@@ -193,27 +175,3 @@ export class Drawer {
} }
} }
} }
export function getComputedPropertyValue(name) {
if (typeof window === 'undefined') {
return '#fff';
}
return getComputedStyle(document.documentElement).getPropertyValue(name);
}
let theme = {
background: '#222',
foreground: '#75baff',
caret: '#ffcc00',
selection: 'rgba(128, 203, 196, 0.5)',
selectionMatch: '#036dd626',
lineHighlight: '#00000050',
gutterBackground: 'transparent',
gutterForeground: '#8a919966',
};
export function getTheme() {
return theme;
}
export function setTheme(_theme) {
theme = _theme;
}
+1 -7
View File
@@ -41,17 +41,11 @@ const _bjork = function (n, x) {
}; };
export const bjork = function (ons, steps) { export const bjork = function (ons, steps) {
const inverted = ons < 0;
ons = Math.abs(ons);
const offs = steps - ons; const offs = steps - ons;
const x = Array(ons).fill([1]); const x = Array(ons).fill([1]);
const y = Array(offs).fill([0]); const y = Array(offs).fill([0]);
const result = _bjork([ons, offs], [x, y]); const result = _bjork([ons, offs], [x, y]);
const p = flatten(result[1][0]).concat(flatten(result[1][1])); return flatten(result[1][0]).concat(flatten(result[1][1]));
if (inverted) {
return p.map((x) => (x === 0 ? 1 : 0));
}
return p;
}; };
/** /**
+4 -4
View File
@@ -4,6 +4,8 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { isPattern } from './index.mjs';
export const evalScope = async (...args) => { export const evalScope = async (...args) => {
const results = await Promise.allSettled(args); const results = await Promise.allSettled(args);
const modules = results.filter((result) => result.status === 'fulfilled').map((r) => r.value); const modules = results.filter((result) => result.status === 'fulfilled').map((r) => r.value);
@@ -20,7 +22,6 @@ export const evalScope = async (...args) => {
globalThis[name] = value; globalThis[name] = value;
}); });
}); });
return modules;
}; };
function safeEval(str, options = {}) { function safeEval(str, options = {}) {
@@ -35,12 +36,11 @@ function safeEval(str, options = {}) {
return Function(body)(); return Function(body)();
} }
export const evaluate = async (code, transpiler, transpilerOptions) => { export const evaluate = async (code, transpiler) => {
let meta = {}; let meta = {};
if (transpiler) { if (transpiler) {
// transform syntactically correct js code to semantically usable code // transform syntactically correct js code to semantically usable code
const transpiled = transpiler(code, transpilerOptions); const transpiled = transpiler(code);
code = transpiled.output; code = transpiled.output;
meta = transpiled; meta = transpiled;
} }
-43
View File
@@ -6,7 +6,6 @@ This program is free software: you can redistribute it and/or modify it under th
import Fraction from 'fraction.js'; import Fraction from 'fraction.js';
import { TimeSpan } from './timespan.mjs'; import { TimeSpan } from './timespan.mjs';
import { removeUndefineds } from './util.mjs';
// Returns the start of the cycle. // Returns the start of the cycle.
Fraction.prototype.sam = function () { Fraction.prototype.sam = function () {
@@ -48,39 +47,14 @@ Fraction.prototype.eq = function (other) {
return this.compare(other) == 0; return this.compare(other) == 0;
}; };
Fraction.prototype.ne = function (other) {
return this.compare(other) != 0;
};
Fraction.prototype.max = function (other) { Fraction.prototype.max = function (other) {
return this.gt(other) ? this : other; return this.gt(other) ? this : other;
}; };
Fraction.prototype.maximum = function (...others) {
others = others.map((x) => new Fraction(x));
return others.reduce((max, other) => other.max(max), this);
};
Fraction.prototype.min = function (other) { Fraction.prototype.min = function (other) {
return this.lt(other) ? this : other; return this.lt(other) ? this : other;
}; };
Fraction.prototype.mulmaybe = function (other) {
return other !== undefined ? this.mul(other) : undefined;
};
Fraction.prototype.divmaybe = function (other) {
return other !== undefined ? this.div(other) : undefined;
};
Fraction.prototype.addmaybe = function (other) {
return other !== undefined ? this.add(other) : undefined;
};
Fraction.prototype.submaybe = function (other) {
return other !== undefined ? this.sub(other) : undefined;
};
Fraction.prototype.show = function (/* excludeWhole = false */) { Fraction.prototype.show = function (/* excludeWhole = false */) {
// return this.toFraction(excludeWhole); // return this.toFraction(excludeWhole);
return this.s * this.n + '/' + this.d; return this.s * this.n + '/' + this.d;
@@ -106,26 +80,9 @@ const fraction = (n) => {
}; };
export const gcd = (...fractions) => { export const gcd = (...fractions) => {
fractions = removeUndefineds(fractions);
if (fractions.length === 0) {
return undefined;
}
return fractions.reduce((gcd, fraction) => gcd.gcd(fraction), fraction(1)); return fractions.reduce((gcd, fraction) => gcd.gcd(fraction), fraction(1));
}; };
export const lcm = (...fractions) => {
fractions = removeUndefineds(fractions);
if (fractions.length === 0) {
return undefined;
}
const x = fractions.pop();
return fractions.reduce(
(lcm, fraction) => (lcm === undefined || fraction === undefined ? undefined : lcm.lcm(fraction)),
x,
);
};
fraction._original = Fraction; fraction._original = Fraction;
export default fraction; export default fraction;
+1 -36
View File
@@ -3,7 +3,6 @@ hap.mjs - <short description TODO>
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/hap.mjs> Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/hap.mjs>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import Fraction from './fraction.mjs';
export class Hap { export class Hap {
/* /*
@@ -33,43 +32,13 @@ export class Hap {
} }
get duration() { get duration() {
let duration; return this.whole.end.sub(this.whole.begin).mul(typeof this.value?.clip === 'number' ? this.value?.clip : 1);
if (typeof this.value?.duration === 'number') {
duration = Fraction(this.value.duration);
} else {
duration = this.whole.end.sub(this.whole.begin);
}
if (typeof this.value?.clip === 'number') {
return duration.mul(this.value.clip);
}
return duration;
} }
get endClipped() { get endClipped() {
return this.whole.begin.add(this.duration); return this.whole.begin.add(this.duration);
} }
isActive(currentTime) {
return this.whole.begin <= currentTime && this.endClipped >= currentTime;
}
isInPast(currentTime) {
return currentTime > this.endClipped;
}
isInNearPast(margin, currentTime) {
return currentTime - margin <= this.endClipped;
}
isInFuture(currentTime) {
return currentTime < this.whole.begin;
}
isInNearFuture(margin, currentTime) {
return currentTime < this.whole.begin && currentTime > this.whole.begin - margin;
}
isWithinTime(min, max) {
return this.whole.begin <= max && this.endClipped >= min;
}
wholeOrPart() { wholeOrPart() {
return this.whole ? this.whole : this.part; return this.whole ? this.whole : this.part;
} }
@@ -91,10 +60,6 @@ export class Hap {
return this.whole != undefined && this.whole.begin.equals(this.part.begin); return this.whole != undefined && this.whole.begin.equals(this.part.begin);
} }
hasTag(tag) {
return this.context.tags?.includes(tag);
}
resolveState(state) { resolveState(state) {
if (this.stateful && this.hasOnset()) { if (this.stateful && this.hasOnset()) {
console.log('stateful'); console.log('stateful');
+6 -5
View File
@@ -4,17 +4,14 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import * as controls from './controls.mjs'; // legacy import controls from './controls.mjs';
export * from './euclid.mjs'; export * from './euclid.mjs';
import Fraction from './fraction.mjs'; import Fraction from './fraction.mjs';
import createClock from './zyklus.mjs';
import { logger } from './logger.mjs'; import { logger } from './logger.mjs';
export { Fraction, controls, createClock }; export { Fraction, controls };
export * from './controls.mjs';
export * from './hap.mjs'; export * from './hap.mjs';
export * from './pattern.mjs'; export * from './pattern.mjs';
export * from './signal.mjs'; export * from './signal.mjs';
export * from './pick.mjs';
export * from './state.mjs'; export * from './state.mjs';
export * from './timespan.mjs'; export * from './timespan.mjs';
export * from './util.mjs'; export * from './util.mjs';
@@ -24,6 +21,10 @@ export * from './repl.mjs';
export * from './cyclist.mjs'; export * from './cyclist.mjs';
export * from './logger.mjs'; export * from './logger.mjs';
export * from './time.mjs'; export * from './time.mjs';
export * from './draw.mjs';
export * from './animate.mjs';
export * from './pianoroll.mjs';
export * from './spiral.mjs';
export * from './ui.mjs'; export * from './ui.mjs';
export { default as drawLine } from './drawLine.mjs'; export { default as drawLine } from './drawLine.mjs';
// below won't work with runtime.mjs (json import fails) // below won't work with runtime.mjs (json import fails)
-10
View File
@@ -1,16 +1,6 @@
export const logKey = 'strudel.log'; export const logKey = 'strudel.log';
let debounce = 1000,
lastMessage,
lastTime;
export function logger(message, type, data = {}) { export function logger(message, type, data = {}) {
let t = performance.now();
if (lastMessage === message && t - lastTime < debounce) {
return;
}
lastMessage = message;
lastTime = t;
console.log(`%c${message}`, 'background-color: black;color:white;border-radius:15px'); console.log(`%c${message}`, 'background-color: black;color:white;border-radius:15px');
if (typeof document !== 'undefined' && typeof CustomEvent !== 'undefined') { if (typeof document !== 'undefined' && typeof CustomEvent !== 'undefined') {
document.dispatchEvent( document.dispatchEvent(
-107
View File
@@ -1,107 +0,0 @@
/*
neocyclist.mjs - event scheduler like cyclist, except recieves clock pulses from clockworker in order to sync across multiple instances.
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/neocyclist.mjs>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { logger } from './logger.mjs';
import { ClockCollator, cycleToSeconds } from './util.mjs';
export class NeoCyclist {
constructor({ onTrigger, onToggle, getTime }) {
this.started = false;
this.cps = 0.5;
this.lastTick = 0; // absolute time when last tick (clock callback) happened
this.getTime = getTime; // get absolute time
this.time_at_last_tick_message = 0;
// the clock of the worker and the audio context clock can drift apart over time
// aditionally, the message time of the worker pinging the callback to process haps can be inconsistent.
// we need to keep a rolling average of the time difference between the worker clock and audio context clock
// in order to schedule events consistently.
this.collator = new ClockCollator({ getTargetClockTime: getTime });
this.onToggle = onToggle;
this.latency = 0.1; // fixed trigger time offset
this.cycle = 0;
this.id = Math.round(Date.now() * Math.random());
this.worker = new SharedWorker(new URL('./clockworker.js', import.meta.url));
this.worker.port.start();
this.channel = new BroadcastChannel('strudeltick');
const tickCallback = (payload) => {
const { cps, begin, end, cycle, time } = payload;
this.cps = cps;
this.cycle = cycle;
const currentTime = this.collator.calculateOffset(time) + time;
processHaps(begin, end, currentTime);
this.time_at_last_tick_message = currentTime;
};
const processHaps = (begin, end, currentTime) => {
if (this.started === false) {
return;
}
const haps = this.pattern.queryArc(begin, end, { _cps: this.cps });
haps.forEach((hap) => {
if (hap.hasOnset()) {
const timeUntilTrigger = cycleToSeconds(hap.whole.begin - this.cycle, this.cps);
const targetTime = timeUntilTrigger + currentTime + this.latency;
const duration = cycleToSeconds(hap.duration, this.cps);
onTrigger?.(hap, 0, duration, this.cps, targetTime);
}
});
};
// receive messages from worker clock and process them
this.channel.onmessage = (message) => {
if (!this.started) {
return;
}
const { payload, type } = message.data;
switch (type) {
case 'tick': {
tickCallback(payload);
}
}
};
}
sendMessage(type, payload) {
this.worker.port.postMessage({ type, payload, id: this.id });
}
now() {
const gap = (this.getTime() - this.time_at_last_tick_message) * this.cps;
return this.cycle + gap;
}
setCps(cps = 1) {
this.sendMessage('cpschange', { cps });
}
setCycle(cycle) {
this.sendMessage('setcycle', { cycle });
}
setStarted(started) {
this.sendMessage('toggle', { started });
this.started = started;
this.onToggle?.(started);
}
start() {
logger('[cyclist] start');
this.setStarted(true);
}
stop() {
logger('[cyclist] stop');
this.collator.reset();
this.setStarted(false);
}
setPattern(pat, autostart = false) {
this.pattern = pat;
if (autostart && !this.started) {
this.start();
}
}
log(begin, end, haps) {
const onsets = haps.filter((h) => h.hasOnset());
console.log(`${begin.toFixed(4)} - ${end.toFixed(4)} ${Array(onsets.length).fill('I').join('')}`);
}
}
+4 -5
View File
@@ -1,6 +1,6 @@
{ {
"name": "@strudel/core", "name": "@strudel/core",
"version": "1.2.0", "version": "1.0.1",
"description": "Port of Tidal Cycles to JavaScript", "description": "Port of Tidal Cycles to JavaScript",
"main": "index.mjs", "main": "index.mjs",
"type": "module", "type": "module",
@@ -9,7 +9,6 @@
}, },
"scripts": { "scripts": {
"test": "vitest run", "test": "vitest run",
"bench": "vitest bench",
"build": "vite build", "build": "vite build",
"prepublishOnly": "pnpm build" "prepublishOnly": "pnpm build"
}, },
@@ -31,11 +30,11 @@
}, },
"homepage": "https://strudel.cc", "homepage": "https://strudel.cc",
"dependencies": { "dependencies": {
"fraction.js": "^5.2.1" "fraction.js": "^4.3.7"
}, },
"gitHead": "0e26d4e741500f5bae35b023608f062a794905c2", "gitHead": "0e26d4e741500f5bae35b023608f062a794905c2",
"devDependencies": { "devDependencies": {
"vite": "^6.0.11", "vite": "^5.0.10",
"vitest": "^3.0.4" "vitest": "^1.1.0"
} }
} }
+247 -1103
View File
File diff suppressed because it is too large Load Diff
@@ -1,11 +1,10 @@
/* /*
pianoroll.mjs - <short description TODO> pianoroll.mjs - <short description TODO>
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/canvas/pianoroll.mjs> Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/pianoroll.mjs>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { Pattern, noteToMidi, freqToMidi, isPattern } from '@strudel/core'; import { Pattern, noteToMidi, getDrawContext, freqToMidi, isNote } from './index.mjs';
import { getTheme, getDrawContext } from './draw.mjs';
const scale = (normalized, min, max) => normalized * (max - min) + min; const scale = (normalized, min, max) => normalized * (max - min) + min;
const getValue = (e) => { const getValue = (e) => {
@@ -19,13 +18,7 @@ const getValue = (e) => {
} }
note = note ?? n; note = note ?? n;
if (typeof note === 'string') { if (typeof note === 'string') {
try {
// TODO: n(run(32)).scale("D:minor") fails when trying to query negative time..
return noteToMidi(note); return noteToMidi(note);
} catch (err) {
// console.warn(`error converting note to midi: ${err}`); // this spams to crazy
return 0;
}
} }
if (typeof note === 'number') { if (typeof note === 'number') {
return note; return note;
@@ -36,12 +29,38 @@ const getValue = (e) => {
return value; return value;
}; };
Pattern.prototype.pianoroll = function (options = {}) {
let { cycles = 4, playhead = 0.5, overscan = 1, hideNegative = false } = options;
let from = -cycles * playhead;
let to = cycles * (1 - playhead);
this.draw(
(ctx, haps, t) => {
const inFrame = (event) =>
(!hideNegative || event.whole.begin >= 0) && event.whole.begin <= t + to && event.endClipped >= t + from;
pianoroll({
...options,
time: t,
ctx,
haps: haps.filter(inFrame),
});
},
{
from: from - overscan,
to: to + overscan,
},
);
return this;
};
// this function allows drawing a pianoroll without ties to Pattern.prototype
// it will probably replace the above in the future
/** /**
* Visualises a pattern as a scrolling 'pianoroll', displayed in the background of the editor. To show a pianoroll for all running patterns, use `all(pianoroll)`. To have a pianoroll appear below * Displays a midi-style piano roll
* a pattern instead, prefix with `_`, e.g.: `sound("bd sd")._pianoroll()`.
* *
* @name pianoroll * @name pianoroll
* @synonyms punchcard
* @param {Object} options Object containing all the optional following parameters as key value pairs: * @param {Object} options Object containing all the optional following parameters as key value pairs:
* @param {integer} cycles number of cycles to be displayed at the same time - defaults to 4 * @param {integer} cycles number of cycles to be displayed at the same time - defaults to 4
* @param {number} playhead location of the active notes on the time axis - 0 to 1, defaults to 0.5 * @param {number} playhead location of the active notes on the time axis - 0 to 1, defaults to 0.5
@@ -67,51 +86,11 @@ const getValue = (e) => {
* @param {integer} minMidi minimum note value to display on the value axis - defaults to 10 * @param {integer} minMidi minimum note value to display on the value axis - defaults to 10
* @param {integer} maxMidi maximum note value to display on the value axis - defaults to 90 * @param {integer} maxMidi maximum note value to display on the value axis - defaults to 90
* @param {boolean} autorange automatically calculate the minMidi and maxMidi parameters - 0 by default * @param {boolean} autorange automatically calculate the minMidi and maxMidi parameters - 0 by default
* @see _pianoroll *
* @example * @example
* note("c2 a2 eb2") * note("C2 A2 G2").euclid(5,8).s('piano').clip(1).color('salmon').pianoroll({vertical:1, labels:1})
* .euclid(5,8)
* .s('sawtooth')
* .lpenv(4).lpf(300)
* .pianoroll({ labels: 1 })
*/ */
export function pianoroll({
Pattern.prototype.pianoroll = function (options = {}) {
let { cycles = 4, playhead = 0.5, overscan = 0, hideNegative = false, ctx = getDrawContext(), id = 1 } = options;
let from = -cycles * playhead;
let to = cycles * (1 - playhead);
const inFrame = (hap, t) => (!hideNegative || hap.whole.begin >= 0) && hap.isWithinTime(t + from, t + to);
this.draw(
(haps, time) => {
__pianoroll({
...options,
time,
ctx,
haps: haps.filter((hap) => inFrame(hap, time)),
});
},
{
lookbehind: from - overscan,
lookahead: to + overscan,
id,
},
);
return this;
};
export function pianoroll(arg) {
if (isPattern(arg)) {
// Single argument as a pattern
// (to support `all(pianoroll)`)
return arg.pianoroll();
}
// Single argument with option - return function to get the pattern
// (to support `all(pianoroll(options))`)
return (pat) => pat.pianoroll(arg);
}
export function __pianoroll({
time, time,
haps, haps,
cycles = 4, cycles = 4,
@@ -119,16 +98,19 @@ export function __pianoroll({
flipTime = 0, flipTime = 0,
flipValues = 0, flipValues = 0,
hideNegative = false, hideNegative = false,
inactive = getTheme().foreground, // inactive = '#C9E597',
active = getTheme().foreground, // inactive = '#FFCA28',
inactive = '#7491D2',
active = '#FFCA28',
// background = '#2A3236',
background = 'transparent', background = 'transparent',
smear = 0, smear = 0,
playheadColor = getTheme().foreground, playheadColor = 'white',
minMidi = 10, minMidi = 10,
maxMidi = 90, maxMidi = 90,
autorange = 0, autorange = 0,
timeframe: timeframeProp, timeframe: timeframeProp,
fold = 1, fold = 0,
vertical = 0, vertical = 0,
labels = false, labels = false,
fill = 1, fill = 1,
@@ -139,17 +121,12 @@ export function __pianoroll({
colorizeInactive = 1, colorizeInactive = 1,
fontFamily, fontFamily,
ctx, ctx,
id,
} = {}) { } = {}) {
const w = ctx.canvas.width; const w = ctx.canvas.width;
const h = ctx.canvas.height; const h = ctx.canvas.height;
let from = -cycles * playhead; let from = -cycles * playhead;
let to = cycles * (1 - playhead); let to = cycles * (1 - playhead);
if (id) {
haps = haps.filter((hap) => hap.hasTag(id));
}
if (timeframeProp) { if (timeframeProp) {
console.warn('timeframe is deprecated! use from/to instead'); console.warn('timeframe is deprecated! use from/to instead');
from = 0; from = 0;
@@ -204,14 +181,13 @@ export function __pianoroll({
if (hideInactive && !isActive) { if (hideInactive && !isActive) {
return; return;
} }
let color = event.value?.color; let color = event.value?.color || event.context?.color;
active = color || active; active = color || active;
inactive = colorizeInactive ? color || inactive : inactive; inactive = colorizeInactive ? color || inactive : inactive;
color = isActive ? active : inactive; color = isActive ? active : inactive;
ctx.fillStyle = fillCurrent ? color : 'transparent'; ctx.fillStyle = fillCurrent ? color : 'transparent';
ctx.strokeStyle = color; ctx.strokeStyle = color;
const { velocity = 1, gain = 1 } = event.value || {}; ctx.globalAlpha = event.context.velocity ?? event.value?.gain ?? 1;
ctx.globalAlpha = velocity * gain;
const timeProgress = (event.whole.begin - (flipTime ? to : from)) / timeExtent; const timeProgress = (event.whole.begin - (flipTime ? to : from)) / timeExtent;
const timePx = scale(timeProgress, ...timeRange); const timePx = scale(timeProgress, ...timeRange);
let durationPx = scale(event.duration / timeExtent, 0, timeAxis); let durationPx = scale(event.duration / timeExtent, 0, timeAxis);
@@ -281,14 +257,14 @@ export function getDrawOptions(drawTime, options = {}) {
let [lookbehind, lookahead] = drawTime; let [lookbehind, lookahead] = drawTime;
lookbehind = Math.abs(lookbehind); lookbehind = Math.abs(lookbehind);
const cycles = lookahead + lookbehind; const cycles = lookahead + lookbehind;
const playhead = cycles !== 0 ? lookbehind / cycles : 0; const playhead = lookbehind / cycles;
return { fold: 1, ...options, cycles, playhead }; return { fold: 1, ...options, cycles, playhead };
} }
export const getPunchcardPainter = export const getPunchcardPainter =
(options = {}) => (options = {}) =>
(ctx, time, haps, drawTime) => (ctx, time, haps, drawTime, paintOptions = {}) =>
__pianoroll({ ctx, time, haps, ...getDrawOptions(drawTime, options) }); pianoroll({ ctx, time, haps, ...getDrawOptions(drawTime, { ...paintOptions, ...options }) });
Pattern.prototype.punchcard = function (options) { Pattern.prototype.punchcard = function (options) {
return this.onPaint(getPunchcardPainter(options)); return this.onPaint(getPunchcardPainter(options));
@@ -312,5 +288,5 @@ Pattern.prototype.wordfall = function (options) {
export function drawPianoroll(options) { export function drawPianoroll(options) {
const { drawTime, ...rest } = options; const { drawTime, ...rest } = options;
__pianoroll({ ...getDrawOptions(drawTime), ...rest }); pianoroll({ ...getDrawOptions(drawTime), ...rest });
} }
-214
View File
@@ -1,214 +0,0 @@
/*
pick.mjs - methods that use one pattern to pick events from other patterns.
Copyright (C) 2024 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/signal.mjs>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Pattern, reify, silence, register } from './pattern.mjs';
import { _mod, clamp, objectMap } from './util.mjs';
const _pick = function (lookup, pat, modulo = true) {
const array = Array.isArray(lookup);
const len = Object.keys(lookup).length;
lookup = objectMap(lookup, reify);
if (len === 0) {
return silence;
}
return pat.fmap((i) => {
let key = i;
if (array) {
key = modulo ? Math.round(key) % len : clamp(Math.round(key), 0, lookup.length - 1);
}
return lookup[key];
});
};
/** * Picks patterns (or plain values) either from a list (by index) or a lookup table (by name).
* Similar to `inhabit`, but maintains the structure of the original patterns.
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
* @example
* note("<0 1 2!2 3>".pick(["g a", "e f", "f g f g" , "g c d"]))
* @example
* sound("<0 1 [2,0]>".pick(["bd sd", "cp cp", "hh hh"]))
* @example
* sound("<0!2 [0,1] 1>".pick(["bd(3,8)", "sd sd"]))
* @example
* s("<a!2 [a,b] b>".pick({a: "bd(3,8)", b: "sd sd"}))
*/
export const pick = function (lookup, pat) {
// backward compatibility - the args used to be flipped
if (Array.isArray(pat)) {
[pat, lookup] = [lookup, pat];
}
return __pick(lookup, pat);
};
const __pick = register('pick', function (lookup, pat) {
return _pick(lookup, pat, false).innerJoin();
});
/** * The same as `pick`, but if you pick a number greater than the size of the list,
* it wraps around, rather than sticking at the maximum value.
* For example, if you pick the fifth pattern of a list of three, you'll get the
* second one.
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
*/
export const pickmod = register('pickmod', function (lookup, pat) {
return _pick(lookup, pat, true).innerJoin();
});
/** * pickF lets you use a pattern of numbers to pick which function to apply to another pattern.
* @param {Pattern} pat
* @param {Pattern} lookup a pattern of indices
* @param {function[]} funcs the array of functions from which to pull
* @returns {Pattern}
* @example
* s("bd [rim hh]").pickF("<0 1 2>", [rev,jux(rev),fast(2)])
* @example
* note("<c2 d2>(3,8)").s("square")
* .pickF("<0 2> 1", [jux(rev),fast(2),x=>x.lpf(800)])
*/
export const pickF = register('pickF', function (lookup, funcs, pat) {
return pat.apply(pick(lookup, funcs));
});
/** * The same as `pickF`, but if you pick a number greater than the size of the functions list,
* it wraps around, rather than sticking at the maximum value.
* @param {Pattern} pat
* @param {Pattern} lookup a pattern of indices
* @param {function[]} funcs the array of functions from which to pull
* @returns {Pattern}
*/
export const pickmodF = register('pickmodF', function (lookup, funcs, pat) {
return pat.apply(pickmod(lookup, funcs));
});
/** * Similar to `pick`, but it applies an outerJoin instead of an innerJoin.
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
*/
export const pickOut = register('pickOut', function (lookup, pat) {
return _pick(lookup, pat, false).outerJoin();
});
/** * The same as `pickOut`, but if you pick a number greater than the size of the list,
* it wraps around, rather than sticking at the maximum value.
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
*/
export const pickmodOut = register('pickmodOut', function (lookup, pat) {
return _pick(lookup, pat, true).outerJoin();
});
/** * Similar to `pick`, but the choosen pattern is restarted when its index is triggered.
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
*/
export const pickRestart = register('pickRestart', function (lookup, pat) {
return _pick(lookup, pat, false).restartJoin();
});
/** * The same as `pickRestart`, but if you pick a number greater than the size of the list,
* it wraps around, rather than sticking at the maximum value.
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
* @example
* "<a@2 b@2 c@2 d@2>".pickRestart({
a: n("0 1 2 0"),
b: n("2 3 4 ~"),
c: n("[4 5] [4 3] 2 0"),
d: n("0 -3 0 ~")
}).scale("C:major").s("piano")
*/
export const pickmodRestart = register('pickmodRestart', function (lookup, pat) {
return _pick(lookup, pat, true).restartJoin();
});
/** * Similar to `pick`, but the choosen pattern is reset when its index is triggered.
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
*/
export const pickReset = register('pickReset', function (lookup, pat) {
return _pick(lookup, pat, false).resetJoin();
});
/** * The same as `pickReset`, but if you pick a number greater than the size of the list,
* it wraps around, rather than sticking at the maximum value.
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
*/
export const pickmodReset = register('pickmodReset', function (lookup, pat) {
return _pick(lookup, pat, true).resetJoin();
});
/**
/** * Picks patterns (or plain values) either from a list (by index) or a lookup table (by name).
* Similar to `pick`, but cycles are squeezed into the target ('inhabited') pattern.
* @name inhabit
* @synonyms pickSqueeze
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
* @example
* "<a b [a,b]>".inhabit({a: s("bd(3,8)"),
b: s("cp sd")
})
* @example
* s("a@2 [a b] a".inhabit({a: "bd(3,8)", b: "sd sd"})).slow(4)
*/
export const { inhabit, pickSqueeze } = register(['inhabit', 'pickSqueeze'], function (lookup, pat) {
return _pick(lookup, pat, false).squeezeJoin();
});
/** * The same as `inhabit`, but if you pick a number greater than the size of the list,
* it wraps around, rather than sticking at the maximum value.
* For example, if you pick the fifth pattern of a list of three, you'll get the
* second one.
* @name inhabitmod
* @synonyms pickmodSqueeze
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
*/
export const { inhabitmod, pickmodSqueeze } = register(['inhabitmod', 'pickmodSqueeze'], function (lookup, pat) {
return _pick(lookup, pat, true).squeezeJoin();
});
/**
* Pick from the list of values (or patterns of values) via the index using the given
* pattern of integers. The selected pattern will be compressed to fit the duration of the selecting event
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
* @example
* note(squeeze("<0@2 [1!2] 2>", ["g a", "f g f g" , "g a c d"]))
*/
export const squeeze = (pat, xs) => {
xs = xs.map(reify);
if (xs.length == 0) {
return silence;
}
return pat
.fmap((i) => {
const key = _mod(Math.round(i), xs.length);
return xs[key];
})
.squeezeJoin();
};

Some files were not shown because too many files have changed in this diff Show More