mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-19 00:56:43 -04:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 42d7781d44 | |||
| a746bf5461 | |||
| 700f0be0ba | |||
| cb59d632a8 | |||
| 9fd86458e6 | |||
| 3cd49065c8 | |||
| a7726e2334 | |||
| 26793aec91 | |||
| 7c4ed7e05f | |||
| 93cfe9802c | |||
| 0106a129c9 |
@@ -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
@@ -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"]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
name: Tauri Builder
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
platform: [macos-latest, ubuntu-latest, windows-latest]
|
||||||
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
rust_target: x86_64-unknown-linux-gnu
|
||||||
|
- os: macos-latest
|
||||||
|
rust_target: x86_64-apple-darwin
|
||||||
|
- os: macos-latest
|
||||||
|
rust_target: aarch64-apple-darwin
|
||||||
|
- os: windows-latest
|
||||||
|
rust_target: x86_64-pc-windows-msvc
|
||||||
|
runs-on: ${{ matrix.platform }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- uses: pnpm/action-setup@v2
|
||||||
|
with:
|
||||||
|
version: 8.6.2
|
||||||
|
|
||||||
|
- name: Node.js setup
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: latest
|
||||||
|
# node-version-file: '.nvmrc'
|
||||||
|
|
||||||
|
- name: Install Rust (Stable)
|
||||||
|
run:
|
||||||
|
curl https://sh.rustup.rs -sSf | sh -s -- -y
|
||||||
|
|
||||||
|
- name: Install dependencies (ubuntu only)
|
||||||
|
if: matrix.platform == 'ubuntu-latest'
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf libasound2-dev
|
||||||
|
|
||||||
|
- name: Install app dependencies from lockfile and build web
|
||||||
|
run: pnpm install
|
||||||
|
|
||||||
|
- name: Build the app
|
||||||
|
uses: tauri-apps/tauri-action@v0
|
||||||
|
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
# tauri-action replaces \_\_VERSION\_\_ with the app version
|
||||||
|
tagName: ${{ github.ref_name }}
|
||||||
|
releaseName: "Strudel v__VERSION__"
|
||||||
|
releaseBody: |
|
||||||
|
See the assets to download this version and install.
|
||||||
|
releaseDraft: true
|
||||||
|
prerelease: false
|
||||||
@@ -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'
|
||||||
|
|||||||
@@ -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
|
|
||||||
|
|||||||
+1
-2
@@ -10,6 +10,5 @@ paper
|
|||||||
pnpm-lock.yaml
|
pnpm-lock.yaml
|
||||||
pnpm-workspace.yaml
|
pnpm-workspace.yaml
|
||||||
**/dev-dist
|
**/dev-dist
|
||||||
|
superdough-wasm
|
||||||
website/.astro
|
website/.astro
|
||||||
!tidal-drum-machines.json
|
|
||||||
!tidal-drum-machines-alias.json
|
|
||||||
|
|||||||
+6
-12
@@ -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!
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# strudel
|
# strudel
|
||||||
|
|
||||||
[](https://github.com/tidalcycles/strudel/actions) [](https://doi.org/10.5281/zenodo.6659278)
|
[](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/)
|
```bash
|
||||||
2. Install [pnpm](https://pnpm.io/installation)
|
pnpm run setup
|
||||||
3. Install dependencies by running the following command:
|
pnpm run repl
|
||||||
```bash
|
```
|
||||||
pnpm i
|
|
||||||
```
|
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -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,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
@@ -1,31 +1,10 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<button id="play">play</button>
|
||||||
<head>
|
<button id="stop">stop</button>
|
||||||
<meta charset="UTF-8" />
|
<script type="module">
|
||||||
<!-- <script src="../../packages/web/dist/index.js"></script> -->
|
import { initStrudel } from 'https://cdn.skypack.dev/@strudel/web@0.8.2';
|
||||||
<script src="https://unpkg.com/@strudel/web@1.0.3"></script>
|
|
||||||
</head>
|
|
||||||
<body style="background: #222">
|
|
||||||
<button id="play">play</button>
|
|
||||||
<button id="stop">stop</button>
|
|
||||||
<script>
|
|
||||||
strudel.initStrudel();
|
|
||||||
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))
|
</script>
|
||||||
.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>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -1,24 +1,16 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<button id="a">A</button>
|
||||||
<head>
|
<button id="b">B</button>
|
||||||
<meta charset="UTF-8" />
|
<button id="c">C</button>
|
||||||
<!-- <script src="../../packages/web/dist/index.js"></script> -->
|
<button id="stop">stop</button>
|
||||||
<script src="https://unpkg.com/@strudel/web@1.0.3"></script>
|
<script type="module">
|
||||||
</head>
|
import { initStrudel } from 'https://cdn.skypack.dev/@strudel/web@0.8.2';
|
||||||
<body style="background: #222">
|
initStrudel({
|
||||||
<button id="a">A</button>
|
prebake: () => samples('github:tidalcycles/dirt-samples'),
|
||||||
<button id="b">B</button>
|
});
|
||||||
<button id="c">C</button>
|
const click = (id, action) => document.getElementById(id).addEventListener('click', action);
|
||||||
<button id="stop">stop</button>
|
click('a', () => evaluate(`s('bd,jvbass(3,8)').jux(rev)`));
|
||||||
<script>
|
click('b', () => s('bd*2,hh(3,4),jvbass(5,8,1)').jux(rev).play());
|
||||||
initStrudel({
|
click('c', () => s('bd*2,hh(3,4),jvbass:[0 4](5,8,1)').jux(rev).stack(s('~ sd')).play());
|
||||||
prebake: () => samples('github:tidalcycles/dirt-samples'),
|
click('stop', () => hush());
|
||||||
});
|
</script>
|
||||||
const click = (id, action) => document.getElementById(id).addEventListener('click', action);
|
|
||||||
click('a', () => evaluate(`s('bd,jvbass(3,8)').jux(rev)`));
|
|
||||||
click('b', () => s('bd*2,hh(3,4),jvbass(5,8,1)').jux(rev).play());
|
|
||||||
click('c', () => s('bd*2,hh(3,4),jvbass:[0 4](5,8,1)').jux(rev).stack(s('~ sd')).play());
|
|
||||||
click('stop', () => hush());
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|||||||
@@ -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>
|
|
||||||
@@ -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';
|
||||||
@@ -54,7 +53,7 @@
|
|||||||
|
|
||||||
function getTune() {
|
function getTune() {
|
||||||
return `samples('github:tidalcycles/dirt-samples')
|
return `samples('github:tidalcycles/dirt-samples')
|
||||||
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,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,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'),
|
||||||
|
|||||||
@@ -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:*",
|
||||||
|
|||||||
@@ -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:*"
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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:*",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export default `samples('github:tidalcycles/dirt-samples')
|
export default `samples('github:tidalcycles/dirt-samples')
|
||||||
setcps(1)
|
|
||||||
stack(
|
stack(
|
||||||
// amen
|
// amen
|
||||||
n("0 1 2 3 4 5 6 7")
|
n("0 1 2 3 4 5 6 7")
|
||||||
|
|||||||
@@ -12,6 +12,6 @@
|
|||||||
"superdough": "workspace:*"
|
"superdough": "workspace:*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"vite": "^6.0.11"
|
"vite": "^5.0.10"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
```
|
|
||||||
@@ -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>
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# public
|
|
||||||
|
|
||||||
this file is just here to make sure the public folder exists
|
|
||||||
@@ -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
-19
@@ -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,23 +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",
|
||||||
"vite-plugin-bundle-audioworklet": "workspace:*"
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
|
"vitest": "^1.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
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';
|
||||||
@@ -13,22 +12,19 @@ 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: '()[]{}<>' }) : []),
|
isBracketMatchingEnabled: (on) => (on ? bracketMatching({ brackets: '()[]{}<>' }) : []),
|
||||||
isBracketClosingEnabled: (on) => (on ? closeBrackets() : []),
|
|
||||||
isLineNumbersDisplayed: (on) => (on ? lineNumbers() : []),
|
isLineNumbersDisplayed: (on) => (on ? lineNumbers() : []),
|
||||||
theme,
|
theme,
|
||||||
isAutoCompletionEnabled,
|
isAutoCompletionEnabled,
|
||||||
@@ -43,7 +39,6 @@ const compartments = Object.fromEntries(Object.keys(extensions).map((key) => [ke
|
|||||||
export const defaultSettings = {
|
export const defaultSettings = {
|
||||||
keybindings: 'codemirror',
|
keybindings: 'codemirror',
|
||||||
isBracketMatchingEnabled: false,
|
isBracketMatchingEnabled: false,
|
||||||
isBracketClosingEnabled: true,
|
|
||||||
isLineNumbersDisplayed: true,
|
isLineNumbersDisplayed: true,
|
||||||
isActiveLineHighlighted: false,
|
isActiveLineHighlighted: false,
|
||||||
isAutoCompletionEnabled: false,
|
isAutoCompletionEnabled: false,
|
||||||
@@ -67,7 +62,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 +71,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 +94,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 +125,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 +186,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 +219,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 +240,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');
|
||||||
}
|
}
|
||||||
@@ -301,9 +298,6 @@ export class StrudelMirror {
|
|||||||
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 +330,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 +342,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');
|
|
||||||
|
|||||||
@@ -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([]);
|
||||||
|
|||||||
@@ -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}` },
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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';
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/codemirror",
|
"name": "@strudel/codemirror",
|
||||||
"version": "1.2.1",
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,21 +60,19 @@ 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')
|
return Decoration.widget({
|
||||||
.map(({ from, to, value, min, max, step }) => {
|
widget: new SliderWidget(value, min, max, from, to, step, view),
|
||||||
return Decoration.widget({
|
side: 0,
|
||||||
widget: new SliderWidget(value, min, max, from, to, step, view),
|
}).range(from /* , to */);
|
||||||
side: 0,
|
});
|
||||||
}).range(from /* , to */);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const sliderPlugin = ViewPlugin.fromClass(
|
export const sliderPlugin = ViewPlugin.fromClass(
|
||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Vendored
+410
-89
@@ -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
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -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
@@ -1,43 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
Vendored
-51
@@ -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
@@ -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
@@ -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
@@ -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' },
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
-47
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
-50
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* @name 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
@@ -1,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -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' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
-42
@@ -1,42 +0,0 @@
|
|||||||
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' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
-42
@@ -1,42 +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: '#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
@@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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] },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
-82
@@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* gruvbox-dark
|
|
||||||
* author morhetz
|
|
||||||
* 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` },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
-130
@@ -1,130 +0,0 @@
|
|||||||
/*
|
|
||||||
* gruvbox-light
|
|
||||||
* author morhetz
|
|
||||||
* 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
@@ -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
@@ -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
@@ -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
@@ -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' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
Vendored
-78
@@ -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
@@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
@@ -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
@@ -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
@@ -1,39 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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] },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
+13
-17
@@ -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 const settings = {
|
|
||||||
background: '#222',
|
|
||||||
lineBackground: '#22222299',
|
|
||||||
foreground: '#fff',
|
|
||||||
caret: '#ffcc00',
|
|
||||||
selection: 'rgba(128, 203, 196, 0.5)',
|
|
||||||
selectionMatch: '#036dd626',
|
|
||||||
lineHighlight: '#00000050',
|
|
||||||
gutterBackground: 'transparent',
|
|
||||||
gutterForeground: '#8a919966',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default createTheme({
|
export default createTheme({
|
||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
settings,
|
settings: {
|
||||||
|
background: '#222',
|
||||||
|
foreground: '#75baff', // whats that?
|
||||||
|
caret: '#ffcc00',
|
||||||
|
selection: 'rgba(128, 203, 196, 0.5)',
|
||||||
|
selectionMatch: '#036dd626',
|
||||||
|
// lineHighlight: '#8a91991a', // original
|
||||||
|
lineHighlight: '#00000050',
|
||||||
|
gutterBackground: 'transparent',
|
||||||
|
// gutterForeground: '#8a919966',
|
||||||
|
gutterForeground: '#8a919966',
|
||||||
|
},
|
||||||
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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' },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
@@ -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}`;
|
||||||
@@ -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);
|
|
||||||
@@ -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 };
|
|
||||||
}
|
|
||||||
+1439
-1792
File diff suppressed because it is too large
Load Diff
+23
-52
@@ -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);
|
||||||
|
}
|
||||||
|
if (window.strudelScheduler) {
|
||||||
|
clearInterval(window.strudelScheduler);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Pattern.prototype.onPaint = function (painter) {
|
Pattern.prototype.onPaint = function (onPaint) {
|
||||||
return this.withState((state) => {
|
// this is evil! TODO: add pattern.context
|
||||||
if (!state.controls.painters) {
|
this.context = { onPaint };
|
||||||
state.controls.painters = [];
|
return this;
|
||||||
}
|
|
||||||
state.controls.painters.push(painter);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
Pattern.prototype.getPainters = function () {
|
|
||||||
let painters = [];
|
|
||||||
this.queryArc(0, 0, { painters });
|
|
||||||
return painters;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
@@ -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,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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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');
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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('')}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@strudel/core",
|
"name": "@strudel/core",
|
||||||
"version": "1.2.1",
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+295
-1151
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 {
|
return noteToMidi(note);
|
||||||
// TODO: n(run(32)).scale("D:minor") fails when trying to query negative time..
|
|
||||||
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 });
|
||||||
}
|
}
|
||||||
@@ -1,213 +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();
|
|
||||||
};
|
|
||||||
+16
-81
@@ -1,4 +1,3 @@
|
|||||||
import { NeoCyclist } from './neocyclist.mjs';
|
|
||||||
import { Cyclist } from './cyclist.mjs';
|
import { Cyclist } from './cyclist.mjs';
|
||||||
import { evaluate as _evaluate } from './evaluate.mjs';
|
import { evaluate as _evaluate } from './evaluate.mjs';
|
||||||
import { logger } from './logger.mjs';
|
import { logger } from './logger.mjs';
|
||||||
@@ -7,20 +6,17 @@ import { evalScope } from './evaluate.mjs';
|
|||||||
import { register, Pattern, isPattern, silence, stack } from './pattern.mjs';
|
import { register, Pattern, isPattern, silence, stack } from './pattern.mjs';
|
||||||
|
|
||||||
export function repl({
|
export function repl({
|
||||||
|
interval,
|
||||||
defaultOutput,
|
defaultOutput,
|
||||||
|
onSchedulerError,
|
||||||
onEvalError,
|
onEvalError,
|
||||||
beforeEval,
|
beforeEval,
|
||||||
beforeStart,
|
|
||||||
afterEval,
|
afterEval,
|
||||||
getTime,
|
getTime,
|
||||||
transpiler,
|
transpiler,
|
||||||
onToggle,
|
onToggle,
|
||||||
editPattern,
|
editPattern,
|
||||||
onUpdateState,
|
onUpdateState,
|
||||||
sync = false,
|
|
||||||
setInterval,
|
|
||||||
clearInterval,
|
|
||||||
id,
|
|
||||||
}) {
|
}) {
|
||||||
const state = {
|
const state = {
|
||||||
schedulerError: undefined,
|
schedulerError: undefined,
|
||||||
@@ -34,10 +30,6 @@ export function repl({
|
|||||||
started: false,
|
started: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const transpilerOptions = {
|
|
||||||
id,
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateState = (update) => {
|
const updateState = (update) => {
|
||||||
Object.assign(state, update);
|
Object.assign(state, update);
|
||||||
state.isDirty = state.code !== state.activeCode;
|
state.isDirty = state.code !== state.activeCode;
|
||||||
@@ -45,38 +37,28 @@ export function repl({
|
|||||||
onUpdateState?.(state);
|
onUpdateState?.(state);
|
||||||
};
|
};
|
||||||
|
|
||||||
const schedulerOptions = {
|
const scheduler = new Cyclist({
|
||||||
|
interval,
|
||||||
onTrigger: getTrigger({ defaultOutput, getTime }),
|
onTrigger: getTrigger({ defaultOutput, getTime }),
|
||||||
|
onError: onSchedulerError,
|
||||||
getTime,
|
getTime,
|
||||||
onToggle: (started) => {
|
onToggle: (started) => {
|
||||||
updateState({ started });
|
updateState({ started });
|
||||||
onToggle?.(started);
|
onToggle?.(started);
|
||||||
},
|
},
|
||||||
setInterval,
|
});
|
||||||
clearInterval,
|
|
||||||
beforeStart,
|
|
||||||
};
|
|
||||||
|
|
||||||
// NeoCyclist uses a shared worker to communicate between instances, which is not supported on mobile chrome
|
|
||||||
const scheduler =
|
|
||||||
sync && typeof SharedWorker != 'undefined' ? new NeoCyclist(schedulerOptions) : new Cyclist(schedulerOptions);
|
|
||||||
let pPatterns = {};
|
let pPatterns = {};
|
||||||
let anonymousIndex = 0;
|
|
||||||
let allTransform;
|
let allTransform;
|
||||||
let eachTransform;
|
|
||||||
|
|
||||||
const hush = function () {
|
const hush = function () {
|
||||||
pPatterns = {};
|
pPatterns = {};
|
||||||
anonymousIndex = 0;
|
|
||||||
allTransform = undefined;
|
allTransform = undefined;
|
||||||
eachTransform = undefined;
|
|
||||||
return silence;
|
return silence;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setPattern = async (pattern, autostart = true) => {
|
const setPattern = (pattern, autostart = true) => {
|
||||||
pattern = editPattern?.(pattern) || pattern;
|
pattern = editPattern?.(pattern) || pattern;
|
||||||
await scheduler.setPattern(pattern, autostart);
|
scheduler.setPattern(pattern, autostart);
|
||||||
return pattern;
|
|
||||||
};
|
};
|
||||||
setTime(() => scheduler.now()); // TODO: refactor?
|
setTime(() => scheduler.now()); // TODO: refactor?
|
||||||
|
|
||||||
@@ -86,50 +68,14 @@ export function repl({
|
|||||||
const toggle = () => scheduler.toggle();
|
const toggle = () => scheduler.toggle();
|
||||||
const setCps = (cps) => scheduler.setCps(cps);
|
const setCps = (cps) => scheduler.setCps(cps);
|
||||||
const setCpm = (cpm) => scheduler.setCps(cpm / 60);
|
const setCpm = (cpm) => scheduler.setCps(cpm / 60);
|
||||||
|
|
||||||
// TODO - not documented as jsdoc examples as the test framework doesn't simulate enough context for `each` and `all`..
|
|
||||||
|
|
||||||
/** Applies a function to all the running patterns. Note that the patterns are groups together into a single `stack` before the function is applied. This is probably what you want, but see `each` for
|
|
||||||
* a version that applies the function to each pattern separately.
|
|
||||||
* ```
|
|
||||||
* $: sound("bd - cp sd")
|
|
||||||
* $: sound("hh*8")
|
|
||||||
* all(fast("<2 3>"))
|
|
||||||
* ```
|
|
||||||
* ```
|
|
||||||
* $: sound("bd - cp sd")
|
|
||||||
* $: sound("hh*8")
|
|
||||||
* all(x => x.pianoroll())
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
const all = function (transform) {
|
const all = function (transform) {
|
||||||
allTransform = transform;
|
allTransform = transform;
|
||||||
return silence;
|
return silence;
|
||||||
};
|
};
|
||||||
/** Applies a function to each of the running patterns separately. This is intended for future use with upcoming 'stepwise' features. See `all` for a version that applies the function to all the patterns stacked together into a single pattern.
|
|
||||||
* ```
|
|
||||||
* $: sound("bd - cp sd")
|
|
||||||
* $: sound("hh*8")
|
|
||||||
* each(fast("<2 3>"))
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
const each = function (transform) {
|
|
||||||
eachTransform = transform;
|
|
||||||
return silence;
|
|
||||||
};
|
|
||||||
|
|
||||||
// set pattern methods that use this repl via closure
|
// set pattern methods that use this repl via closure
|
||||||
const injectPatternMethods = () => {
|
const injectPatternMethods = () => {
|
||||||
Pattern.prototype.p = function (id) {
|
Pattern.prototype.p = function (id) {
|
||||||
if (typeof id === 'string' && (id.startsWith('_') || id.endsWith('_'))) {
|
|
||||||
// allows muting a pattern x with x_ or _x
|
|
||||||
return silence;
|
|
||||||
}
|
|
||||||
if (id === '$') {
|
|
||||||
// allows adding anonymous patterns with $:
|
|
||||||
id = `$${anonymousIndex}`;
|
|
||||||
anonymousIndex++;
|
|
||||||
}
|
|
||||||
pPatterns[id] = this;
|
pPatterns[id] = this;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -158,9 +104,8 @@ export function repl({
|
|||||||
const cpm = register('cpm', function (cpm, pat) {
|
const cpm = register('cpm', function (cpm, pat) {
|
||||||
return pat._fast(cpm / 60 / scheduler.cps);
|
return pat._fast(cpm / 60 / scheduler.cps);
|
||||||
});
|
});
|
||||||
return evalScope({
|
evalScope({
|
||||||
all,
|
all,
|
||||||
each,
|
|
||||||
hush,
|
hush,
|
||||||
cpm,
|
cpm,
|
||||||
setCps,
|
setCps,
|
||||||
@@ -176,20 +121,12 @@ export function repl({
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
updateState({ code, pending: true });
|
updateState({ code, pending: true });
|
||||||
await injectPatternMethods();
|
injectPatternMethods();
|
||||||
setTime(() => scheduler.now()); // TODO: refactor?
|
|
||||||
await beforeEval?.({ code });
|
await beforeEval?.({ code });
|
||||||
shouldHush && hush();
|
shouldHush && hush();
|
||||||
let { pattern, meta } = await _evaluate(code, transpiler, transpilerOptions);
|
let { pattern, meta } = await _evaluate(code, transpiler);
|
||||||
if (Object.keys(pPatterns).length) {
|
if (Object.keys(pPatterns).length) {
|
||||||
let patterns = Object.values(pPatterns);
|
pattern = stack(...Object.values(pPatterns));
|
||||||
if (eachTransform) {
|
|
||||||
// Explicit lambda so only element (not index and array) are passed
|
|
||||||
patterns = patterns.map((x) => eachTransform(x));
|
|
||||||
}
|
|
||||||
pattern = stack(...patterns);
|
|
||||||
} else if (eachTransform) {
|
|
||||||
pattern = eachTransform(pattern);
|
|
||||||
}
|
}
|
||||||
if (allTransform) {
|
if (allTransform) {
|
||||||
pattern = allTransform(pattern);
|
pattern = allTransform(pattern);
|
||||||
@@ -199,7 +136,7 @@ export function repl({
|
|||||||
throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.'));
|
throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.'));
|
||||||
}
|
}
|
||||||
logger(`[eval] code updated`);
|
logger(`[eval] code updated`);
|
||||||
pattern = await setPattern(pattern, autostart);
|
setPattern(pattern, autostart);
|
||||||
updateState({
|
updateState({
|
||||||
miniLocations: meta?.miniLocations || [],
|
miniLocations: meta?.miniLocations || [],
|
||||||
widgets: meta?.widgets || [],
|
widgets: meta?.widgets || [],
|
||||||
@@ -213,7 +150,6 @@ export function repl({
|
|||||||
return pattern;
|
return pattern;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger(`[eval] error: ${err.message}`, 'error');
|
logger(`[eval] error: ${err.message}`, 'error');
|
||||||
console.error(err);
|
|
||||||
updateState({ evalError: err, pending: false });
|
updateState({ evalError: err, pending: false });
|
||||||
onEvalError?.(err);
|
onEvalError?.(err);
|
||||||
}
|
}
|
||||||
@@ -224,15 +160,14 @@ export function repl({
|
|||||||
|
|
||||||
export const getTrigger =
|
export const getTrigger =
|
||||||
({ getTime, defaultOutput }) =>
|
({ getTime, defaultOutput }) =>
|
||||||
async (hap, deadline, duration, cps, t) => {
|
async (hap, deadline, duration, cps) => {
|
||||||
// TODO: get rid of deadline after https://github.com/tidalcycles/strudel/pull/1004
|
|
||||||
try {
|
try {
|
||||||
if (!hap.context.onTrigger || !hap.context.dominantTrigger) {
|
if (!hap.context.onTrigger || !hap.context.dominantTrigger) {
|
||||||
await defaultOutput(hap, deadline, duration, cps, t);
|
await defaultOutput(hap, deadline, duration, cps);
|
||||||
}
|
}
|
||||||
if (hap.context.onTrigger) {
|
if (hap.context.onTrigger) {
|
||||||
// call signature of output / onTrigger is different...
|
// call signature of output / onTrigger is different...
|
||||||
await hap.context.onTrigger(getTime() + deadline, hap, getTime(), cps, t);
|
await hap.context.onTrigger(getTime() + deadline, hap, getTime(), cps);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger(`[cyclist] error: ${err.message}`, 'error');
|
logger(`[cyclist] error: ${err.message}`, 'error');
|
||||||
|
|||||||
+170
-343
@@ -1,14 +1,13 @@
|
|||||||
/*
|
/*
|
||||||
signal.mjs - continuous patterns
|
signal.mjs - <short description TODO>
|
||||||
Copyright (C) 2024 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/signal.mjs>
|
Copyright (C) 2022 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/>.
|
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 { Hap } from './hap.mjs';
|
import { Hap } from './hap.mjs';
|
||||||
import { Pattern, fastcat, pure, register, reify, silence, stack, sequenceP } from './pattern.mjs';
|
import { Pattern, fastcat, reify, silence, stack, register } from './pattern.mjs';
|
||||||
import Fraction from './fraction.mjs';
|
import Fraction from './fraction.mjs';
|
||||||
|
import { id, _mod, clamp, objectMap } from './util.mjs';
|
||||||
import { id, keyAlias, getCurrentKeyboardState } from './util.mjs';
|
|
||||||
|
|
||||||
export function steady(value) {
|
export function steady(value) {
|
||||||
// A continuous value
|
// A continuous value
|
||||||
@@ -16,10 +15,13 @@ export function steady(value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const signal = (func) => {
|
export const signal = (func) => {
|
||||||
const query = (state) => [new Hap(undefined, state.span, func(state.span.begin))];
|
const query = (state) => [new Hap(undefined, state.span, func(state.span.midpoint()))];
|
||||||
return new Pattern(query);
|
return new Pattern(query);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const isaw = signal((t) => 1 - (t % 1));
|
||||||
|
export const isaw2 = isaw.toBipolar();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A sawtooth signal between 0 and 1.
|
* A sawtooth signal between 0 and 1.
|
||||||
*
|
*
|
||||||
@@ -33,40 +35,8 @@ export const signal = (func) => {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const saw = signal((t) => t % 1);
|
export const saw = signal((t) => t % 1);
|
||||||
|
|
||||||
/**
|
|
||||||
* A sawtooth signal between -1 and 1 (like `saw`, but bipolar).
|
|
||||||
*
|
|
||||||
* @return {Pattern}
|
|
||||||
*/
|
|
||||||
export const saw2 = saw.toBipolar();
|
export const saw2 = saw.toBipolar();
|
||||||
|
|
||||||
/**
|
|
||||||
* A sawtooth signal between 1 and 0 (like `saw`, but flipped).
|
|
||||||
*
|
|
||||||
* @return {Pattern}
|
|
||||||
* @example
|
|
||||||
* note("<c3 [eb3,g3] g2 [g3,bb3]>*8")
|
|
||||||
* .clip(isaw.slow(2))
|
|
||||||
* @example
|
|
||||||
* n(isaw.range(0,8).segment(8))
|
|
||||||
* .scale('C major')
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const isaw = signal((t) => 1 - (t % 1));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A sawtooth signal between 1 and -1 (like `saw2`, but flipped).
|
|
||||||
*
|
|
||||||
* @return {Pattern}
|
|
||||||
*/
|
|
||||||
export const isaw2 = isaw.toBipolar();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A sine signal between -1 and 1 (like `sine`, but bipolar).
|
|
||||||
*
|
|
||||||
* @return {Pattern}
|
|
||||||
*/
|
|
||||||
export const sine2 = signal((t) => Math.sin(Math.PI * 2 * t));
|
export const sine2 = signal((t) => Math.sin(Math.PI * 2 * t));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -90,12 +60,6 @@ export const sine = sine2.fromBipolar();
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const cosine = sine._early(Fraction(1).div(4));
|
export const cosine = sine._early(Fraction(1).div(4));
|
||||||
|
|
||||||
/**
|
|
||||||
* A cosine signal between -1 and 1 (like `cosine`, but bipolar).
|
|
||||||
*
|
|
||||||
* @return {Pattern}
|
|
||||||
*/
|
|
||||||
export const cosine2 = sine2._early(Fraction(1).div(4));
|
export const cosine2 = sine2._early(Fraction(1).div(4));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,12 +71,6 @@ export const cosine2 = sine2._early(Fraction(1).div(4));
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const square = signal((t) => Math.floor((t * 2) % 2));
|
export const square = signal((t) => Math.floor((t * 2) % 2));
|
||||||
|
|
||||||
/**
|
|
||||||
* A square signal between -1 and 1 (like `square`, but bipolar).
|
|
||||||
*
|
|
||||||
* @return {Pattern}
|
|
||||||
*/
|
|
||||||
export const square2 = square.toBipolar();
|
export const square2 = square.toBipolar();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,71 +81,11 @@ export const square2 = square.toBipolar();
|
|||||||
* n(tri.segment(8).range(0,7)).scale("C:minor")
|
* n(tri.segment(8).range(0,7)).scale("C:minor")
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const tri = fastcat(saw, isaw);
|
export const tri = fastcat(isaw, saw);
|
||||||
|
export const tri2 = fastcat(isaw2, saw2);
|
||||||
|
|
||||||
/**
|
|
||||||
* A triangle signal between -1 and 1 (like `tri`, but bipolar).
|
|
||||||
*
|
|
||||||
* @return {Pattern}
|
|
||||||
*/
|
|
||||||
export const tri2 = fastcat(saw2, isaw2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An inverted triangle signal between 1 and 0 (like `tri`, but flipped).
|
|
||||||
*
|
|
||||||
* @return {Pattern}
|
|
||||||
* @example
|
|
||||||
* n(itri.segment(8).range(0,7)).scale("C:minor")
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export const itri = fastcat(isaw, saw);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An inverted triangle signal between -1 and 1 (like `itri`, but bipolar).
|
|
||||||
*
|
|
||||||
* @return {Pattern}
|
|
||||||
*/
|
|
||||||
export const itri2 = fastcat(isaw2, saw2);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A signal representing the cycle time.
|
|
||||||
*
|
|
||||||
* @return {Pattern}
|
|
||||||
*/
|
|
||||||
export const time = signal(id);
|
export const time = signal(id);
|
||||||
|
|
||||||
/**
|
|
||||||
* The mouse's x position value ranges from 0 to 1.
|
|
||||||
* @name mousex
|
|
||||||
* @return {Pattern}
|
|
||||||
* @example
|
|
||||||
* n(mousex.segment(4).range(0,7)).scale("C:minor")
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The mouse's y position value ranges from 0 to 1.
|
|
||||||
* @name mousey
|
|
||||||
* @return {Pattern}
|
|
||||||
* @example
|
|
||||||
* n(mousey.segment(4).range(0,7)).scale("C:minor")
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
let _mouseY = 0,
|
|
||||||
_mouseX = 0;
|
|
||||||
if (typeof window !== 'undefined') {
|
|
||||||
//document.onmousemove = (e) => {
|
|
||||||
document.addEventListener('mousemove', (e) => {
|
|
||||||
_mouseY = e.clientY / document.body.clientHeight;
|
|
||||||
_mouseX = e.clientX / document.body.clientWidth;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const mousey = signal(() => _mouseY);
|
|
||||||
export const mouseY = signal(() => _mouseY);
|
|
||||||
export const mousex = signal(() => _mouseX);
|
|
||||||
export const mouseX = signal(() => _mouseX);
|
|
||||||
|
|
||||||
// random signals
|
// random signals
|
||||||
|
|
||||||
const xorwise = (x) => {
|
const xorwise = (x) => {
|
||||||
@@ -208,7 +106,7 @@ const timeToRand = (x) => Math.abs(intSeedToRand(timeToIntSeed(x)));
|
|||||||
const timeToRandsPrime = (seed, n) => {
|
const timeToRandsPrime = (seed, n) => {
|
||||||
const result = [];
|
const result = [];
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
for (let i = 0; i < n; ++i) {
|
for (let i = 0; i < n; ++n) {
|
||||||
result.push(intSeedToRand(seed));
|
result.push(intSeedToRand(seed));
|
||||||
seed = xorwise(seed);
|
seed = xorwise(seed);
|
||||||
}
|
}
|
||||||
@@ -227,82 +125,7 @@ const timeToRands = (t, n) => timeToRandsPrime(timeToIntSeed(t), n);
|
|||||||
* n(run(4)).scale("C4:pentatonic")
|
* n(run(4)).scale("C4:pentatonic")
|
||||||
* // n("0 1 2 3").scale("C4:pentatonic")
|
* // n("0 1 2 3").scale("C4:pentatonic")
|
||||||
*/
|
*/
|
||||||
export const run = (n) => saw.range(0, n).round().segment(n);
|
export const run = (n) => saw.range(0, n).floor().segment(n);
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a pattern from a binary number.
|
|
||||||
*
|
|
||||||
* @name binary
|
|
||||||
* @param {number} n - input number to convert to binary
|
|
||||||
* @example
|
|
||||||
* "hh".s().struct(binary(5))
|
|
||||||
* // "hh".s().struct("1 0 1")
|
|
||||||
*/
|
|
||||||
export const binary = (n) => {
|
|
||||||
const nBits = reify(n).log2(0).floor().add(1);
|
|
||||||
return binaryN(n, nBits);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a pattern from a binary number, padded to n bits long.
|
|
||||||
*
|
|
||||||
* @name binaryN
|
|
||||||
* @param {number} n - input number to convert to binary
|
|
||||||
* @param {number} nBits - pattern length, defaults to 16
|
|
||||||
* @example
|
|
||||||
* "hh".s().struct(binaryN(55532, 16))
|
|
||||||
* // "hh".s().struct("1 1 0 1 1 0 0 0 1 1 1 0 1 1 0 0")
|
|
||||||
*/
|
|
||||||
export const binaryN = (n, nBits = 16) => {
|
|
||||||
nBits = reify(nBits);
|
|
||||||
// Shift and mask, putting msb on the right-side
|
|
||||||
const bitPos = run(nBits).mul(-1).add(nBits.sub(1));
|
|
||||||
return reify(n).segment(nBits).brshift(bitPos).band(pure(1));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const randrun = (n) => {
|
|
||||||
return signal((t) => {
|
|
||||||
// Without adding 0.5, the first cycle is always 0,1,2,3,...
|
|
||||||
const rands = timeToRands(t.floor().add(0.5), n);
|
|
||||||
const nums = rands
|
|
||||||
.map((n, i) => [n, i])
|
|
||||||
.sort((a, b) => a[0] > b[0] - a[0] < b[0])
|
|
||||||
.map((x) => x[1]);
|
|
||||||
const i = t.cyclePos().mul(n).floor() % n;
|
|
||||||
return nums[i];
|
|
||||||
})._segment(n);
|
|
||||||
};
|
|
||||||
|
|
||||||
const _rearrangeWith = (ipat, n, pat) => {
|
|
||||||
const pats = [...Array(n).keys()].map((i) => pat.zoom(Fraction(i).div(n), Fraction(i + 1).div(n)));
|
|
||||||
return ipat.fmap((i) => pats[i].repeatCycles(n)._fast(n)).innerJoin();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Slices a pattern into the given number of parts, then plays those parts in random order.
|
|
||||||
* Each part will be played exactly once per cycle.
|
|
||||||
* @name shuffle
|
|
||||||
* @example
|
|
||||||
* note("c d e f").sound("piano").shuffle(4)
|
|
||||||
* @example
|
|
||||||
* note("c d e f".shuffle(4), "g").sound("piano")
|
|
||||||
*/
|
|
||||||
export const shuffle = register('shuffle', (n, pat) => {
|
|
||||||
return _rearrangeWith(randrun(n), n, pat);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Slices a pattern into the given number of parts, then plays those parts at random. Similar to `shuffle`,
|
|
||||||
* but parts might be played more than once, or not at all, per cycle.
|
|
||||||
* @name scramble
|
|
||||||
* @example
|
|
||||||
* note("c d e f").sound("piano").scramble(4)
|
|
||||||
* @example
|
|
||||||
* note("c d e f".scramble(4), "g").sound("piano")
|
|
||||||
*/
|
|
||||||
export const scramble = register('scramble', (n, pat) => {
|
|
||||||
return _rearrangeWith(_irand(n)._segment(n), n, pat);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A continuous pattern of random numbers, between 0 and 1.
|
* A continuous pattern of random numbers, between 0 and 1.
|
||||||
@@ -320,24 +143,7 @@ export const rand = signal(timeToRand);
|
|||||||
export const rand2 = rand.toBipolar();
|
export const rand2 = rand.toBipolar();
|
||||||
|
|
||||||
export const _brandBy = (p) => rand.fmap((x) => x < p);
|
export const _brandBy = (p) => rand.fmap((x) => x < p);
|
||||||
|
|
||||||
/**
|
|
||||||
* A continuous pattern of 0 or 1 (binary random), with a probability for the value being 1
|
|
||||||
*
|
|
||||||
* @name brandBy
|
|
||||||
* @param {number} probability - a number between 0 and 1
|
|
||||||
* @example
|
|
||||||
* s("hh*10").pan(brandBy(0.2))
|
|
||||||
*/
|
|
||||||
export const brandBy = (pPat) => reify(pPat).fmap(_brandBy).innerJoin();
|
export const brandBy = (pPat) => reify(pPat).fmap(_brandBy).innerJoin();
|
||||||
|
|
||||||
/**
|
|
||||||
* A continuous pattern of 0 or 1 (binary random)
|
|
||||||
*
|
|
||||||
* @name brand
|
|
||||||
* @example
|
|
||||||
* s("hh*10").pan(brand)
|
|
||||||
*/
|
|
||||||
export const brand = _brandBy(0.5);
|
export const brand = _brandBy(0.5);
|
||||||
|
|
||||||
export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i));
|
export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i));
|
||||||
@@ -354,6 +160,143 @@ export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i));
|
|||||||
*/
|
*/
|
||||||
export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin();
|
export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin();
|
||||||
|
|
||||||
|
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));
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
/** * 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.
|
||||||
|
* @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 = register('inhabit', function (lookup, pat) {
|
||||||
|
return _pick(lookup, pat, true).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.
|
||||||
|
* @param {Pattern} pat
|
||||||
|
* @param {*} xs
|
||||||
|
* @returns {Pattern}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const inhabitmod = register('inhabit', function (lookup, pat) {
|
||||||
|
return _pick(lookup, pat, false).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();
|
||||||
|
};
|
||||||
|
|
||||||
export const __chooseWith = (pat, xs) => {
|
export const __chooseWith = (pat, xs) => {
|
||||||
xs = xs.map(reify);
|
xs = xs.map(reify);
|
||||||
if (xs.length == 0) {
|
if (xs.length == 0) {
|
||||||
@@ -393,8 +336,6 @@ export const chooseInWith = (pat, xs) => {
|
|||||||
* Chooses randomly from the given list of elements.
|
* Chooses randomly from the given list of elements.
|
||||||
* @param {...any} xs values / patterns to choose from.
|
* @param {...any} xs values / patterns to choose from.
|
||||||
* @returns {Pattern} - a continuous pattern.
|
* @returns {Pattern} - a continuous pattern.
|
||||||
* @example
|
|
||||||
* note("c2 g2!2 d2 f1").s(choose("sine", "triangle", "bd:6"))
|
|
||||||
*/
|
*/
|
||||||
export const choose = (...xs) => chooseWith(rand, xs);
|
export const choose = (...xs) => chooseWith(rand, xs);
|
||||||
|
|
||||||
@@ -421,7 +362,6 @@ Pattern.prototype.choose2 = function (...xs) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Picks one of the elements at random each cycle.
|
* Picks one of the elements at random each cycle.
|
||||||
* @synonyms randcat
|
|
||||||
* @returns {Pattern}
|
* @returns {Pattern}
|
||||||
* @example
|
* @example
|
||||||
* chooseCycles("bd", "hh", "sd").s().fast(8)
|
* chooseCycles("bd", "hh", "sd").s().fast(8)
|
||||||
@@ -433,58 +373,26 @@ export const chooseCycles = (...xs) => chooseInWith(rand.segment(1), xs);
|
|||||||
export const randcat = chooseCycles;
|
export const randcat = chooseCycles;
|
||||||
|
|
||||||
const _wchooseWith = function (pat, ...pairs) {
|
const _wchooseWith = function (pat, ...pairs) {
|
||||||
// A list of patterns of values
|
|
||||||
const values = pairs.map((pair) => reify(pair[0]));
|
const values = pairs.map((pair) => reify(pair[0]));
|
||||||
|
|
||||||
// A list of weight patterns
|
|
||||||
const weights = [];
|
const weights = [];
|
||||||
|
let accum = 0;
|
||||||
let total = pure(0);
|
|
||||||
for (const pair of pairs) {
|
for (const pair of pairs) {
|
||||||
// 'add' accepts either values or patterns of values here, so no need
|
accum += pair[1];
|
||||||
// to explicitly reify
|
weights.push(accum);
|
||||||
total = total.add(pair[1]);
|
|
||||||
// accumulate our list of weight patterns
|
|
||||||
weights.push(total);
|
|
||||||
}
|
}
|
||||||
// a pattern of lists of weights
|
const total = accum;
|
||||||
const weightspat = sequenceP(weights);
|
|
||||||
|
|
||||||
// Takes a number from 0-1, returns a pattern of patterns of values
|
|
||||||
const match = function (r) {
|
const match = function (r) {
|
||||||
const findpat = total.mul(r);
|
const find = r * total;
|
||||||
return weightspat.fmap((weights) => (find) => values[weights.findIndex((x) => x > find, weights)]).appLeft(findpat);
|
return values[weights.findIndex((x) => x > find, weights)];
|
||||||
};
|
};
|
||||||
// This returns a pattern of patterns.. The innerJoin is in wchooseCycles
|
return pat.fmap(match);
|
||||||
return pat.bind(match);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const wchooseWith = (...args) => _wchooseWith(...args).outerJoin();
|
const wchooseWith = (...args) => _wchooseWith(...args).outerJoin();
|
||||||
|
|
||||||
/**
|
|
||||||
* Chooses randomly from the given list of elements by giving a probability to each element
|
|
||||||
* @param {...any} pairs arrays of value and weight
|
|
||||||
* @returns {Pattern} - a continuous pattern.
|
|
||||||
* @example
|
|
||||||
* note("c2 g2!2 d2 f1").s(wchoose(["sine",10], ["triangle",1], ["bd:6",1]))
|
|
||||||
*/
|
|
||||||
export const wchoose = (...pairs) => wchooseWith(rand, ...pairs);
|
export const wchoose = (...pairs) => wchooseWith(rand, ...pairs);
|
||||||
|
|
||||||
/**
|
export const wchooseCycles = (...pairs) => _wchooseWith(rand, ...pairs).innerJoin();
|
||||||
* Picks one of the elements at random each cycle by giving a probability to each element
|
|
||||||
* @synonyms wrandcat
|
|
||||||
* @returns {Pattern}
|
|
||||||
* @example
|
|
||||||
* wchooseCycles(["bd",10], ["hh",1], ["sd",1]).s().fast(8)
|
|
||||||
* @example
|
|
||||||
* wchooseCycles(["bd bd bd",5], ["hh hh hh",3], ["sd sd sd",1]).fast(4).s()
|
|
||||||
* @example
|
|
||||||
* // The probability can itself be a pattern
|
|
||||||
* wchooseCycles(["bd(3,8)","<5 0>"], ["hh hh hh",3]).fast(4).s()
|
|
||||||
*/
|
|
||||||
export const wchooseCycles = (...pairs) => _wchooseWith(rand.segment(1), ...pairs).innerJoin();
|
|
||||||
|
|
||||||
export const wrandcat = wchooseCycles;
|
|
||||||
|
|
||||||
// this function expects pat to be a pattern of floats...
|
// this function expects pat to be a pattern of floats...
|
||||||
export const perlinWith = (pat) => {
|
export const perlinWith = (pat) => {
|
||||||
@@ -506,11 +414,8 @@ export const perlinWith = (pat) => {
|
|||||||
*/
|
*/
|
||||||
export const perlin = perlinWith(time.fmap((v) => Number(v)));
|
export const perlin = perlinWith(time.fmap((v) => Number(v)));
|
||||||
|
|
||||||
export const degradeByWith = register(
|
export const degradeByWith = register('degradeByWith', (withPat, x, pat) =>
|
||||||
'degradeByWith',
|
pat.fmap((a) => (_) => a).appLeft(withPat.filterValues((v) => v > x)),
|
||||||
(withPat, x, pat) => pat.fmap((a) => (_) => a).appLeft(withPat.filterValues((v) => v > x)),
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -526,18 +431,10 @@ export const degradeByWith = register(
|
|||||||
* s("hh*8").degradeBy(0.2)
|
* s("hh*8").degradeBy(0.2)
|
||||||
* @example
|
* @example
|
||||||
* s("[hh?0.2]*8")
|
* s("[hh?0.2]*8")
|
||||||
* @example
|
|
||||||
* //beat generator
|
|
||||||
* s("bd").segment(16).degradeBy(.5).ribbon(16,1)
|
|
||||||
*/
|
*/
|
||||||
export const degradeBy = register(
|
export const degradeBy = register('degradeBy', function (x, pat) {
|
||||||
'degradeBy',
|
return pat._degradeByWith(rand, x);
|
||||||
function (x, pat) {
|
});
|
||||||
return pat._degradeByWith(rand, x);
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -551,7 +448,7 @@ export const degradeBy = register(
|
|||||||
* @example
|
* @example
|
||||||
* s("[hh?]*8")
|
* s("[hh?]*8")
|
||||||
*/
|
*/
|
||||||
export const degrade = register('degrade', (pat) => pat._degradeBy(0.5), true, true);
|
export const degrade = register('degrade', (pat) => pat._degradeBy(0.5));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inverse of `degradeBy`: Randomly removes events from the pattern by a given amount.
|
* Inverse of `degradeBy`: Randomly removes events from the pattern by a given amount.
|
||||||
@@ -565,40 +462,15 @@ export const degrade = register('degrade', (pat) => pat._degradeBy(0.5), true, t
|
|||||||
* @returns Pattern
|
* @returns Pattern
|
||||||
* @example
|
* @example
|
||||||
* s("hh*8").undegradeBy(0.2)
|
* s("hh*8").undegradeBy(0.2)
|
||||||
* @example
|
|
||||||
* s("hh*10").layer(
|
|
||||||
* x => x.degradeBy(0.2).pan(0),
|
|
||||||
* x => x.undegradeBy(0.8).pan(1)
|
|
||||||
* )
|
|
||||||
*/
|
*/
|
||||||
export const undegradeBy = register(
|
export const undegradeBy = register('undegradeBy', function (x, pat) {
|
||||||
'undegradeBy',
|
return pat._degradeByWith(
|
||||||
function (x, pat) {
|
rand.fmap((r) => 1 - r),
|
||||||
return pat._degradeByWith(
|
x,
|
||||||
rand.fmap((r) => 1 - r),
|
);
|
||||||
x,
|
});
|
||||||
);
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
export const undegrade = register('undegrade', (pat) => pat._undegradeBy(0.5));
|
||||||
* Inverse of `degrade`: Randomly removes 50% of events from the pattern. Shorthand for `.undegradeBy(0.5)`
|
|
||||||
* Events that would be removed by degrade are let through by undegrade and vice versa (see second example).
|
|
||||||
*
|
|
||||||
* @name undegrade
|
|
||||||
* @memberof Pattern
|
|
||||||
* @returns Pattern
|
|
||||||
* @example
|
|
||||||
* s("hh*8").undegrade()
|
|
||||||
* @example
|
|
||||||
* s("hh*10").layer(
|
|
||||||
* x => x.degrade().pan(0),
|
|
||||||
* x => x.undegrade().pan(1)
|
|
||||||
* )
|
|
||||||
*/
|
|
||||||
export const undegrade = register('undegrade', (pat) => pat._undegradeBy(0.5), true, true);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -757,48 +629,3 @@ export const never = register('never', function (_, pat) {
|
|||||||
export const always = register('always', function (func, pat) {
|
export const always = register('always', function (func, pat) {
|
||||||
return func(pat);
|
return func(pat);
|
||||||
});
|
});
|
||||||
|
|
||||||
//keyname: string | Array<string>
|
|
||||||
//keyname reference: https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values
|
|
||||||
export function _keyDown(keyname) {
|
|
||||||
if (Array.isArray(keyname) === false) {
|
|
||||||
keyname = [keyname];
|
|
||||||
}
|
|
||||||
const keyState = getCurrentKeyboardState();
|
|
||||||
return keyname.every((x) => {
|
|
||||||
const keyName = keyAlias.get(x) ?? x;
|
|
||||||
return keyState[keyName];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Do something on a keypress, or array of keypresses
|
|
||||||
* [Key name reference](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values)
|
|
||||||
*
|
|
||||||
* @name whenKey
|
|
||||||
* @memberof Pattern
|
|
||||||
* @returns Pattern
|
|
||||||
* @example
|
|
||||||
* s("bd(5,8)").whenKey("Control:j", x => x.segment(16).color("red")).whenKey("Control:i", x => x.fast(2).color("blue"))
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const whenKey = register('whenKey', function (input, func, pat) {
|
|
||||||
return pat.when(_keyDown(input), func);
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* returns true when a key or array of keys is held
|
|
||||||
* [Key name reference](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values)
|
|
||||||
*
|
|
||||||
* @name keyDown
|
|
||||||
* @memberof Pattern
|
|
||||||
* @returns Pattern
|
|
||||||
* @example
|
|
||||||
* keyDown("Control:j").pick([s("bd(5,8)"), s("cp(3,8)")])
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const keyDown = register('keyDown', function (pat) {
|
|
||||||
return pat.fmap(_keyDown);
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import { Pattern } from './index.mjs';
|
||||||
|
|
||||||
|
// polar coords -> xy
|
||||||
|
function fromPolar(angle, radius, cx, cy) {
|
||||||
|
const radians = ((angle - 90) * Math.PI) / 180;
|
||||||
|
return [cx + Math.cos(radians) * radius, cy + Math.sin(radians) * radius];
|
||||||
|
}
|
||||||
|
|
||||||
|
const xyOnSpiral = (angle, margin, cx, cy, rotate = 0) => fromPolar((angle + rotate) * 360, margin * angle, cx, cy); // TODO: logSpiral
|
||||||
|
|
||||||
|
// draw spiral / segment of spiral
|
||||||
|
function spiralSegment(options) {
|
||||||
|
let {
|
||||||
|
ctx,
|
||||||
|
from = 0,
|
||||||
|
to = 3,
|
||||||
|
margin = 50,
|
||||||
|
cx = 100,
|
||||||
|
cy = 100,
|
||||||
|
rotate = 0,
|
||||||
|
thickness = margin / 2,
|
||||||
|
color = '#0000ff30',
|
||||||
|
cap = 'round',
|
||||||
|
stretch = 1,
|
||||||
|
fromOpacity = 1,
|
||||||
|
toOpacity = 1,
|
||||||
|
} = options;
|
||||||
|
from *= stretch;
|
||||||
|
to *= stretch;
|
||||||
|
rotate *= stretch;
|
||||||
|
ctx.lineWidth = thickness;
|
||||||
|
ctx.lineCap = cap;
|
||||||
|
ctx.strokeStyle = color;
|
||||||
|
ctx.globalAlpha = fromOpacity;
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
let [sx, sy] = xyOnSpiral(from, margin, cx, cy, rotate);
|
||||||
|
ctx.moveTo(sx, sy);
|
||||||
|
|
||||||
|
const increment = 1 / 60;
|
||||||
|
let angle = from;
|
||||||
|
while (angle <= to) {
|
||||||
|
const [x, y] = xyOnSpiral(angle, margin, cx, cy, rotate);
|
||||||
|
//ctx.lineWidth = angle*thickness;
|
||||||
|
ctx.globalAlpha = ((angle - from) / (to - from)) * toOpacity;
|
||||||
|
ctx.lineTo(x, y);
|
||||||
|
angle += increment;
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
Pattern.prototype.spiral = function (options = {}) {
|
||||||
|
const {
|
||||||
|
stretch = 1,
|
||||||
|
size = 80,
|
||||||
|
thickness = size / 2,
|
||||||
|
cap = 'butt', // round butt squar,
|
||||||
|
inset = 3, // start angl,
|
||||||
|
playheadColor = '#ffffff90',
|
||||||
|
playheadLength = 0.02,
|
||||||
|
playheadThickness = thickness,
|
||||||
|
padding = 0,
|
||||||
|
steady = 1,
|
||||||
|
inactiveColor = '#ffffff20',
|
||||||
|
colorizeInactive = 0,
|
||||||
|
fade = true,
|
||||||
|
// logSpiral = true,
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
function spiral({ ctx, time, haps, drawTime }) {
|
||||||
|
const [w, h] = [ctx.canvas.width, ctx.canvas.height];
|
||||||
|
ctx.clearRect(0, 0, w * 2, h * 2);
|
||||||
|
const [cx, cy] = [w / 2, h / 2];
|
||||||
|
const settings = {
|
||||||
|
margin: size / stretch,
|
||||||
|
cx,
|
||||||
|
cy,
|
||||||
|
stretch,
|
||||||
|
cap,
|
||||||
|
thickness,
|
||||||
|
};
|
||||||
|
|
||||||
|
const playhead = {
|
||||||
|
...settings,
|
||||||
|
thickness: playheadThickness,
|
||||||
|
from: inset - playheadLength,
|
||||||
|
to: inset,
|
||||||
|
color: playheadColor,
|
||||||
|
};
|
||||||
|
|
||||||
|
const [min] = drawTime;
|
||||||
|
const rotate = steady * time;
|
||||||
|
haps.forEach((hap) => {
|
||||||
|
const isActive = hap.whole.begin <= time && hap.endClipped > time;
|
||||||
|
const from = hap.whole.begin - time + inset;
|
||||||
|
const to = hap.endClipped - time + inset - padding;
|
||||||
|
const { color } = hap.context;
|
||||||
|
const opacity = fade ? 1 - Math.abs((hap.whole.begin - time) / min) : 1;
|
||||||
|
spiralSegment({
|
||||||
|
ctx,
|
||||||
|
...settings,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
rotate,
|
||||||
|
color: colorizeInactive || isActive ? color : inactiveColor,
|
||||||
|
fromOpacity: opacity,
|
||||||
|
toOpacity: opacity,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
spiralSegment({
|
||||||
|
ctx,
|
||||||
|
...playhead,
|
||||||
|
rotate,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.onPaint((ctx, time, haps, drawTime) => spiral({ ctx, time, haps, drawTime }));
|
||||||
|
};
|
||||||
@@ -4,43 +4,25 @@ Copyright (C) 2023 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 { s, pan, getControlName } from '../controls.mjs';
|
import controls from '../controls.mjs';
|
||||||
import { mini } from '../../mini/mini.mjs';
|
import { mini } from '../../mini/mini.mjs';
|
||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import Fraction from '../fraction.mjs';
|
|
||||||
|
|
||||||
describe('controls', () => {
|
describe('controls', () => {
|
||||||
it('should support controls', () => {
|
it('should support controls', () => {
|
||||||
expect(s('bd').firstCycleValues).toEqual([{ s: 'bd' }]);
|
expect(controls.s('bd').firstCycleValues).toEqual([{ s: 'bd' }]);
|
||||||
});
|
});
|
||||||
it('should support compound controls', () => {
|
it('should support compound controls', () => {
|
||||||
expect(s(mini('bd:3')).firstCycleValues).toEqual([{ s: 'bd', n: 3 }]);
|
expect(controls.s(mini('bd:3')).firstCycleValues).toEqual([{ s: 'bd', n: 3 }]);
|
||||||
expect(s(mini('bd:3 sd:4:1.4')).firstCycleValues).toEqual([
|
expect(controls.s(mini('bd:3 sd:4:1.4')).firstCycleValues).toEqual([
|
||||||
{ s: 'bd', n: 3 },
|
{ s: 'bd', n: 3 },
|
||||||
{ s: 'sd', n: 4, gain: 1.4 },
|
{ s: 'sd', n: 4, gain: 1.4 },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
it('should support ignore extra elements in compound controls', () => {
|
it('should support ignore extra elements in compound controls', () => {
|
||||||
expect(s(mini('bd:3:0.4 sd:4:0.5:3:17')).firstCycleValues).toEqual([
|
expect(controls.s(mini('bd:3:0.4 sd:4:0.5:3:17')).firstCycleValues).toEqual([
|
||||||
{ s: 'bd', n: 3, gain: 0.4 },
|
{ s: 'bd', n: 3, gain: 0.4 },
|
||||||
{ s: 'sd', n: 4, gain: 0.5 },
|
{ s: 'sd', n: 4, gain: 0.5 },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
it('should support nested controls', () => {
|
|
||||||
expect(s(mini('bd').pan(1)).firstCycleValues).toEqual([{ s: 'bd', pan: 1 }]);
|
|
||||||
expect(s(mini('bd:1').pan(1)).firstCycleValues).toEqual([{ s: 'bd', n: 1, pan: 1 }]);
|
|
||||||
});
|
|
||||||
it('preserves step count of the left pattern', () => {
|
|
||||||
expect(s(mini('bd cp mt').pan(mini('1 2 3 4')))._steps).toEqual(Fraction(3));
|
|
||||||
});
|
|
||||||
it('preserves step count of the right pattern for .out', () => {
|
|
||||||
expect(s(mini('bd cp mt').set.out(pan(mini('1 2 3 4'))))._steps).toEqual(Fraction(4));
|
|
||||||
});
|
|
||||||
it('combines step count of the pattern for .mix as lcm', () => {
|
|
||||||
expect(s(mini('bd cp mt').set.mix(pan(mini('1 2 3 4'))))._steps).toEqual(Fraction(12));
|
|
||||||
});
|
|
||||||
it('finds control name by alias', () => {
|
|
||||||
expect(getControlName('lpf')).toEqual('cutoff');
|
|
||||||
expect(getControlName('cutoff')).toEqual('cutoff');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user