+
+
+ {entry.name}
+
+ {entry.tags && (
+
+ {entry.tags.join(', ')}
+
+ )}
+
{!!entry.synonyms_text && (
Synonyms: {entry.synonyms_text}
From a4212589e5e0a2d3d6e9a31bf196f30e557b24e3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Va=CC=81clav=20Volhejn?=
Date: Sun, 12 Oct 2025 16:33:07 +0200
Subject: [PATCH 009/124] Recategorize
---
packages/core/controls.mjs | 36 ++++++++++++++--------------
packages/core/pattern.mjs | 20 ++++++++--------
packages/core/signal.mjs | 48 +++++++++++++++++++-------------------
3 files changed, 52 insertions(+), 52 deletions(-)
diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs
index 4e60fc487..db689e1a2 100644
--- a/packages/core/controls.mjs
+++ b/packages/core/controls.mjs
@@ -1621,7 +1621,7 @@ export const { fadeInTime } = registerControl('fadeInTime');
* Set frequency of sound.
*
* @name freq
- * @tags transforms
+ * @tags temporal
* @param {number | Pattern} frequency in Hz. the audible range is between 20 and 20000 Hz
* @example
* freq("220 110 440 110").s("superzow").osc()
@@ -2205,7 +2205,7 @@ export const { cps } = registerControl('cps');
* Multiplies the duration with the given number. Also cuts samples off at the end if they exceed the duration.
*
* @name clip
- * @tags transforms
+ * @tags temporal
* @synonyms legato
* @param {number | Pattern} factor >= 0
* @example
@@ -2218,7 +2218,7 @@ export const { clip, legato } = registerControl('clip', 'legato');
* Sets the duration of the event in cycles. Similar to clip / legato, it also cuts samples off at the end if they exceed the duration.
*
* @name duration
- * @tags transforms
+ * @tags temporal
* @synonyms dur
* @param {number | Pattern} seconds >= 0
* @example
@@ -2297,7 +2297,7 @@ export const ar = register('ar', (t, pat) => {
* MIDI channel: Sets the MIDI channel for the event.
*
* @name midichan
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} channel MIDI channel number (0-15)
* @example
* note("c4").midichan(1).midi()
@@ -2310,7 +2310,7 @@ export const { midimap } = registerControl('midimap');
* MIDI port: Sets the MIDI port for the event.
*
* @name midiport
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} port MIDI port
* @example
* note("c a f e").midiport("<0 1 2 3>").midi()
@@ -2321,7 +2321,7 @@ export const { midiport } = registerControl('midiport');
* MIDI command: Sends a MIDI command message.
*
* @name midicmd
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} command MIDI command
* @example
* midicmd("clock*48,/2").midi()
@@ -2332,7 +2332,7 @@ export const { midicmd } = registerControl('midicmd');
* MIDI control: Sends a MIDI control change message.
*
* @name control
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} MIDI control number (0-127)
* @param {number | Pattern} MIDI controller value (0-127)
*/
@@ -2348,7 +2348,7 @@ export const control = register('control', (args, pat) => {
* MIDI control number: Sends a MIDI control change message.
*
* @name ccn
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} MIDI control number (0-127)
*/
export const { ccn } = registerControl('ccn');
@@ -2356,7 +2356,7 @@ export const { ccn } = registerControl('ccn');
* MIDI control value: Sends a MIDI control change message.
*
* @name ccv
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} MIDI control value (0-127)
*/
export const { ccv } = registerControl('ccv');
@@ -2366,7 +2366,7 @@ export const { ctlNum } = registerControl('ctlNum');
/**
* MIDI NRPN non-registered parameter number: Sends a MIDI NRPN non-registered parameter number message.
* @name nrpnn
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} nrpnn MIDI NRPN non-registered parameter number (0-127)
* @example
* note("c4").nrpnn("1:8").nrpv("123").midichan(1).midi()
@@ -2375,7 +2375,7 @@ export const { nrpnn } = registerControl('nrpnn');
/**
* MIDI NRPN non-registered parameter value: Sends a MIDI NRPN non-registered parameter value message.
* @name nrpv
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} nrpv MIDI NRPN non-registered parameter value (0-127)
* @example
* note("c4").nrpnn("1:8").nrpv("123").midichan(1).midi()
@@ -2386,7 +2386,7 @@ export const { nrpv } = registerControl('nrpv');
* MIDI program number: Sends a MIDI program change message.
*
* @name progNum
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} program MIDI program number (0-127)
* @example
* note("c4").progNum(10).midichan(1).midi()
@@ -2396,7 +2396,7 @@ export const { progNum } = registerControl('progNum');
/**
* MIDI sysex: Sends a MIDI sysex message.
* @name sysex
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} id Sysex ID
* @param {number | Pattern} data Sysex data
* @example
@@ -2412,7 +2412,7 @@ export const sysex = register('sysex', (args, pat) => {
/**
* MIDI sysex ID: Sends a MIDI sysex identifier message.
* @name sysexid
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} id Sysex ID
* @example
* note("c4").sysexid("0x77").sysexdata("0x01:0x02:0x03:0x04").midichan(1).midi()
@@ -2421,7 +2421,7 @@ export const { sysexid } = registerControl('sysexid');
/**
* MIDI sysex data: Sends a MIDI sysex message.
* @name sysexdata
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} data Sysex data
* @example
* note("c4").sysexid("0x77").sysexdata("0x01:0x02:0x03:0x04").midichan(1).midi()
@@ -2431,7 +2431,7 @@ export const { sysexdata } = registerControl('sysexdata');
/**
* MIDI pitch bend: Sends a MIDI pitch bend message.
* @name midibend
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} midibend MIDI pitch bend (-1 - 1)
* @example
* note("c4").midibend(sine.slow(4).range(-0.4,0.4)).midi()
@@ -2440,7 +2440,7 @@ export const { midibend } = registerControl('midibend');
/**
* MIDI key after touch: Sends a MIDI key after touch message.
* @name miditouch
- * @tags examples
+ * @tags external_io
* @param {number | Pattern} miditouch MIDI key after touch (0-1)
* @example
* note("c4").miditouch(sine.slow(4).range(0,1)).midi()
@@ -2461,7 +2461,7 @@ export const getControlName = (alias) => {
* Sets properties in a batch.
*
* @name as
- * @tags transforms
+ * @tags temporal
* @param {String | Array} mapping the control names that are set
* @example
* "c:.5 a:1 f:.25 e:.8".as("note:clip")
diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs
index 2d6459a89..4a0dbe58f 100644
--- a/packages/core/pattern.mjs
+++ b/packages/core/pattern.mjs
@@ -978,7 +978,7 @@ Pattern.prototype.collect = function () {
/**
* Selects indices in in stacked notes.
- * @tags transforms
+ * @tags temporal
* @example
* note("<[c,eb,g]!2 [c,f,ab] [d,f,ab]>")
* .arpWith(haps => haps[2])
@@ -993,7 +993,7 @@ export const arpWith = register('arpWith', (func, pat) => {
/**
* Selects indices in in stacked notes.
- * @tags transforms
+ * @tags temporal
* @example
* note("<[c,eb,g]!2 [c,f,ab] [d,f,ab]>")
* .arp("0 [0,2] 1 [0,2]")
@@ -1342,7 +1342,7 @@ export function reify(thing) {
/**
* Takes a list of patterns, and returns a pattern of lists.
*
- * @tags transforms
+ * @tags temporal
*/
export function sequenceP(pats) {
let result = pure([]);
@@ -3354,7 +3354,7 @@ Pattern.prototype.steps = Pattern.prototype.pace;
* Cuts each sample into the given number of parts, allowing you to explore a technique known as 'granular synthesis'.
* It turns a pattern of samples into a pattern of parts of samples.
* @name chop
- * @tags transforms
+ * @tags temporal
* @memberof Pattern
* @returns Pattern
* @example
@@ -3385,7 +3385,7 @@ export const chop = register('chop', function (n, pat) {
/**
* Cuts each sample into the given number of parts, triggering progressive portions of each sample at each loop.
* @name striate
- * @tags transforms
+ * @tags temporal
* @memberof Pattern
* @returns Pattern
* @example
@@ -3404,7 +3404,7 @@ export const striate = register('striate', function (n, pat) {
/**
* Makes the sample fit the given number of cycles by changing the speed.
* @name loopAt
- * @tags transforms
+ * @tags temporal
* @memberof Pattern
* @returns Pattern
* @example
@@ -3423,7 +3423,7 @@ const _loopAt = function (factor, pat, cps = 0.5) {
* Chops samples into the given number of slices, triggering those slices with a given pattern of slice numbers.
* Instead of a number, it also accepts a list of numbers from 0 to 1 to slice at specific points.
* @name slice
- * @tags transforms
+ * @tags temporal
* @memberof Pattern
* @returns Pattern
* @example
@@ -3477,7 +3477,7 @@ Pattern.prototype.onTriggerTime = function (func) {
/**
* Works the same as slice, but changes the playback speed of each slice to match the duration of its step.
* @name splice
- * @tags transforms
+ * @tags temporal
* @example
* samples('github:tidalcycles/dirt-samples')
* s("breaks165")
@@ -3515,7 +3515,7 @@ export const { loopAt, loopat } = register(['loopAt', 'loopat'], function (facto
* Makes the sample fit its event duration. Good for rhythmical loops like drum breaks.
* Similar to `loopAt`.
* @name fit
- * @tags transforms
+ * @tags temporal
* @example
* samples({ rhodes: 'https://cdn.freesound.org/previews/132/132051_316502-lq.mp3' })
* s("rhodes/2").fit()
@@ -3541,7 +3541,7 @@ export const fit = register('fit', (pat) =>
* given by a global clock and this function will be
* deprecated/removed.
* @name loopAtCps
- * @tags transforms
+ * @tags temporal
* @memberof Pattern
* @returns Pattern
* @example
diff --git a/packages/core/signal.mjs b/packages/core/signal.mjs
index 2c3a63324..ce17fdeae 100644
--- a/packages/core/signal.mjs
+++ b/packages/core/signal.mjs
@@ -300,7 +300,7 @@ const _rearrangeWith = (ipat, n, pat) => {
* 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
- * @tags transforms
+ * @tags temporal
* @example
* note("c d e f").sound("piano").shuffle(4)
* @example
@@ -314,7 +314,7 @@ export const shuffle = register('shuffle', (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
- * @tags transforms
+ * @tags temporal
* @example
* note("c d e f").sound("piano").scramble(4)
* @example
@@ -393,7 +393,7 @@ export const __chooseWith = (pat, xs) => {
/**
* Choose from the list of values (or patterns of values) using the given
* pattern of numbers, which should be in the range of 0..1
- * @tags transforms
+ * @tags temporal
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
@@ -407,7 +407,7 @@ export const chooseWith = (pat, xs) => {
/**
* As with {chooseWith}, but the structure comes from the chosen values, rather
* than the pattern you're using to choose with.
- * @tags transforms
+ * @tags temporal
* @param {Pattern} pat
* @param {*} xs
* @returns {Pattern}
@@ -418,7 +418,7 @@ export const chooseInWith = (pat, xs) => {
/**
* Chooses randomly from the given list of elements.
- * @tags transforms
+ * @tags temporal
* @param {...any} xs values / patterns to choose from.
* @returns {Pattern} - a continuous pattern.
* @example
@@ -434,7 +434,7 @@ export const chooseOut = choose;
* Chooses from the given list of values (or patterns of values), according
* to the pattern that the method is called on. The pattern should be in
* the range 0 .. 1.
- * @tags transforms
+ * @tags temporal
* @param {...any} xs
* @returns {Pattern}
*/
@@ -445,7 +445,7 @@ Pattern.prototype.choose = function (...xs) {
/**
* As with choose, but the pattern that this method is called on should be
* in the range -1 .. 1
- * @tags transforms
+ * @tags temporal
* @param {...any} xs
* @returns {Pattern}
*/
@@ -455,7 +455,7 @@ Pattern.prototype.choose2 = function (...xs) {
/**
* Picks one of the elements at random each cycle.
- * @tags transforms
+ * @tags temporal
* @synonyms randcat
* @returns {Pattern}
* @example
@@ -498,7 +498,7 @@ const wchooseWith = (...args) => _wchooseWith(...args).outerJoin();
/**
* Chooses randomly from the given list of elements by giving a probability to each element
- * @tags transforms
+ * @tags temporal
* @param {...any} pairs arrays of value and weight
* @returns {Pattern} - a continuous pattern.
* @example
@@ -508,7 +508,7 @@ export const wchoose = (...pairs) => wchooseWith(rand, ...pairs);
/**
* Picks one of the elements at random each cycle by giving a probability to each element
- * @tags transforms
+ * @tags temporal
* @synonyms wrandcat
* @returns {Pattern}
* @example
@@ -590,7 +590,7 @@ export const degradeByWith = register(
* 0 = 0% chance of removal
* 1 = 100% chance of removal
*
- * @tags transforms
+ * @tags temporal
* @name degradeBy
* @memberof Pattern
* @param {number} amount - a number between 0 and 1
@@ -616,7 +616,7 @@ export const degradeBy = register(
*
* Randomly removes 50% of events from the pattern. Shorthand for `.degradeBy(0.5)`
*
- * @tags transforms
+ * @tags temporal
* @name degrade
* @memberof Pattern
* @returns Pattern
@@ -633,7 +633,7 @@ export const degrade = register('degrade', (pat) => pat._degradeBy(0.5), true, t
* 1 = 0% chance of removal
* Events that would be removed by degradeBy are let through by undegradeBy and vice versa (see second example).
*
- * @tags transforms
+ * @tags temporal
* @name undegradeBy
* @memberof Pattern
* @param {number} amount - a number between 0 and 1
@@ -662,7 +662,7 @@ export const undegradeBy = register(
* 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).
*
- * @tags transforms
+ * @tags temporal
* @name undegrade
* @memberof Pattern
* @returns Pattern
@@ -681,7 +681,7 @@ export const undegrade = register('undegrade', (pat) => pat._undegradeBy(0.5), t
* Randomly applies the given function by the given probability.
* Similar to `someCyclesBy`
*
- * @tags transforms
+ * @tags temporal
* @name sometimesBy
* @memberof Pattern
* @param {number | Pattern} probability - a number between 0 and 1
@@ -701,7 +701,7 @@ export const sometimesBy = register('sometimesBy', function (patx, func, pat) {
*
* Applies the given function with a 50% chance
*
- * @tags transforms
+ * @tags temporal
* @name sometimes
* @memberof Pattern
* @param {function} function - the transformation to apply
@@ -723,7 +723,7 @@ export const sometimes = register('sometimes', function (func, pat) {
* @param {number | Pattern} probability - a number between 0 and 1
* @param {function} function - the transformation to apply
* @returns Pattern
- * @tags transforms
+ * @tags temporal
* @example
* s("bd,hh*8").someCyclesBy(.3, x=>x.speed("0.5"))
*/
@@ -746,7 +746,7 @@ export const someCyclesBy = register('someCyclesBy', function (patx, func, pat)
* @name someCycles
* @memberof Pattern
* @returns Pattern
- * @tags transforms
+ * @tags temporal
* @example
* s("bd,hh*8").someCycles(x=>x.speed("0.5"))
*/
@@ -761,7 +761,7 @@ export const someCycles = register('someCycles', function (func, pat) {
* @name often
* @memberof Pattern
* @returns Pattern
- * @tags transforms
+ * @tags temporal
* @example
* s("hh*8").often(x=>x.speed("0.5"))
*/
@@ -776,7 +776,7 @@ export const often = register('often', function (func, pat) {
* @name rarely
* @memberof Pattern
* @returns Pattern
- * @tags transforms
+ * @tags temporal
* @example
* s("hh*8").rarely(x=>x.speed("0.5"))
*/
@@ -788,7 +788,7 @@ export const rarely = register('rarely', function (func, pat) {
*
* Shorthand for `.sometimesBy(0.1, fn)`
*
- * @tags transforms
+ * @tags temporal
* @name almostNever
* @memberof Pattern
* @returns Pattern
@@ -803,7 +803,7 @@ export const almostNever = register('almostNever', function (func, pat) {
*
* Shorthand for `.sometimesBy(0.9, fn)`
*
- * @tags transforms
+ * @tags temporal
* @name almostAlways
* @memberof Pattern
* @returns Pattern
@@ -818,7 +818,7 @@ export const almostAlways = register('almostAlways', function (func, pat) {
*
* Shorthand for `.sometimesBy(0, fn)` (never calls fn)
*
- * @tags transforms
+ * @tags temporal
* @name never
* @memberof Pattern
* @returns Pattern
@@ -833,7 +833,7 @@ export const never = register('never', function (_, pat) {
*
* Shorthand for `.sometimesBy(1, fn)` (always calls fn)
*
- * @tags transforms
+ * @tags temporal
* @name always
* @memberof Pattern
* @returns Pattern
From b952e4c735a9f77592824e5542a6e3e93e9530aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Va=CC=81clav=20Volhejn?=
Date: Sun, 19 Oct 2025 20:54:22 +0200
Subject: [PATCH 010/124] Add superdough tags
---
packages/core/controls.mjs | 132 ++++++++++++++++++-------------------
1 file changed, 66 insertions(+), 66 deletions(-)
diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs
index db689e1a2..2add9e416 100644
--- a/packages/core/controls.mjs
+++ b/packages/core/controls.mjs
@@ -351,7 +351,7 @@ export const { warpsync } = registerControl('warpsync');
* Define a custom webaudio node to use as a sound source.
*
* @name source
- * @tags external_io
+ * @tags external_io, superdough
* @synonyms src
* @param {function} getSource
* @synonyms src
@@ -411,7 +411,7 @@ export const { accelerate } = registerControl('accelerate');
* Sets the velocity from 0 to 1. Is multiplied together with gain.
*
* @name velocity
- * @tags effects
+ * @tags effects, superdough
* @example
* s("hh*8")
* .gain(".4!2 1 .4!2 1 .4 1")
@@ -422,7 +422,7 @@ export const { velocity } = registerControl('velocity');
* Controls the gain by an exponential amount.
*
* @name gain
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} amount gain.
* @example
* s("hh*8").gain(".4!2 1 .4!2 1 .4 1").fast(2)
@@ -433,7 +433,7 @@ export const { gain } = registerControl('gain');
* Gain applied after all effects have been processed.
*
* @name postgain
- * @tags effects
+ * @tags effects, superdough
* @example
* s("bd sd [~ bd] sd,hh*8")
* .compressor("-20:20:10:.002:.02").postgain(1.5)
@@ -581,7 +581,7 @@ export const { fmvelocity } = registerControl('fmvelocity');
* Select the sound bank to use. To be used together with `s`. The bank name (+ "_") will be prepended to the value of `s`.
*
* @name bank
- * @tags samples
+ * @tags samples, superdough
* @param {string | Pattern} bank the name of the bank
* @example
* s("bd sd [~ bd] sd").bank('RolandTR909') // = s("RolandTR909_bd RolandTR909_sd")
@@ -635,7 +635,7 @@ export const { sustain, sus } = registerControl('sustain', 'sus');
* Amplitude envelope release time: The time it takes after the offset to go from sustain level to zero.
*
* @name release
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} time release time in seconds
* @synonyms rel
* @example
@@ -650,7 +650,7 @@ export const { hold } = registerControl('hold');
* can also optionally supply the 'bpq' parameter separated by ':'.
*
* @name bpf
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} frequency center frequency
* @synonyms bandf, bp
* @example
@@ -663,7 +663,7 @@ export const { bandf, bpf, bp } = registerControl(['bandf', 'bandq', 'bpenv'], '
* Sets the **b**and-**p**ass **q**-factor (resonance).
*
* @name bpq
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} q q factor
* @synonyms bandq
* @example
@@ -743,7 +743,7 @@ export const { loopEnd, loope } = registerControl('loopEnd', 'loope');
* Bit crusher effect.
*
* @name crush
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction).
* @example
* s(",hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>")
@@ -755,7 +755,7 @@ export const { crush } = registerControl('crush');
* Fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers
*
* @name coarse
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on.
* @example
* s("bd sd [~ bd] sd,hh*8").coarse("<1 4 8 16 32>")
@@ -767,7 +767,7 @@ export const { coarse } = registerControl('coarse');
* Modulate the amplitude of a sound with a continuous waveform
*
* @name tremolo
- * @tags effects
+ * @tags effects, superdough
* @synonyms trem
* @param {number | Pattern} speed modulation speed in HZ
* @example
@@ -780,7 +780,7 @@ export const { tremolo } = registerControl(['tremolo', 'tremolodepth', 'tremolos
* Modulate the amplitude of a sound with a continuous waveform
*
* @name tremolosync
- * @tags effects
+ * @tags effects, superdough
* @synonyms tremsync
* @param {number | Pattern} cycles modulation speed in cycles
* @example
@@ -796,7 +796,7 @@ export const { tremolosync } = registerControl(
* Depth of amplitude modulation
*
* @name tremolodepth
- * @tags effects
+ * @tags effects, superdough
* @synonyms tremdepth
* @param {number | Pattern} depth
* @example
@@ -808,7 +808,7 @@ export const { tremolodepth } = registerControl('tremolodepth', 'tremdepth');
* Alter the shape of the modulation waveform
*
* @name tremoloskew
- * @tags effects
+ * @tags effects, superdough
* @synonyms tremskew
* @param {number | Pattern} amount between 0 & 1, the shape of the waveform
* @example
@@ -821,7 +821,7 @@ export const { tremoloskew } = registerControl('tremoloskew', 'tremskew');
* Alter the phase of the modulation waveform
*
* @name tremolophase
- * @tags effects
+ * @tags effects, superdough
* @synonyms tremphase
* @param {number | Pattern} offset the offset in cycles of the modulation
* @example
@@ -834,7 +834,7 @@ export const { tremolophase } = registerControl('tremolophase', 'tremphase');
* Shape of amplitude modulation
*
* @name tremoloshape
- * @tags effects
+ * @tags effects, superdough
* @synonyms tremshape
* @param {number | Pattern} shape tri | square | sine | saw | ramp
* @example
@@ -846,7 +846,7 @@ export const { tremoloshape } = registerControl('tremoloshape', 'tremshape');
* Filter overdrive for supported filter types
*
* @name drive
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} amount
* @example
* note("{f g g c d a a#}%16".sub(17)).s("supersaw").lpenv(8).lpf(150).lpq(.8).ftype('ladder').drive("<.5 4>")
@@ -860,7 +860,7 @@ export const { drive } = registerControl('drive');
* Can be applied to multiple orbits with the ':' mininotation, e.g. `duckorbit("2:3")`
*
* @name duckorbit
- * @tags effects
+ * @tags effects, superdough
* @synonyms duck
* @param {number | Pattern} orbit target orbit
* @example
@@ -881,7 +881,7 @@ export const { duck } = registerControl('duckorbit', 'duck');
* Note: this requires first applying the effect to multiple orbits with e.g. `duckorbit("2:3")`.
*
* @name duckdepth
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} depth depth of modulation from 0 to 1
* @example
* stack( n(run(8)).scale("c:minor").s("sawtooth").delay(.7).orbit(2), s("bd:4!4").beat("0,4,8,11,14",16).duckorbit(2).duckattack(0.2).duckdepth("<1 .9 .6 0>"))
@@ -901,7 +901,7 @@ export const { duckdepth } = registerControl('duckdepth');
* Note: this requires first applying the effect to multiple orbits with e.g. `duckorbit("2:3")`.
*
* @name duckonset
- * @tags effects
+ * @tags effects, superdough
* @synonyms duckons
*
* @param {number | Pattern} time The onset time in seconds
@@ -929,7 +929,7 @@ export const { duckonset } = registerControl('duckonset', 'duckons');
* Note: this requires first applying the effect to multiple orbits with e.g. `duckorbit("2:3")`.
*
* @name duckattack
- * @tags effects
+ * @tags effects, superdough
* @synonyms duckatt
*
* @param {number | Pattern} time The attack time in seconds
@@ -1028,7 +1028,7 @@ export const { pwsweep } = registerControl('pwsweep');
* Phaser audio effect that approximates popular guitar pedals.
*
* @name phaser
- * @tags effects
+ * @tags effects, superdough
* @synonyms ph
* @param {number | Pattern} speed speed of modulation
* @example
@@ -1046,7 +1046,7 @@ export const { phaserrate, ph, phaser } = registerControl(
* The frequency sweep range of the lfo for the phaser effect. Defaults to 2000
*
* @name phasersweep
- * @tags effects
+ * @tags effects, superdough
* @synonyms phs
* @param {number | Pattern} phasersweep most useful values are between 0 and 4000
* @example
@@ -1060,7 +1060,7 @@ export const { phasersweep, phs } = registerControl('phasersweep', 'phs');
* The center frequency of the phaser in HZ. Defaults to 1000
*
* @name phasercenter
- * @tags effects
+ * @tags effects, superdough
* @synonyms phc
* @param {number | Pattern} centerfrequency in HZ
* @example
@@ -1075,7 +1075,7 @@ export const { phasercenter, phc } = registerControl('phasercenter', 'phc');
* The amount the signal is affected by the phaser effect. Defaults to 0.75
*
* @name phaserdepth
- * @tags effects
+ * @tags effects, superdough
* @synonyms phd, phasdp
* @param {number | Pattern} depth number between 0 and 1
* @example
@@ -1112,7 +1112,7 @@ export const { cut } = registerControl('cut');
* When using mininotation, you can also optionally add the 'lpq' parameter, separated by ':'.
*
* @name lpf
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} frequency audible between 0 and 20000
* @synonyms cutoff, ctf, lp
* @example
@@ -1126,7 +1126,7 @@ export const { cutoff, ctf, lpf, lp } = registerControl(['cutoff', 'resonance',
/**
* Sets the lowpass filter envelope modulation depth.
* @name lpenv
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_
* @synonyms lpe
* @example
@@ -1140,7 +1140,7 @@ export const { lpenv, lpe } = registerControl('lpenv', 'lpe');
/**
* Sets the highpass filter envelope modulation depth.
* @name hpenv
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_
* @synonyms hpe
* @example
@@ -1154,7 +1154,7 @@ export const { hpenv, hpe } = registerControl('hpenv', 'hpe');
/**
* Sets the bandpass filter envelope modulation depth.
* @name bpenv
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_
* @synonyms bpe
* @example
@@ -1168,7 +1168,7 @@ export const { bpenv, bpe } = registerControl('bpenv', 'bpe');
/**
* Sets the attack duration for the lowpass filter envelope.
* @name lpattack
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} attack time of the filter envelope
* @synonyms lpa
* @example
@@ -1182,7 +1182,7 @@ export const { lpattack, lpa } = registerControl('lpattack', 'lpa');
/**
* Sets the attack duration for the highpass filter envelope.
* @name hpattack
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} attack time of the highpass filter envelope
* @synonyms hpa
* @example
@@ -1196,7 +1196,7 @@ export const { hpattack, hpa } = registerControl('hpattack', 'hpa');
/**
* Sets the attack duration for the bandpass filter envelope.
* @name bpattack
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} attack time of the bandpass filter envelope
* @synonyms bpa
* @example
@@ -1210,7 +1210,7 @@ export const { bpattack, bpa } = registerControl('bpattack', 'bpa');
/**
* Sets the decay duration for the lowpass filter envelope.
* @name lpdecay
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} decay time of the filter envelope
* @synonyms lpd
* @example
@@ -1224,7 +1224,7 @@ export const { lpdecay, lpd } = registerControl('lpdecay', 'lpd');
/**
* Sets the decay duration for the highpass filter envelope.
* @name hpdecay
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} decay time of the highpass filter envelope
* @synonyms hpd
* @example
@@ -1239,7 +1239,7 @@ export const { hpdecay, hpd } = registerControl('hpdecay', 'hpd');
/**
* Sets the decay duration for the bandpass filter envelope.
* @name bpdecay
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} decay time of the bandpass filter envelope
* @synonyms bpd
* @example
@@ -1254,7 +1254,7 @@ export const { bpdecay, bpd } = registerControl('bpdecay', 'bpd');
/**
* Sets the sustain amplitude for the lowpass filter envelope.
* @name lpsustain
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} sustain amplitude of the lowpass filter envelope
* @synonyms lps
* @example
@@ -1269,7 +1269,7 @@ export const { lpsustain, lps } = registerControl('lpsustain', 'lps');
/**
* Sets the sustain amplitude for the highpass filter envelope.
* @name hpsustain
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} sustain amplitude of the highpass filter envelope
* @synonyms hps
* @example
@@ -1284,7 +1284,7 @@ export const { hpsustain, hps } = registerControl('hpsustain', 'hps');
/**
* Sets the sustain amplitude for the bandpass filter envelope.
* @name bpsustain
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} sustain amplitude of the bandpass filter envelope
* @synonyms bps
* @example
@@ -1299,7 +1299,7 @@ export const { bpsustain, bps } = registerControl('bpsustain', 'bps');
/**
* Sets the release time for the lowpass filter envelope.
* @name lprelease
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} release time of the filter envelope
* @synonyms lpr
* @example
@@ -1315,7 +1315,7 @@ export const { lprelease, lpr } = registerControl('lprelease', 'lpr');
/**
* Sets the release time for the highpass filter envelope.
* @name hprelease
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} release time of the highpass filter envelope
* @synonyms hpr
* @example
@@ -1331,7 +1331,7 @@ export const { hprelease, hpr } = registerControl('hprelease', 'hpr');
/**
* Sets the release time for the bandpass filter envelope.
* @name bprelease
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} release time of the bandpass filter envelope
* @synonyms bpr
* @example
@@ -1363,7 +1363,7 @@ export const { ftype } = registerControl('ftype');
/**
* controls the center of the filter envelope. 0 is unipolar positive, .5 is bipolar, 1 is unipolar negative
* @name fanchor
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} center 0 to 1
* @example
* note("{f g g c d a a#}%8").s("sawtooth").lpf("{1000}%2")
@@ -1376,7 +1376,7 @@ export const { fanchor } = registerControl('fanchor');
* When using mininotation, you can also optionally add the 'hpq' parameter, separated by ':'.
*
* @name hpf
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} frequency audible between 0 and 20000
* @synonyms hp, hcutoff
* @example
@@ -1438,7 +1438,7 @@ export const { hcutoff, hpf, hp } = registerControl(['hcutoff', 'hresonance', 'h
* Controls the **h**igh-**p**ass **q**-value.
*
* @name hpq
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} q resonance factor between 0 and 50
* @synonyms hresonance
* @example
@@ -1450,7 +1450,7 @@ export const { hresonance, hpq } = registerControl('hresonance', 'hpq');
* Controls the **l**ow-**p**ass **q**-value.
*
* @name lpq
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} q resonance factor between 0 and 50
* @synonyms resonance
* @example
@@ -1463,7 +1463,7 @@ export const { resonance, lpq } = registerControl('resonance', 'lpq');
* DJ filter, below 0.5 is low pass filter, above is high pass filter.
*
* @name djf
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} cutoff below 0.5 is low pass filter, above is high pass filter
* @example
* n(irand(16).seg(8)).scale("d:phrygian").s("supersaw").djf("<.5 .3 .2 .75>")
@@ -1480,7 +1480,7 @@ export const { djf } = registerControl('djf');
*
*
* @name delay
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} level between 0 and 1
* @example
* s("bd bd").delay("<0 .25 .5 1>")
@@ -1494,7 +1494,7 @@ export const { delay } = registerControl(['delay', 'delaytime', 'delayfeedback']
* Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it
*
* @name delayfeedback
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} feedback between 0 and 1
* @synonyms delayfb, dfb
* @example
@@ -1508,7 +1508,7 @@ export const { delayfeedback, delayfb, dfb } = registerControl('delayfeedback',
* Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it
*
* @name delayfeedback
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} feedback between 0 and 1
* @synonyms delayfb, dfb
* @example
@@ -1533,7 +1533,7 @@ export const { delaytime, delayt, dt } = registerControl('delaytime', 'delayt',
* Sets the time of the delay effect in cycles.
*
* @name delaysync
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} cycles delay length in cycles
* @synonyms delayt, dt
* @example
@@ -1595,7 +1595,7 @@ export const { spread } = registerControl('spread');
* Set dryness of reverb. See `room` and `size` for more information about reverb.
*
* @name dry
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} dry 0 = wet, 1 = dry
* @example
* n("[0,3,7](3,8)").s("superpiano").room(.7).dry("<0 .5 .75 1>").osc()
@@ -1814,7 +1814,7 @@ export const { octave } = registerControl('octave');
* An `orbit` is a global parameter context for patterns. Patterns with the same orbit will share the same global effects.
*
* @name orbit
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} number
* @example
* stack(
@@ -1831,7 +1831,7 @@ export const { overshape } = registerControl('overshape');
* Sets position in stereo.
*
* @name pan
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel)
* @example
* s("[bd hh]*2").pan("<.5 1 .5 0>")
@@ -1897,7 +1897,7 @@ export const { mode } = registerControl(['mode', 'anchor']);
* When using mininotation, you can also optionally add the 'size' parameter, separated by ':'.
*
* @name room
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} level between 0 and 1
* @example
* s("bd sd [~ bd] sd").room("<0 .2 .4 .6 .8 1>")
@@ -1911,7 +1911,7 @@ export const { room } = registerControl(['room', 'size']);
* When this property is changed, the reverb will be recaculated, so only change this sparsely..
*
* @name roomlp
- * @tags effects
+ * @tags effects, superdough
* @synonyms rlp
* @param {number} frequency between 0 and 20000hz
* @example
@@ -1925,7 +1925,7 @@ export const { roomlp, rlp } = registerControl('roomlp', 'rlp');
* When this property is changed, the reverb will be recaculated, so only change this sparsely..
*
* @name roomdim
- * @tags effects
+ * @tags effects, superdough
* @synonyms rdim
* @param {number} frequency between 0 and 20000hz
* @example
@@ -1940,7 +1940,7 @@ export const { roomdim, rdim } = registerControl('roomdim', 'rdim');
* When this property is changed, the reverb will be recaculated, so only change this sparsely..
*
* @name roomfade
- * @tags effects
+ * @tags effects, superdough
* @synonyms rfade
* @param {number} seconds for the reverb to fade
* @example
@@ -1953,7 +1953,7 @@ export const { roomfade, rfade } = registerControl('roomfade', 'rfade');
/**
* Sets the sample to use as an impulse response for the reverb.
* @name iresponse
- * @tags effects
+ * @tags effects, superdough
* @param {string | Pattern} sample to use as an impulse response
* @synonyms ir
* @example
@@ -1965,7 +1965,7 @@ export const { ir, iresponse } = registerControl(['ir', 'i'], 'iresponse');
/**
* Sets speed of the sample for the impulse response.
* @name irspeed
- * @tags effects
+ * @tags effects, superdough
* @param {string | Pattern} speed
* @example
* samples('github:switchangel/pad')
@@ -1977,7 +1977,7 @@ export const { irspeed } = registerControl('irspeed');
/**
* Sets the beginning of the IR response sample
* @name irbegin
- * @tags effects
+ * @tags effects, superdough
* @param {string | Pattern} begin between 0 and 1
* @synonyms ir
* @example
@@ -1991,7 +1991,7 @@ export const { irbegin } = registerControl('irbegin');
* When this property is changed, the reverb will be recaculated, so only change this sparsely..
*
* @name roomsize
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} size between 0 and 10
* @synonyms rsize, sz, size
* @example
@@ -2015,7 +2015,7 @@ export const { roomsize, size, sz, rsize } = registerControl('roomsize', 'size',
*
*
* @name shape
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} distortion between 0 and 1
* @example
* s("bd sd [~ bd] sd,hh*8").shape("<0 .2 .4 .6 .8>")
@@ -2028,7 +2028,7 @@ export const { shape } = registerControl(['shape', 'shapevol']);
* Most useful values are usually between 0 and 10 (depending on source gain). If you are feeling adventurous, you can turn it up to 11 and beyond ;)
*
* @name distort
- * @tags effects
+ * @tags effects, superdough
* @synonyms dist
* @param {number | Pattern} distortion
* @example
@@ -2043,7 +2043,7 @@ export const { distort, dist } = registerControl(['distort', 'distortvol'], 'dis
* More info [here](https://developer.mozilla.org/en-US/docs/Web/API/DynamicsCompressorNode?retiredLocale=de#instance_properties)
*
* @name compressor
- * @tags effects
+ * @tags effects, superdough
* @example
* s("bd sd [~ bd] sd,hh*8")
* .compressor("-20:20:10:.002:.02")
@@ -2129,7 +2129,7 @@ export const { squiz } = registerControl('squiz');
* Formant filter to make things sound like vowels.
*
* @name vowel
- * @tags effects
+ * @tags effects, superdough
* @param {string | Pattern} vowel You can use a e i o u ae aa oe ue y uh un en an on, corresponding to [a] [e] [i] [o] [u] [æ] [ɑ] [ø] [y] [ɯ] [ʌ] [œ̃] [ɛ̃] [ɑ̃] [ɔ̃]. Aliases: aa = å = ɑ, oe = ø = ö, y = ı, ae = æ.
* @example
* note("[c2 >]*2").s('sawtooth')
@@ -2154,7 +2154,7 @@ export const { waveloss } = registerControl('waveloss');
* Noise crackle density
*
* @name density
- * @tags effects
+ * @tags effects, superdough
* @param {number | Pattern} density between 0 and x
* @example
* s("crackle*4").density("<0.01 0.04 0.2 0.5>".slow(4))
From 96d0f2053e7fc0afbf515668945f3a4f3346fca7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Va=CC=81clav=20Volhejn?=
Date: Sun, 19 Oct 2025 21:13:14 +0200
Subject: [PATCH 011/124] Add supradough controls
---
packages/core/controls.mjs | 96 +++++++++++++++++++-------------------
1 file changed, 48 insertions(+), 48 deletions(-)
diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs
index 2add9e416..dda12767d 100644
--- a/packages/core/controls.mjs
+++ b/packages/core/controls.mjs
@@ -411,7 +411,7 @@ export const { accelerate } = registerControl('accelerate');
* Sets the velocity from 0 to 1. Is multiplied together with gain.
*
* @name velocity
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @example
* s("hh*8")
* .gain(".4!2 1 .4!2 1 .4 1")
@@ -422,7 +422,7 @@ export const { velocity } = registerControl('velocity');
* Controls the gain by an exponential amount.
*
* @name gain
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} amount gain.
* @example
* s("hh*8").gain(".4!2 1 .4!2 1 .4 1").fast(2)
@@ -433,7 +433,7 @@ export const { gain } = registerControl('gain');
* Gain applied after all effects have been processed.
*
* @name postgain
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @example
* s("bd sd [~ bd] sd,hh*8")
* .compressor("-20:20:10:.002:.02").postgain(1.5)
@@ -456,7 +456,7 @@ export const { amp } = registerControl('amp');
* Amplitude envelope attack time: Specifies how long it takes for the sound to reach its peak value, relative to the onset.
*
* @name attack
- * @tags effects
+ * @tags effects, superdough, supradough
* @param {number | Pattern} attack time in seconds.
* @synonyms att
* @example
@@ -472,7 +472,7 @@ export const { attack, att } = registerControl('attack', 'att');
* while decimal numbers and complex ratios sound metallic.
*
* @name fmh
- * @tags effects
+ * @tags effects, superdough, supradough
* @param {number | Pattern} harmonicity
* @example
* note("c e g b g e")
@@ -487,7 +487,7 @@ export const { fmh } = registerControl(['fmh', 'fmi'], 'fmh');
* Controls the modulation index, which defines the brightness of the sound.
*
* @name fm
- * @tags effects
+ * @tags effects, superdough, supradough
* @param {number | Pattern} brightness modulation index
* @synonyms fmi
* @example
@@ -502,7 +502,7 @@ export const { fmi, fm } = registerControl(['fmi', 'fmh'], 'fm');
* Ramp type of fm envelope. Exp might be a bit broken..
*
* @name fmenv
- * @tags effects
+ * @tags effects, superdough, supradough
* @param {number | Pattern} type lin | exp
* @example
* note("c e g b g e")
@@ -518,7 +518,7 @@ export const { fmenv } = registerControl('fmenv');
* Attack time for the FM envelope: time it takes to reach maximum modulation
*
* @name fmattack
- * @tags effects
+ * @tags effects, superdough, supradough
* @param {number | Pattern} time attack time
* @example
* note("c e g b g e")
@@ -533,7 +533,7 @@ export const { fmattack } = registerControl('fmattack');
* Waveform of the fm modulator
*
* @name fmwave
- * @tags effects
+ * @tags effects, superdough, supradough
* @param {number | Pattern} wave waveform
* @example
* n("0 1 2 3".fast(4)).scale("d:minor").s("sine").fmwave("").fm(4).fmh(2.01)
@@ -547,7 +547,7 @@ export const { fmwave } = registerControl('fmwave');
* Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase.
*
* @name fmdecay
- * @tags effects
+ * @tags effects, superdough, supradough
* @param {number | Pattern} time decay time
* @example
* note("c e g b g e")
@@ -562,7 +562,7 @@ export const { fmdecay } = registerControl('fmdecay');
* Sustain level for the FM envelope: how much modulation is applied after the decay phase
*
* @name fmsustain
- * @tags effects
+ * @tags effects, superdough, supradough
* @param {number | Pattern} level sustain level
* @example
* note("c e g b g e")
@@ -611,7 +611,7 @@ export const { fft } = registerControl('fft');
* Note that the decay is only audible if the sustain value is lower than 1.
*
* @name decay
- * @tags effects
+ * @tags effects, superdough, supradough
* @param {number | Pattern} time decay time in seconds
* @synonyms dec
* @example
@@ -623,7 +623,7 @@ export const { decay, dec } = registerControl('decay', 'dec');
* Amplitude envelope sustain level: The level which is reached after attack / decay, being sustained until the offset.
*
* @name sustain
- * @tags effects
+ * @tags effects, superdough, supradough
* @param {number | Pattern} gain sustain level between 0 and 1
* @synonyms sus
* @example
@@ -635,7 +635,7 @@ export const { sustain, sus } = registerControl('sustain', 'sus');
* Amplitude envelope release time: The time it takes after the offset to go from sustain level to zero.
*
* @name release
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} time release time in seconds
* @synonyms rel
* @example
@@ -650,7 +650,7 @@ export const { hold } = registerControl('hold');
* can also optionally supply the 'bpq' parameter separated by ':'.
*
* @name bpf
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} frequency center frequency
* @synonyms bandf, bp
* @example
@@ -663,7 +663,7 @@ export const { bandf, bpf, bp } = registerControl(['bandf', 'bandq', 'bpenv'], '
* Sets the **b**and-**p**ass **q**-factor (resonance).
*
* @name bpq
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} q q factor
* @synonyms bandq
* @example
@@ -743,7 +743,7 @@ export const { loopEnd, loope } = registerControl('loopEnd', 'loope');
* Bit crusher effect.
*
* @name crush
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction).
* @example
* s(",hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>")
@@ -755,7 +755,7 @@ export const { crush } = registerControl('crush');
* Fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers
*
* @name coarse
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on.
* @example
* s("bd sd [~ bd] sd,hh*8").coarse("<1 4 8 16 32>")
@@ -1112,7 +1112,7 @@ export const { cut } = registerControl('cut');
* When using mininotation, you can also optionally add the 'lpq' parameter, separated by ':'.
*
* @name lpf
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} frequency audible between 0 and 20000
* @synonyms cutoff, ctf, lp
* @example
@@ -1126,7 +1126,7 @@ export const { cutoff, ctf, lpf, lp } = registerControl(['cutoff', 'resonance',
/**
* Sets the lowpass filter envelope modulation depth.
* @name lpenv
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_
* @synonyms lpe
* @example
@@ -1140,7 +1140,7 @@ export const { lpenv, lpe } = registerControl('lpenv', 'lpe');
/**
* Sets the highpass filter envelope modulation depth.
* @name hpenv
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_
* @synonyms hpe
* @example
@@ -1154,7 +1154,7 @@ export const { hpenv, hpe } = registerControl('hpenv', 'hpe');
/**
* Sets the bandpass filter envelope modulation depth.
* @name bpenv
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_
* @synonyms bpe
* @example
@@ -1168,7 +1168,7 @@ export const { bpenv, bpe } = registerControl('bpenv', 'bpe');
/**
* Sets the attack duration for the lowpass filter envelope.
* @name lpattack
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} attack time of the filter envelope
* @synonyms lpa
* @example
@@ -1182,7 +1182,7 @@ export const { lpattack, lpa } = registerControl('lpattack', 'lpa');
/**
* Sets the attack duration for the highpass filter envelope.
* @name hpattack
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} attack time of the highpass filter envelope
* @synonyms hpa
* @example
@@ -1196,7 +1196,7 @@ export const { hpattack, hpa } = registerControl('hpattack', 'hpa');
/**
* Sets the attack duration for the bandpass filter envelope.
* @name bpattack
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} attack time of the bandpass filter envelope
* @synonyms bpa
* @example
@@ -1210,7 +1210,7 @@ export const { bpattack, bpa } = registerControl('bpattack', 'bpa');
/**
* Sets the decay duration for the lowpass filter envelope.
* @name lpdecay
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} decay time of the filter envelope
* @synonyms lpd
* @example
@@ -1224,7 +1224,7 @@ export const { lpdecay, lpd } = registerControl('lpdecay', 'lpd');
/**
* Sets the decay duration for the highpass filter envelope.
* @name hpdecay
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} decay time of the highpass filter envelope
* @synonyms hpd
* @example
@@ -1239,7 +1239,7 @@ export const { hpdecay, hpd } = registerControl('hpdecay', 'hpd');
/**
* Sets the decay duration for the bandpass filter envelope.
* @name bpdecay
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} decay time of the bandpass filter envelope
* @synonyms bpd
* @example
@@ -1254,7 +1254,7 @@ export const { bpdecay, bpd } = registerControl('bpdecay', 'bpd');
/**
* Sets the sustain amplitude for the lowpass filter envelope.
* @name lpsustain
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} sustain amplitude of the lowpass filter envelope
* @synonyms lps
* @example
@@ -1269,7 +1269,7 @@ export const { lpsustain, lps } = registerControl('lpsustain', 'lps');
/**
* Sets the sustain amplitude for the highpass filter envelope.
* @name hpsustain
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} sustain amplitude of the highpass filter envelope
* @synonyms hps
* @example
@@ -1284,7 +1284,7 @@ export const { hpsustain, hps } = registerControl('hpsustain', 'hps');
/**
* Sets the sustain amplitude for the bandpass filter envelope.
* @name bpsustain
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} sustain amplitude of the bandpass filter envelope
* @synonyms bps
* @example
@@ -1299,7 +1299,7 @@ export const { bpsustain, bps } = registerControl('bpsustain', 'bps');
/**
* Sets the release time for the lowpass filter envelope.
* @name lprelease
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} release time of the filter envelope
* @synonyms lpr
* @example
@@ -1315,7 +1315,7 @@ export const { lprelease, lpr } = registerControl('lprelease', 'lpr');
/**
* Sets the release time for the highpass filter envelope.
* @name hprelease
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} release time of the highpass filter envelope
* @synonyms hpr
* @example
@@ -1331,7 +1331,7 @@ export const { hprelease, hpr } = registerControl('hprelease', 'hpr');
/**
* Sets the release time for the bandpass filter envelope.
* @name bprelease
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} release time of the bandpass filter envelope
* @synonyms bpr
* @example
@@ -1376,7 +1376,7 @@ export const { fanchor } = registerControl('fanchor');
* When using mininotation, you can also optionally add the 'hpq' parameter, separated by ':'.
*
* @name hpf
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} frequency audible between 0 and 20000
* @synonyms hp, hcutoff
* @example
@@ -1391,7 +1391,7 @@ export const { fanchor } = registerControl('fanchor');
* Applies a vibrato to the frequency of the oscillator.
*
* @name vib
- * @tags effects
+ * @tags effects, superdough, supradough
* @synonyms vibrato, v
* @param {number | Pattern} frequency of the vibrato in hertz
* @example
@@ -1419,7 +1419,7 @@ export const { noise } = registerControl('noise');
* Sets the vibrato depth in semitones. Only has an effect if `vibrato` | `vib` | `v` is is also set
*
* @name vibmod
- * @tags effects
+ * @tags effects, superdough, supradough
* @synonyms vmod
* @param {number | Pattern} depth of vibrato (in semitones)
* @example
@@ -1438,7 +1438,7 @@ export const { hcutoff, hpf, hp } = registerControl(['hcutoff', 'hresonance', 'h
* Controls the **h**igh-**p**ass **q**-value.
*
* @name hpq
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} q resonance factor between 0 and 50
* @synonyms hresonance
* @example
@@ -1450,7 +1450,7 @@ export const { hresonance, hpq } = registerControl('hresonance', 'hpq');
* Controls the **l**ow-**p**ass **q**-value.
*
* @name lpq
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} q resonance factor between 0 and 50
* @synonyms resonance
* @example
@@ -1480,7 +1480,7 @@ export const { djf } = registerControl('djf');
*
*
* @name delay
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} level between 0 and 1
* @example
* s("bd bd").delay("<0 .25 .5 1>")
@@ -1494,7 +1494,7 @@ export const { delay } = registerControl(['delay', 'delaytime', 'delayfeedback']
* Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it
*
* @name delayfeedback
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} feedback between 0 and 1
* @synonyms delayfb, dfb
* @example
@@ -1508,7 +1508,7 @@ export const { delayfeedback, delayfb, dfb } = registerControl('delayfeedback',
* Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it
*
* @name delayfeedback
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} feedback between 0 and 1
* @synonyms delayfb, dfb
* @example
@@ -1635,7 +1635,7 @@ export const { freq } = registerControl('freq');
* Attack time of pitch envelope.
*
* @name pattack
- * @tags effects
+ * @tags effects, superdough, supradough
* @synonyms patt
* @param {number | Pattern} time time in seconds
* @example
@@ -1647,7 +1647,7 @@ export const { pattack, patt } = registerControl('pattack', 'patt');
* Decay time of pitch envelope.
*
* @name pdecay
- * @tags effects
+ * @tags effects, superdough, supradough
* @synonyms pdec
* @param {number | Pattern} time time in seconds
* @example
@@ -1661,7 +1661,7 @@ export const { psustain, psus } = registerControl('psustain', 'psus');
* Release time of pitch envelope
*
* @name prelease
- * @tags effects
+ * @tags effects, superdough, supradough
* @synonyms prel
* @param {number | Pattern} time time in seconds
* @example
@@ -1676,7 +1676,7 @@ export const { prelease, prel } = registerControl('prelease', 'prel');
* If you don't set other pitch envelope controls, `pattack:.2` will be the default.
*
* @name penv
- * @tags effects
+ * @tags effects, superdough, supradough
* @param {number | Pattern} semitones change in semitones
* @example
* note("c")
@@ -1831,7 +1831,7 @@ export const { overshape } = registerControl('overshape');
* Sets position in stereo.
*
* @name pan
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel)
* @example
* s("[bd hh]*2").pan("<.5 1 .5 0>")
@@ -2028,7 +2028,7 @@ export const { shape } = registerControl(['shape', 'shapevol']);
* Most useful values are usually between 0 and 10 (depending on source gain). If you are feeling adventurous, you can turn it up to 11 and beyond ;)
*
* @name distort
- * @tags effects, superdough
+ * @tags effects, superdough, supradough
* @synonyms dist
* @param {number | Pattern} distortion
* @example
From 69360b3ec8731e75045f44b9f08840739fbc7e61 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Va=CC=81clav=20Volhejn?=
Date: Sun, 19 Oct 2025 21:17:25 +0200
Subject: [PATCH 012/124] Also tag "noise"
---
packages/core/controls.mjs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs
index dda12767d..c6ff8d79b 100644
--- a/packages/core/controls.mjs
+++ b/packages/core/controls.mjs
@@ -1409,7 +1409,7 @@ export const { vib, vibrato, v } = registerControl(['vib', 'vibmod'], 'vibrato',
* Adds pink noise to the mix
*
* @name noise
- * @tags generators
+ * @tags generators, superdough, supradough
* @param {number | Pattern} wet wet amount
* @example
* sound("/2")
From 2483c673a4ae08ac33fc60eb2155fdcd4ba091cc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Va=CC=81clav=20Volhejn?=
Date: Sun, 19 Oct 2025 21:19:42 +0200
Subject: [PATCH 013/124] Effects -> fx, untag "crossfade"
---
packages/core/controls.mjs | 262 +++++++++++++++---------------
packages/superdough/wavetable.mjs | 2 +-
packages/supradough/dough.mjs | 2 +-
3 files changed, 133 insertions(+), 133 deletions(-)
diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs
index c6ff8d79b..1bfd5a892 100644
--- a/packages/core/controls.mjs
+++ b/packages/core/controls.mjs
@@ -92,7 +92,7 @@ export const { s, sound } = registerControl(['s', 'n', 'gain'], 'sound');
* Position in the wavetable of the wavetable oscillator
*
* @name wt
- * @tags effects
+ * @tags fx
* @param {number | Pattern} position Position in the wavetable from 0 to 1
* @synonyms wavetablePosition
* @example
@@ -104,7 +104,7 @@ export const { wt, wavetablePosition } = registerControl('wt', 'wavetablePositio
* Amount of envelope applied wavetable oscillator's position envelope
*
* @name wtenv
- * @tags effects
+ * @tags fx
* @param {number | Pattern} amount between 0 and 1
*/
export const { wtenv } = registerControl('wtenv');
@@ -112,7 +112,7 @@ export const { wtenv } = registerControl('wtenv');
* Attack time of the wavetable oscillator's position envelope
*
* @name wtattack
- * @tags effects
+ * @tags fx
* @synonyms wtatt
* @param {number | Pattern} time attack time in seconds
*/
@@ -122,7 +122,7 @@ export const { wtattack, wtatt } = registerControl('wtattack', 'wtatt');
* Decay time of the wavetable oscillator's position envelope
*
* @name wtdecay
- * @tags effects
+ * @tags fx
* @synonyms wtdec
* @param {number | Pattern} time decay time in seconds
*/
@@ -132,7 +132,7 @@ export const { wtdecay, wtdec } = registerControl('wtdecay', 'wtdec');
* Sustain time of the wavetable oscillator's position envelope
*
* @name wtsustain
- * @tags effects
+ * @tags fx
* @synonyms wtsus
* @param {number | Pattern} gain sustain level (0 to 1)
*/
@@ -142,7 +142,7 @@ export const { wtsustain, wtsus } = registerControl('wtsustain', 'wtsus');
* Release time of the wavetable oscillator's position envelope
*
* @name wtrelease
- * @tags effects
+ * @tags fx
* @synonyms wtrel
* @param {number | Pattern} time release time in seconds
*/
@@ -152,7 +152,7 @@ export const { wtrelease, wtrel } = registerControl('wtrelease', 'wtrel');
* Rate of the LFO for the wavetable oscillator's position
*
* @name wtrate
- * @tags effects
+ * @tags fx
* @param {number | Pattern} rate rate in hertz
*/
export const { wtrate } = registerControl('wtrate');
@@ -160,7 +160,7 @@ export const { wtrate } = registerControl('wtrate');
* cycle synced rate of the LFO for the wavetable oscillator's position
*
* @name wtsync
- * @tags effects
+ * @tags fx
* @param {number | Pattern} rate rate in cycles
*/
export const { wtsync } = registerControl('wtsync');
@@ -169,7 +169,7 @@ export const { wtsync } = registerControl('wtsync');
* Depth of the LFO for the wavetable oscillator's position
*
* @name wtdepth
- * @tags effects
+ * @tags fx
* @param {number | Pattern} depth depth of modulation
*/
export const { wtdepth } = registerControl('wtdepth');
@@ -178,7 +178,7 @@ export const { wtdepth } = registerControl('wtdepth');
* Shape of the LFO for the wavetable oscillator's position
*
* @name wtshape
- * @tags effects
+ * @tags fx
* @param {number | Pattern} shape Shape of the lfo (0, 1, 2, ..)
*/
export const { wtshape } = registerControl('wtshape');
@@ -187,7 +187,7 @@ export const { wtshape } = registerControl('wtshape');
* DC offset of the LFO for the wavetable oscillator's position
*
* @name wtdc
- * @tags effects
+ * @tags fx
* @param {number | Pattern} dcoffset dc offset. set to 0 for unipolar
*/
export const { wtdc } = registerControl('wtdc');
@@ -196,7 +196,7 @@ export const { wtdc } = registerControl('wtdc');
* Skew of the LFO for the wavetable oscillator's position
*
* @name wtskew
- * @tags effects
+ * @tags fx
* @param {number | Pattern} skew How much to bend the LFO shape
*/
export const { wtskew } = registerControl('wtskew');
@@ -205,7 +205,7 @@ export const { wtskew } = registerControl('wtskew');
* Amount of warp (alteration of the waveform) to apply to the wavetable oscillator
*
* @name warp
- * @tags effects
+ * @tags fx
* @param {number | Pattern} amount Warp of the wavetable from 0 to 1
* @synonyms wavetableWarp
* @example
@@ -218,7 +218,7 @@ export const { warp, wavetableWarp } = registerControl('warp', 'wavetableWarp');
* Attack time of the wavetable oscillator's warp envelope
*
* @name warpattack
- * @tags effects
+ * @tags fx
* @synonyms warpatt
* @param {number | Pattern} time attack time in seconds
*/
@@ -228,7 +228,7 @@ export const { warpattack, warpatt } = registerControl('warpattack', 'warpatt');
* Decay time of the wavetable oscillator's warp envelope
*
* @name warpdecay
- * @tags effects
+ * @tags fx
* @synonyms warpdec
* @param {number | Pattern} time decay time in seconds
*/
@@ -238,7 +238,7 @@ export const { warpdecay, warpdec } = registerControl('warpdecay', 'warpdec');
* Sustain time of the wavetable oscillator's warp envelope
*
* @name warpsustain
- * @tags effects
+ * @tags fx
* @synonyms warpsus
* @param {number | Pattern} gain sustain level (0 to 1)
*/
@@ -248,7 +248,7 @@ export const { warpsustain, warpsus } = registerControl('warpsustain', 'warpsus'
* Release time of the wavetable oscillator's warp envelope
*
* @name warprelease
- * @tags effects
+ * @tags fx
* @synonyms warprel
* @param {number | Pattern} time release time in seconds
*/
@@ -258,7 +258,7 @@ export const { warprelease, warprel } = registerControl('warprelease', 'warprel'
* Rate of the LFO for the wavetable oscillator's warp
*
* @name warprate
- * @tags effects
+ * @tags fx
* @param {number | Pattern} rate rate in hertz
*/
export const { warprate } = registerControl('warprate');
@@ -267,7 +267,7 @@ export const { warprate } = registerControl('warprate');
* Depth of the LFO for the wavetable oscillator's warp
*
* @name warpdepth
- * @tags effects
+ * @tags fx
* @param {number | Pattern} depth depth of modulation
*/
export const { warpdepth } = registerControl('warpdepth');
@@ -276,7 +276,7 @@ export const { warpdepth } = registerControl('warpdepth');
* Shape of the LFO for the wavetable oscillator's warp
*
* @name warpshape
- * @tags effects
+ * @tags fx
* @param {number | Pattern} shape Shape of the lfo (0, 1, 2, ..)
*/
export const { warpshape } = registerControl('warpshape');
@@ -285,7 +285,7 @@ export const { warpshape } = registerControl('warpshape');
* DC offset of the LFO for the wavetable oscillator's warp
*
* @name warpdc
- * @tags effects
+ * @tags fx
* @param {number | Pattern} dcoffset dc offset. set to 0 for unipolar
*/
export const { warpdc } = registerControl('warpdc');
@@ -294,7 +294,7 @@ export const { warpdc } = registerControl('warpdc');
* Skew of the LFO for the wavetable oscillator's warp
*
* @name warpskew
- * @tags effects
+ * @tags fx
* @param {number | Pattern} skew How much to bend the LFO shape
*/
export const { warpskew } = registerControl('warpskew');
@@ -306,7 +306,7 @@ export const { warpskew } = registerControl('warpskew');
* spin, chaos, primes, binary, brownian, reciprocal, wormhole, logistic, sigmoid, fractal, flip
*
* @name warpmode
- * @tags effects
+ * @tags fx
* @param {number | string | Pattern} mode Warp mode
* @synonyms wavetableWarpMode
* @example
@@ -320,7 +320,7 @@ export const { warpmode, wavetableWarpMode } = registerControl('warpmode', 'wave
* Amount of randomness of the initial phase of the wavetable oscillator.
*
* @name wtphaserand
- * @tags effects
+ * @tags fx
* @param {number | Pattern} amount Randomness of the initial phase. Between 0 (not random) and 1 (fully random)
* @synonyms wavetablePhaseRand
* @example
@@ -333,7 +333,7 @@ export const { wtphaserand, wavetablePhaseRand } = registerControl('wtphaserand'
* Amount of envelope applied wavetable oscillator's position envelope
*
* @name warpenv
- * @tags effects
+ * @tags fx
* @param {number | Pattern} amount between 0 and 1
*/
export const { warpenv } = registerControl('warpenv');
@@ -342,7 +342,7 @@ export const { warpenv } = registerControl('warpenv');
* cycle synced rate of the LFO for the wavetable warp position
*
* @name warpsync
- * @tags effects
+ * @tags fx
* @param {number | Pattern} rate rate in cycles
*/
export const { warpsync } = registerControl('warpsync');
@@ -411,7 +411,7 @@ export const { accelerate } = registerControl('accelerate');
* Sets the velocity from 0 to 1. Is multiplied together with gain.
*
* @name velocity
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @example
* s("hh*8")
* .gain(".4!2 1 .4!2 1 .4 1")
@@ -422,7 +422,7 @@ export const { velocity } = registerControl('velocity');
* Controls the gain by an exponential amount.
*
* @name gain
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} amount gain.
* @example
* s("hh*8").gain(".4!2 1 .4!2 1 .4 1").fast(2)
@@ -433,7 +433,7 @@ export const { gain } = registerControl('gain');
* Gain applied after all effects have been processed.
*
* @name postgain
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @example
* s("bd sd [~ bd] sd,hh*8")
* .compressor("-20:20:10:.002:.02").postgain(1.5)
@@ -444,7 +444,7 @@ export const { postgain } = registerControl('postgain');
* Like `gain`, but linear.
*
* @name amp
- * @tags effects
+ * @tags fx
* @param {number | Pattern} amount gain.
* @superdirtOnly
* @example
@@ -456,7 +456,7 @@ export const { amp } = registerControl('amp');
* Amplitude envelope attack time: Specifies how long it takes for the sound to reach its peak value, relative to the onset.
*
* @name attack
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} attack time in seconds.
* @synonyms att
* @example
@@ -472,7 +472,7 @@ export const { attack, att } = registerControl('attack', 'att');
* while decimal numbers and complex ratios sound metallic.
*
* @name fmh
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} harmonicity
* @example
* note("c e g b g e")
@@ -487,7 +487,7 @@ export const { fmh } = registerControl(['fmh', 'fmi'], 'fmh');
* Controls the modulation index, which defines the brightness of the sound.
*
* @name fm
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} brightness modulation index
* @synonyms fmi
* @example
@@ -502,7 +502,7 @@ export const { fmi, fm } = registerControl(['fmi', 'fmh'], 'fm');
* Ramp type of fm envelope. Exp might be a bit broken..
*
* @name fmenv
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} type lin | exp
* @example
* note("c e g b g e")
@@ -518,7 +518,7 @@ export const { fmenv } = registerControl('fmenv');
* Attack time for the FM envelope: time it takes to reach maximum modulation
*
* @name fmattack
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} time attack time
* @example
* note("c e g b g e")
@@ -533,7 +533,7 @@ export const { fmattack } = registerControl('fmattack');
* Waveform of the fm modulator
*
* @name fmwave
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} wave waveform
* @example
* n("0 1 2 3".fast(4)).scale("d:minor").s("sine").fmwave("").fm(4).fmh(2.01)
@@ -547,7 +547,7 @@ export const { fmwave } = registerControl('fmwave');
* Decay time for the FM envelope: seconds until the sustain level is reached after the attack phase.
*
* @name fmdecay
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} time decay time
* @example
* note("c e g b g e")
@@ -562,7 +562,7 @@ export const { fmdecay } = registerControl('fmdecay');
* Sustain level for the FM envelope: how much modulation is applied after the decay phase
*
* @name fmsustain
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} level sustain level
* @example
* note("c e g b g e")
@@ -593,7 +593,7 @@ export const { bank } = registerControl('bank');
* mix control for the chorus effect
*
* @name chorus
- * @tags effects
+ * @tags fx
* @param {string | Pattern} chorus mix amount between 0 and 1
* @example
* note("d d a# a").s("sawtooth").chorus(.5)
@@ -611,7 +611,7 @@ export const { fft } = registerControl('fft');
* Note that the decay is only audible if the sustain value is lower than 1.
*
* @name decay
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} time decay time in seconds
* @synonyms dec
* @example
@@ -623,7 +623,7 @@ export const { decay, dec } = registerControl('decay', 'dec');
* Amplitude envelope sustain level: The level which is reached after attack / decay, being sustained until the offset.
*
* @name sustain
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} gain sustain level between 0 and 1
* @synonyms sus
* @example
@@ -635,7 +635,7 @@ export const { sustain, sus } = registerControl('sustain', 'sus');
* Amplitude envelope release time: The time it takes after the offset to go from sustain level to zero.
*
* @name release
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} time release time in seconds
* @synonyms rel
* @example
@@ -650,7 +650,7 @@ export const { hold } = registerControl('hold');
* can also optionally supply the 'bpq' parameter separated by ':'.
*
* @name bpf
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} frequency center frequency
* @synonyms bandf, bp
* @example
@@ -663,7 +663,7 @@ export const { bandf, bpf, bp } = registerControl(['bandf', 'bandq', 'bpenv'], '
* Sets the **b**and-**p**ass **q**-factor (resonance).
*
* @name bpq
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} q q factor
* @synonyms bandq
* @example
@@ -743,7 +743,7 @@ export const { loopEnd, loope } = registerControl('loopEnd', 'loope');
* Bit crusher effect.
*
* @name crush
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} depth between 1 (for drastic reduction in bit-depth) to 16 (for barely no reduction).
* @example
* s(",hh*3").fast(2).crush("<16 8 7 6 5 4 3 2>")
@@ -755,7 +755,7 @@ export const { crush } = registerControl('crush');
* Fake-resampling for lowering the sample rate. Caution: This effect seems to only work in chromium based browsers
*
* @name coarse
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} factor 1 for original 2 for half, 3 for a third and so on.
* @example
* s("bd sd [~ bd] sd,hh*8").coarse("<1 4 8 16 32>")
@@ -767,7 +767,7 @@ export const { coarse } = registerControl('coarse');
* Modulate the amplitude of a sound with a continuous waveform
*
* @name tremolo
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms trem
* @param {number | Pattern} speed modulation speed in HZ
* @example
@@ -780,7 +780,7 @@ export const { tremolo } = registerControl(['tremolo', 'tremolodepth', 'tremolos
* Modulate the amplitude of a sound with a continuous waveform
*
* @name tremolosync
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms tremsync
* @param {number | Pattern} cycles modulation speed in cycles
* @example
@@ -796,7 +796,7 @@ export const { tremolosync } = registerControl(
* Depth of amplitude modulation
*
* @name tremolodepth
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms tremdepth
* @param {number | Pattern} depth
* @example
@@ -808,7 +808,7 @@ export const { tremolodepth } = registerControl('tremolodepth', 'tremdepth');
* Alter the shape of the modulation waveform
*
* @name tremoloskew
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms tremskew
* @param {number | Pattern} amount between 0 & 1, the shape of the waveform
* @example
@@ -821,7 +821,7 @@ export const { tremoloskew } = registerControl('tremoloskew', 'tremskew');
* Alter the phase of the modulation waveform
*
* @name tremolophase
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms tremphase
* @param {number | Pattern} offset the offset in cycles of the modulation
* @example
@@ -834,7 +834,7 @@ export const { tremolophase } = registerControl('tremolophase', 'tremphase');
* Shape of amplitude modulation
*
* @name tremoloshape
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms tremshape
* @param {number | Pattern} shape tri | square | sine | saw | ramp
* @example
@@ -846,7 +846,7 @@ export const { tremoloshape } = registerControl('tremoloshape', 'tremshape');
* Filter overdrive for supported filter types
*
* @name drive
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {number | Pattern} amount
* @example
* note("{f g g c d a a#}%16".sub(17)).s("supersaw").lpenv(8).lpf(150).lpq(.8).ftype('ladder').drive("<.5 4>")
@@ -860,7 +860,7 @@ export const { drive } = registerControl('drive');
* Can be applied to multiple orbits with the ':' mininotation, e.g. `duckorbit("2:3")`
*
* @name duckorbit
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms duck
* @param {number | Pattern} orbit target orbit
* @example
@@ -881,7 +881,7 @@ export const { duck } = registerControl('duckorbit', 'duck');
* Note: this requires first applying the effect to multiple orbits with e.g. `duckorbit("2:3")`.
*
* @name duckdepth
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {number | Pattern} depth depth of modulation from 0 to 1
* @example
* stack( n(run(8)).scale("c:minor").s("sawtooth").delay(.7).orbit(2), s("bd:4!4").beat("0,4,8,11,14",16).duckorbit(2).duckattack(0.2).duckdepth("<1 .9 .6 0>"))
@@ -901,7 +901,7 @@ export const { duckdepth } = registerControl('duckdepth');
* Note: this requires first applying the effect to multiple orbits with e.g. `duckorbit("2:3")`.
*
* @name duckonset
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms duckons
*
* @param {number | Pattern} time The onset time in seconds
@@ -929,7 +929,7 @@ export const { duckonset } = registerControl('duckonset', 'duckons');
* Note: this requires first applying the effect to multiple orbits with e.g. `duckorbit("2:3")`.
*
* @name duckattack
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms duckatt
*
* @param {number | Pattern} time The attack time in seconds
@@ -949,7 +949,7 @@ export const { duckattack } = registerControl('duckattack', 'duckatt');
*
* @name byteBeatExpression
* @synonyms bbexpr
- * @tags effects
+ * @tags fx
*
* @param {number | Pattern} byteBeatExpression bitwise expression for creating bytebeat
* @example
@@ -963,7 +963,7 @@ export const { byteBeatExpression, bbexpr } = registerControl('byteBeatExpressio
*
* @name byteBeatStartTime
* @synonyms bbst
- * @tags effects
+ * @tags fx
*
* @param {number | Pattern} byteBeatStartTime in samples (t)
* @example
@@ -990,7 +990,7 @@ export const { channels, ch } = registerControl('channels', 'ch');
* Controls the pulsewidth of the pulse oscillator
*
* @name pw
- * @tags effects
+ * @tags fx
* @param {number | Pattern} pulsewidth
* @example
* note("{f a c e}%16").s("pulse").pw(".8:1:.2")
@@ -1003,7 +1003,7 @@ export const { pw } = registerControl(['pw', 'pwrate', 'pwsweep']);
* Controls the lfo rate for the pulsewidth of the pulse oscillator
*
* @name pwrate
- * @tags effects
+ * @tags fx
* @param {number | Pattern} rate
* @example
* n(run(8)).scale("D:pentatonic").s("pulse").pw("0.5").pwrate("<5 .1 25>").pwsweep("<0.3 .8>")
@@ -1016,7 +1016,7 @@ export const { pwrate } = registerControl('pwrate');
* Controls the lfo sweep for the pulsewidth of the pulse oscillator
*
* @name pwsweep
- * @tags effects
+ * @tags fx
* @param {number | Pattern} sweep
* @example
* n(run(8)).scale("D:pentatonic").s("pulse").pw("0.5").pwrate("<5 .1 25>").pwsweep("<0.3 .8>")
@@ -1028,7 +1028,7 @@ export const { pwsweep } = registerControl('pwsweep');
* Phaser audio effect that approximates popular guitar pedals.
*
* @name phaser
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms ph
* @param {number | Pattern} speed speed of modulation
* @example
@@ -1046,7 +1046,7 @@ export const { phaserrate, ph, phaser } = registerControl(
* The frequency sweep range of the lfo for the phaser effect. Defaults to 2000
*
* @name phasersweep
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms phs
* @param {number | Pattern} phasersweep most useful values are between 0 and 4000
* @example
@@ -1060,7 +1060,7 @@ export const { phasersweep, phs } = registerControl('phasersweep', 'phs');
* The center frequency of the phaser in HZ. Defaults to 1000
*
* @name phasercenter
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms phc
* @param {number | Pattern} centerfrequency in HZ
* @example
@@ -1075,7 +1075,7 @@ export const { phasercenter, phc } = registerControl('phasercenter', 'phc');
* The amount the signal is affected by the phaser effect. Defaults to 0.75
*
* @name phaserdepth
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms phd, phasdp
* @param {number | Pattern} depth number between 0 and 1
* @example
@@ -1090,7 +1090,7 @@ export const { phaserdepth, phd, phasdp } = registerControl('phaserdepth', 'phd'
* Choose the channel the pattern is sent to in superdirt
*
* @name channel
- * @tags effects
+ * @tags fx
* @param {number | Pattern} channel channel number
*
*/
@@ -1099,7 +1099,7 @@ export const { channel } = registerControl('channel');
* In the style of classic drum-machines, `cut` will stop a playing sample as soon as another samples with in same cutgroup is to be played. An example would be an open hi-hat followed by a closed one, essentially muting the open.
*
* @name cut
- * @tags effects
+ * @tags fx
* @param {number | Pattern} group cut group number
* @example
* s("[oh hh]*4").cut(1)
@@ -1112,7 +1112,7 @@ export const { cut } = registerControl('cut');
* When using mininotation, you can also optionally add the 'lpq' parameter, separated by ':'.
*
* @name lpf
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} frequency audible between 0 and 20000
* @synonyms cutoff, ctf, lp
* @example
@@ -1126,7 +1126,7 @@ export const { cutoff, ctf, lpf, lp } = registerControl(['cutoff', 'resonance',
/**
* Sets the lowpass filter envelope modulation depth.
* @name lpenv
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} modulation depth of the lowpass filter envelope between 0 and _n_
* @synonyms lpe
* @example
@@ -1140,7 +1140,7 @@ export const { lpenv, lpe } = registerControl('lpenv', 'lpe');
/**
* Sets the highpass filter envelope modulation depth.
* @name hpenv
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} modulation depth of the highpass filter envelope between 0 and _n_
* @synonyms hpe
* @example
@@ -1154,7 +1154,7 @@ export const { hpenv, hpe } = registerControl('hpenv', 'hpe');
/**
* Sets the bandpass filter envelope modulation depth.
* @name bpenv
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} modulation depth of the bandpass filter envelope between 0 and _n_
* @synonyms bpe
* @example
@@ -1168,7 +1168,7 @@ export const { bpenv, bpe } = registerControl('bpenv', 'bpe');
/**
* Sets the attack duration for the lowpass filter envelope.
* @name lpattack
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} attack time of the filter envelope
* @synonyms lpa
* @example
@@ -1182,7 +1182,7 @@ export const { lpattack, lpa } = registerControl('lpattack', 'lpa');
/**
* Sets the attack duration for the highpass filter envelope.
* @name hpattack
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} attack time of the highpass filter envelope
* @synonyms hpa
* @example
@@ -1196,7 +1196,7 @@ export const { hpattack, hpa } = registerControl('hpattack', 'hpa');
/**
* Sets the attack duration for the bandpass filter envelope.
* @name bpattack
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} attack time of the bandpass filter envelope
* @synonyms bpa
* @example
@@ -1210,7 +1210,7 @@ export const { bpattack, bpa } = registerControl('bpattack', 'bpa');
/**
* Sets the decay duration for the lowpass filter envelope.
* @name lpdecay
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} decay time of the filter envelope
* @synonyms lpd
* @example
@@ -1224,7 +1224,7 @@ export const { lpdecay, lpd } = registerControl('lpdecay', 'lpd');
/**
* Sets the decay duration for the highpass filter envelope.
* @name hpdecay
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} decay time of the highpass filter envelope
* @synonyms hpd
* @example
@@ -1239,7 +1239,7 @@ export const { hpdecay, hpd } = registerControl('hpdecay', 'hpd');
/**
* Sets the decay duration for the bandpass filter envelope.
* @name bpdecay
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} decay time of the bandpass filter envelope
* @synonyms bpd
* @example
@@ -1254,7 +1254,7 @@ export const { bpdecay, bpd } = registerControl('bpdecay', 'bpd');
/**
* Sets the sustain amplitude for the lowpass filter envelope.
* @name lpsustain
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} sustain amplitude of the lowpass filter envelope
* @synonyms lps
* @example
@@ -1269,7 +1269,7 @@ export const { lpsustain, lps } = registerControl('lpsustain', 'lps');
/**
* Sets the sustain amplitude for the highpass filter envelope.
* @name hpsustain
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} sustain amplitude of the highpass filter envelope
* @synonyms hps
* @example
@@ -1284,7 +1284,7 @@ export const { hpsustain, hps } = registerControl('hpsustain', 'hps');
/**
* Sets the sustain amplitude for the bandpass filter envelope.
* @name bpsustain
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} sustain amplitude of the bandpass filter envelope
* @synonyms bps
* @example
@@ -1299,7 +1299,7 @@ export const { bpsustain, bps } = registerControl('bpsustain', 'bps');
/**
* Sets the release time for the lowpass filter envelope.
* @name lprelease
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} release time of the filter envelope
* @synonyms lpr
* @example
@@ -1315,7 +1315,7 @@ export const { lprelease, lpr } = registerControl('lprelease', 'lpr');
/**
* Sets the release time for the highpass filter envelope.
* @name hprelease
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} release time of the highpass filter envelope
* @synonyms hpr
* @example
@@ -1331,7 +1331,7 @@ export const { hprelease, hpr } = registerControl('hprelease', 'hpr');
/**
* Sets the release time for the bandpass filter envelope.
* @name bprelease
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} release time of the bandpass filter envelope
* @synonyms bpr
* @example
@@ -1347,7 +1347,7 @@ export const { bprelease, bpr } = registerControl('bprelease', 'bpr');
/**
* Sets the filter type. The ladder filter is more aggressive. More types might be added in the future.
* @name ftype
- * @tags effects
+ * @tags fx
* @param {number | Pattern} type 12db (0), ladder (1), or 24db (2)
* @example
* note("{f g g c d a a#}%8").s("sawtooth").lpenv(4).lpf(500).ftype("<0 1 2>").lpq(1)
@@ -1363,7 +1363,7 @@ export const { ftype } = registerControl('ftype');
/**
* controls the center of the filter envelope. 0 is unipolar positive, .5 is bipolar, 1 is unipolar negative
* @name fanchor
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {number | Pattern} center 0 to 1
* @example
* note("{f g g c d a a#}%8").s("sawtooth").lpf("{1000}%2")
@@ -1376,7 +1376,7 @@ export const { fanchor } = registerControl('fanchor');
* When using mininotation, you can also optionally add the 'hpq' parameter, separated by ':'.
*
* @name hpf
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} frequency audible between 0 and 20000
* @synonyms hp, hcutoff
* @example
@@ -1391,7 +1391,7 @@ export const { fanchor } = registerControl('fanchor');
* Applies a vibrato to the frequency of the oscillator.
*
* @name vib
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @synonyms vibrato, v
* @param {number | Pattern} frequency of the vibrato in hertz
* @example
@@ -1419,7 +1419,7 @@ export const { noise } = registerControl('noise');
* Sets the vibrato depth in semitones. Only has an effect if `vibrato` | `vib` | `v` is is also set
*
* @name vibmod
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @synonyms vmod
* @param {number | Pattern} depth of vibrato (in semitones)
* @example
@@ -1438,7 +1438,7 @@ export const { hcutoff, hpf, hp } = registerControl(['hcutoff', 'hresonance', 'h
* Controls the **h**igh-**p**ass **q**-value.
*
* @name hpq
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} q resonance factor between 0 and 50
* @synonyms hresonance
* @example
@@ -1450,7 +1450,7 @@ export const { hresonance, hpq } = registerControl('hresonance', 'hpq');
* Controls the **l**ow-**p**ass **q**-value.
*
* @name lpq
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} q resonance factor between 0 and 50
* @synonyms resonance
* @example
@@ -1463,7 +1463,7 @@ export const { resonance, lpq } = registerControl('resonance', 'lpq');
* DJ filter, below 0.5 is low pass filter, above is high pass filter.
*
* @name djf
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {number | Pattern} cutoff below 0.5 is low pass filter, above is high pass filter
* @example
* n(irand(16).seg(8)).scale("d:phrygian").s("supersaw").djf("<.5 .3 .2 .75>")
@@ -1480,7 +1480,7 @@ export const { djf } = registerControl('djf');
*
*
* @name delay
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} level between 0 and 1
* @example
* s("bd bd").delay("<0 .25 .5 1>")
@@ -1494,7 +1494,7 @@ export const { delay } = registerControl(['delay', 'delaytime', 'delayfeedback']
* Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it
*
* @name delayfeedback
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} feedback between 0 and 1
* @synonyms delayfb, dfb
* @example
@@ -1508,7 +1508,7 @@ export const { delayfeedback, delayfb, dfb } = registerControl('delayfeedback',
* Caution: Values >= 1 will result in a signal that gets louder and louder! Don't do it
*
* @name delayfeedback
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} feedback between 0 and 1
* @synonyms delayfb, dfb
* @example
@@ -1520,7 +1520,7 @@ export const { delayspeed } = registerControl('delayspeed');
* Sets the time of the delay effect.
*
* @name delayspeed
- * @tags effects
+ * @tags fx
* @param {number | Pattern} delayspeed controls the pitch of the delay feedback
* @synonyms delayt, dt
* @example
@@ -1533,7 +1533,7 @@ export const { delaytime, delayt, dt } = registerControl('delaytime', 'delayt',
* Sets the time of the delay effect in cycles.
*
* @name delaysync
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {number | Pattern} cycles delay length in cycles
* @synonyms delayt, dt
* @example
@@ -1546,7 +1546,7 @@ export const { delaysync } = registerControl('delaysync');
* Specifies whether delaytime is calculated relative to cps.
*
* @name lock
- * @tags effects
+ * @tags fx
* @param {number | Pattern} enable When set to 1, delaytime is a direct multiple of a cycle.
* @superdirtOnly
* @example
@@ -1560,7 +1560,7 @@ export const { lock } = registerControl('lock');
* Set detune for stacked voices of supported oscillators
*
* @name detune
- * @tags effects
+ * @tags fx
* @param {number | Pattern} amount
* @synonyms det
* @example
@@ -1572,7 +1572,7 @@ export const { detune, det } = registerControl('detune', 'det');
* Set number of stacked voices for supported oscillators
*
* @name unison
- * @tags effects
+ * @tags fx
* @param {number | Pattern} numvoices
* @example
* note("d f a a# a d3").fast(2).s("supersaw").unison("<1 2 7>")
@@ -1584,7 +1584,7 @@ export const { unison } = registerControl('unison');
* Set the stereo pan spread for supported oscillators
*
* @name spread
- * @tags effects
+ * @tags fx
* @param {number | Pattern} spread between 0 and 1
* @example
* note("d f a a# a d3").fast(2).s("supersaw").spread("<0 .3 1>")
@@ -1595,7 +1595,7 @@ export const { spread } = registerControl('spread');
* Set dryness of reverb. See `room` and `size` for more information about reverb.
*
* @name dry
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {number | Pattern} dry 0 = wet, 1 = dry
* @example
* n("[0,3,7](3,8)").s("superpiano").room(.7).dry("<0 .5 .75 1>").osc()
@@ -1635,7 +1635,7 @@ export const { freq } = registerControl('freq');
* Attack time of pitch envelope.
*
* @name pattack
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @synonyms patt
* @param {number | Pattern} time time in seconds
* @example
@@ -1647,7 +1647,7 @@ export const { pattack, patt } = registerControl('pattack', 'patt');
* Decay time of pitch envelope.
*
* @name pdecay
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @synonyms pdec
* @param {number | Pattern} time time in seconds
* @example
@@ -1661,7 +1661,7 @@ export const { psustain, psus } = registerControl('psustain', 'psus');
* Release time of pitch envelope
*
* @name prelease
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @synonyms prel
* @param {number | Pattern} time time in seconds
* @example
@@ -1676,7 +1676,7 @@ export const { prelease, prel } = registerControl('prelease', 'prel');
* If you don't set other pitch envelope controls, `pattack:.2` will be the default.
*
* @name penv
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} semitones change in semitones
* @example
* note("c")
@@ -1688,7 +1688,7 @@ export const { penv } = registerControl('penv');
* Curve of envelope. Defaults to linear. exponential is good for kicks
*
* @name pcurve
- * @tags effects
+ * @tags fx
* @param {number | Pattern} type 0 = linear, 1 = exponential
* @example
* note("g1*4")
@@ -1705,7 +1705,7 @@ export const { pcurve } = registerControl('pcurve');
* If you don't set an anchor, the value will default to the psustain value.
*
* @name panchor
- * @tags effects
+ * @tags fx
* @param {number | Pattern} anchor anchor offset
* @example
* note("c c4").penv(12).panchor("<0 .5 1 .5>")
@@ -1727,7 +1727,7 @@ export const { gate, gat } = registerControl('gate', 'gat');
* Emulation of a Leslie speaker: speakers rotating in a wooden amplified cabinet.
*
* @name leslie
- * @tags effects
+ * @tags fx
* @param {number | Pattern} wet between 0 and 1
* @example
* n("0,4,7").s("supersquare").leslie("<0 .4 .6 1>").osc()
@@ -1739,7 +1739,7 @@ export const { leslie } = registerControl('leslie');
* Rate of modulation / rotation for leslie effect
*
* @name lrate
- * @tags effects
+ * @tags fx
* @param {number | Pattern} rate 6.7 for fast, 0.7 for slow
* @example
* n("0,4,7").s("supersquare").leslie(1).lrate("<1 2 4 8>").osc()
@@ -1752,7 +1752,7 @@ export const { lrate } = registerControl('lrate');
* Physical size of the cabinet in meters. Be careful, it might be slightly larger than your computer. Affects the Doppler amount (pitch warble)
*
* @name lsize
- * @tags effects
+ * @tags fx
* @param {number | Pattern} meters somewhere between 0 and 1
* @example
* n("0,4,7").s("supersquare").leslie(1).lrate(2).lsize("<.1 .5 1>").osc()
@@ -1814,7 +1814,7 @@ export const { octave } = registerControl('octave');
* An `orbit` is a global parameter context for patterns. Patterns with the same orbit will share the same global effects.
*
* @name orbit
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {number | Pattern} number
* @example
* stack(
@@ -1831,7 +1831,7 @@ export const { overshape } = registerControl('overshape');
* Sets position in stereo.
*
* @name pan
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @param {number | Pattern} pan between 0 and 1, from left to right (assuming stereo), once round a circle (assuming multichannel)
* @example
* s("[bd hh]*2").pan("<.5 1 .5 0>")
@@ -1897,7 +1897,7 @@ export const { mode } = registerControl(['mode', 'anchor']);
* When using mininotation, you can also optionally add the 'size' parameter, separated by ':'.
*
* @name room
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {number | Pattern} level between 0 and 1
* @example
* s("bd sd [~ bd] sd").room("<0 .2 .4 .6 .8 1>")
@@ -1911,7 +1911,7 @@ export const { room } = registerControl(['room', 'size']);
* When this property is changed, the reverb will be recaculated, so only change this sparsely..
*
* @name roomlp
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms rlp
* @param {number} frequency between 0 and 20000hz
* @example
@@ -1925,7 +1925,7 @@ export const { roomlp, rlp } = registerControl('roomlp', 'rlp');
* When this property is changed, the reverb will be recaculated, so only change this sparsely..
*
* @name roomdim
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms rdim
* @param {number} frequency between 0 and 20000hz
* @example
@@ -1940,7 +1940,7 @@ export const { roomdim, rdim } = registerControl('roomdim', 'rdim');
* When this property is changed, the reverb will be recaculated, so only change this sparsely..
*
* @name roomfade
- * @tags effects, superdough
+ * @tags fx, superdough
* @synonyms rfade
* @param {number} seconds for the reverb to fade
* @example
@@ -1953,7 +1953,7 @@ export const { roomfade, rfade } = registerControl('roomfade', 'rfade');
/**
* Sets the sample to use as an impulse response for the reverb.
* @name iresponse
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {string | Pattern} sample to use as an impulse response
* @synonyms ir
* @example
@@ -1965,7 +1965,7 @@ export const { ir, iresponse } = registerControl(['ir', 'i'], 'iresponse');
/**
* Sets speed of the sample for the impulse response.
* @name irspeed
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {string | Pattern} speed
* @example
* samples('github:switchangel/pad')
@@ -1977,7 +1977,7 @@ export const { irspeed } = registerControl('irspeed');
/**
* Sets the beginning of the IR response sample
* @name irbegin
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {string | Pattern} begin between 0 and 1
* @synonyms ir
* @example
@@ -1991,7 +1991,7 @@ export const { irbegin } = registerControl('irbegin');
* When this property is changed, the reverb will be recaculated, so only change this sparsely..
*
* @name roomsize
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {number | Pattern} size between 0 and 10
* @synonyms rsize, sz, size
* @example
@@ -2015,7 +2015,7 @@ export const { roomsize, size, sz, rsize } = registerControl('roomsize', 'size',
*
*
* @name shape
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {number | Pattern} distortion between 0 and 1
* @example
* s("bd sd [~ bd] sd,hh*8").shape("<0 .2 .4 .6 .8>")
@@ -2028,7 +2028,7 @@ export const { shape } = registerControl(['shape', 'shapevol']);
* Most useful values are usually between 0 and 10 (depending on source gain). If you are feeling adventurous, you can turn it up to 11 and beyond ;)
*
* @name distort
- * @tags effects, superdough, supradough
+ * @tags fx, superdough, supradough
* @synonyms dist
* @param {number | Pattern} distortion
* @example
@@ -2043,7 +2043,7 @@ export const { distort, dist } = registerControl(['distort', 'distortvol'], 'dis
* More info [here](https://developer.mozilla.org/en-US/docs/Web/API/DynamicsCompressorNode?retiredLocale=de#instance_properties)
*
* @name compressor
- * @tags effects, superdough
+ * @tags fx, superdough
* @example
* s("bd sd [~ bd] sd,hh*8")
* .compressor("-20:20:10:.002:.02")
@@ -2064,7 +2064,7 @@ export const { compressorRelease } = registerControl('compressorRelease');
* Changes the speed of sample playback, i.e. a cheap way of changing pitch.
*
* @name speed
- * @tags effects
+ * @tags fx
* @param {number | Pattern} speed -inf to inf, negative numbers play the sample backwards.
* @example
* s("bd*6").speed("1 2 4 1 -2 -4")
@@ -2078,7 +2078,7 @@ export const { speed } = registerControl('speed');
* Changes the speed of sample playback, i.e. a cheap way of changing pitch.
*
* @name stretch
- * @tags effects
+ * @tags fx
* @param {number | Pattern} factor -inf to inf, negative numbers play the sample backwards.
* @example
* s("gm_flute").stretch("1 2 .5")
@@ -2089,7 +2089,7 @@ export const { stretch } = registerControl('stretch');
* Used in conjunction with `speed`, accepts values of "r" (rate, default behavior), "c" (cycles), or "s" (seconds). Using `unit "c"` means `speed` will be interpreted in units of cycles, e.g. `speed "1"` means samples will be stretched to fill a cycle. Using `unit "s"` means the playback speed will be adjusted so that the duration is the number of seconds specified by `speed`.
*
* @name unit
- * @tags effects
+ * @tags fx
* @param {number | string | Pattern} unit see description above
* @example
* speed("1 2 .5 3").s("bd").unit("c").osc()
@@ -2104,7 +2104,7 @@ export const { unit } = registerControl('unit');
* "A simplistic pitch-raising algorithm. It's not meant to sound natural; its sound is reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter, depending on the input. The algorithm works by cutting the signal into fragments (delimited by upwards-going zero-crossings) and squeezing those fragments in the time domain (i.e. simply playing them back faster than they came in), leaving silences inbetween. All the parameters apart from memlen can be modulated."
*
* @name squiz
- * @tags effects
+ * @tags fx
* @param {number | Pattern} squiz Try passing multiples of 2 to it - 2, 4, 8 etc.
* @example
* squiz("2 4/2 6 [8 16]").s("bd").osc()
@@ -2129,7 +2129,7 @@ export const { squiz } = registerControl('squiz');
* Formant filter to make things sound like vowels.
*
* @name vowel
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {string | Pattern} vowel You can use a e i o u ae aa oe ue y uh un en an on, corresponding to [a] [e] [i] [o] [u] [æ] [ɑ] [ø] [y] [ɯ] [ʌ] [œ̃] [ɛ̃] [ɑ̃] [ɔ̃]. Aliases: aa = å = ɑ, oe = ø = ö, y = ı, ae = æ.
* @example
* note("[c2 >]*2").s('sawtooth')
@@ -2154,7 +2154,7 @@ export const { waveloss } = registerControl('waveloss');
* Noise crackle density
*
* @name density
- * @tags effects, superdough
+ * @tags fx, superdough
* @param {number | Pattern} density between 0 and x
* @example
* s("crackle*4").density("<0.01 0.04 0.2 0.5>".slow(4))
@@ -2262,7 +2262,7 @@ export let createParams = (...names) =>
* ADSR envelope: Combination of Attack, Decay, Sustain, and Release.
*
* @name adsr
- * @tags effects
+ * @tags fx
* @param {number | Pattern} time attack time in seconds
* @param {number | Pattern} time decay time in seconds
* @param {number | Pattern} gain sustain level (0 to 1)
diff --git a/packages/superdough/wavetable.mjs b/packages/superdough/wavetable.mjs
index cfc669c83..677d83628 100644
--- a/packages/superdough/wavetable.mjs
+++ b/packages/superdough/wavetable.mjs
@@ -180,7 +180,7 @@ export function registerWaveTable(key, tables, params) {
* Loads a collection of wavetables to use with `s`
*
* @name tables
- * @tags effects
+ * @tags fx
*/
export const tables = async (url, frameLen, json, options = {}) => {
if (json !== undefined) return _processTables(json, url, frameLen);
diff --git a/packages/supradough/dough.mjs b/packages/supradough/dough.mjs
index 23dfbee09..9b5bf189e 100644
--- a/packages/supradough/dough.mjs
+++ b/packages/supradough/dough.mjs
@@ -18,7 +18,7 @@ function applyGainCurve(val) {
* @param {number} a - Signal A (can be a single value or an array value in buffer processing).
* @param {number} b - Signal B (can be a single value or an array value in buffer processing).
* @param {number} m - Crossfade parameter (0.0 = all A, 1.0 = all B, 0.5 = equal mix).
- * @tags effects
+ * @noAutocomplete
* @returns {number} Crossfaded output value.
*/
function crossfade(a, b, m) {
From 7e4cbefc8fa812769f35eb9da29d3f50839518e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Va=CC=81clav=20Volhejn?=
Date: Sun, 19 Oct 2025 21:22:57 +0200
Subject: [PATCH 014/124] Tag crossfade as internals
---
packages/supradough/dough.mjs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/supradough/dough.mjs b/packages/supradough/dough.mjs
index 9b5bf189e..a31097339 100644
--- a/packages/supradough/dough.mjs
+++ b/packages/supradough/dough.mjs
@@ -18,7 +18,7 @@ function applyGainCurve(val) {
* @param {number} a - Signal A (can be a single value or an array value in buffer processing).
* @param {number} b - Signal B (can be a single value or an array value in buffer processing).
* @param {number} m - Crossfade parameter (0.0 = all A, 1.0 = all B, 0.5 = equal mix).
- * @noAutocomplete
+ * @tags internals
* @returns {number} Crossfaded output value.
*/
function crossfade(a, b, m) {
From 466bf819d883b7f2e35a5dc617727c53765d71cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Va=CC=81clav=20Volhejn?=
Date: Sun, 19 Oct 2025 21:38:46 +0200
Subject: [PATCH 015/124] Fix formatting (trailing space)
---
packages/superdough/worklets.mjs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/superdough/worklets.mjs b/packages/superdough/worklets.mjs
index 3e8276225..b99b9caf6 100644
--- a/packages/superdough/worklets.mjs
+++ b/packages/superdough/worklets.mjs
@@ -852,7 +852,7 @@ class PulseOscillatorProcessor extends AudioWorkletProcessor {
registerProcessor('pulse-oscillator', PulseOscillatorProcessor);
/** BYTE BEATS
- * @tags internals
+ * @tags internals
*/
const chyx = {
/*bit*/ bitC: function (x, y, z) {
From 0830a9df69ddd49bcec08f25b58b390a103bbb74 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Va=CC=81clav=20Volhejn?=
Date: Sat, 1 Nov 2025 20:19:57 +0100
Subject: [PATCH 016/124] Add superdirt tags
---
packages/core/controls.mjs | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs
index 1bfd5a892..da5337ecf 100644
--- a/packages/core/controls.mjs
+++ b/packages/core/controls.mjs
@@ -399,7 +399,7 @@ export const { note } = registerControl(['note', 'n']);
* A pattern of numbers that speed up (or slow down) samples while they play. Currently only supported by osc / superdirt.
*
* @name accelerate
- * @tags samples
+ * @tags samples, superdirt
* @param {number | Pattern} amount acceleration.
* @superdirtOnly
* @example
@@ -444,7 +444,7 @@ export const { postgain } = registerControl('postgain');
* Like `gain`, but linear.
*
* @name amp
- * @tags fx
+ * @tags fx, superdirt
* @param {number | Pattern} amount gain.
* @superdirtOnly
* @example
@@ -1075,7 +1075,7 @@ export const { phasercenter, phc } = registerControl('phasercenter', 'phc');
* The amount the signal is affected by the phaser effect. Defaults to 0.75
*
* @name phaserdepth
- * @tags fx, superdough
+ * @tags fx, superdough, superdirt
* @synonyms phd, phasdp
* @param {number | Pattern} depth number between 0 and 1
* @example
@@ -1546,7 +1546,7 @@ export const { delaysync } = registerControl('delaysync');
* Specifies whether delaytime is calculated relative to cps.
*
* @name lock
- * @tags fx
+ * @tags fx, superdirt
* @param {number | Pattern} enable When set to 1, delaytime is a direct multiple of a cycle.
* @superdirtOnly
* @example
@@ -1595,7 +1595,7 @@ export const { spread } = registerControl('spread');
* Set dryness of reverb. See `room` and `size` for more information about reverb.
*
* @name dry
- * @tags fx, superdough
+ * @tags fx, superdough, superdirt
* @param {number | Pattern} dry 0 = wet, 1 = dry
* @example
* n("[0,3,7](3,8)").s("superpiano").room(.7).dry("<0 .5 .75 1>").osc()
@@ -1727,7 +1727,7 @@ export const { gate, gat } = registerControl('gate', 'gat');
* Emulation of a Leslie speaker: speakers rotating in a wooden amplified cabinet.
*
* @name leslie
- * @tags fx
+ * @tags fx, superdirt
* @param {number | Pattern} wet between 0 and 1
* @example
* n("0,4,7").s("supersquare").leslie("<0 .4 .6 1>").osc()
@@ -1739,7 +1739,7 @@ export const { leslie } = registerControl('leslie');
* Rate of modulation / rotation for leslie effect
*
* @name lrate
- * @tags fx
+ * @tags fx, superdirt
* @param {number | Pattern} rate 6.7 for fast, 0.7 for slow
* @example
* n("0,4,7").s("supersquare").leslie(1).lrate("<1 2 4 8>").osc()
@@ -1752,7 +1752,7 @@ export const { lrate } = registerControl('lrate');
* Physical size of the cabinet in meters. Be careful, it might be slightly larger than your computer. Affects the Doppler amount (pitch warble)
*
* @name lsize
- * @tags fx
+ * @tags fx, superdirt
* @param {number | Pattern} meters somewhere between 0 and 1
* @example
* n("0,4,7").s("supersquare").leslie(1).lrate(2).lsize("<.1 .5 1>").osc()
@@ -1801,6 +1801,7 @@ export const { nudge } = registerControl('nudge');
* Sets the default octave of a synth.
*
* @name octave
+ * @tags fx, superdirt
* @param {number | Pattern} octave octave number
* @example
* n("0,4,7").s('supersquare').octave("<3 4 5 6>").osc()
@@ -2089,7 +2090,7 @@ export const { stretch } = registerControl('stretch');
* Used in conjunction with `speed`, accepts values of "r" (rate, default behavior), "c" (cycles), or "s" (seconds). Using `unit "c"` means `speed` will be interpreted in units of cycles, e.g. `speed "1"` means samples will be stretched to fill a cycle. Using `unit "s"` means the playback speed will be adjusted so that the duration is the number of seconds specified by `speed`.
*
* @name unit
- * @tags fx
+ * @tags fx, superdirt
* @param {number | string | Pattern} unit see description above
* @example
* speed("1 2 .5 3").s("bd").unit("c").osc()
@@ -2104,7 +2105,7 @@ export const { unit } = registerControl('unit');
* "A simplistic pitch-raising algorithm. It's not meant to sound natural; its sound is reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter, depending on the input. The algorithm works by cutting the signal into fragments (delimited by upwards-going zero-crossings) and squeezing those fragments in the time domain (i.e. simply playing them back faster than they came in), leaving silences inbetween. All the parameters apart from memlen can be modulated."
*
* @name squiz
- * @tags fx
+ * @tags fx, superdirt
* @param {number | Pattern} squiz Try passing multiples of 2 to it - 2, 4, 8 etc.
* @example
* squiz("2 4/2 6 [8 16]").s("bd").osc()
From b7827cb89f16624773f9c5717d64419d1a729154 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Va=CC=81clav=20Volhejn?=
Date: Sat, 1 Nov 2025 21:11:57 +0100
Subject: [PATCH 017/124] Tag new functions
---
packages/core/controls.mjs | 4 ++
packages/core/pattern.mjs | 9 ++++
.../src/repl/components/panel/Reference.jsx | 42 ++++---------------
3 files changed, 20 insertions(+), 35 deletions(-)
diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs
index 50a494864..7c66b4002 100644
--- a/packages/core/controls.mjs
+++ b/packages/core/controls.mjs
@@ -2049,6 +2049,7 @@ export const { distort, dist } = registerControl(['distort', 'distortvol', 'dist
*
* @name distortvol
* @synonyms distvol
+ * @tags fx, superdough, supradough
* @param {number | Pattern} volume linear postgain of the distortion
* @example
* s("bd*4").bank("tr909").distort(2).distortvol(0.8)
@@ -2059,6 +2060,7 @@ export const { distortvol } = registerControl('distortvol', 'distvol');
* Type of waveshaping distortion to apply.
*
* @name distorttype
+ * @tags fx, superdough, supradough
* @synonyms disttype
* @param {number | string | Pattern} type type of distortion to apply
* @example
@@ -2487,6 +2489,7 @@ export const { polyTouch } = registerControl('polyTouch');
/**
* The host to send open sound control messages to. Requires running the OSC bridge.
* @name oschost
+ * @tags external_io
* @param {string | Pattern} oschost e.g. 'localhost'
* @example
* note("c4").oschost('127.0.0.1').oscport(57120).osc();
@@ -2496,6 +2499,7 @@ export const { oschost } = registerControl('oschost');
/**
* The port to send open sound control messages to. Requires running the OSC bridge.
* @name oscport
+ * @tags external_io
* @param {number | Pattern} oscport e.g. 57120
* @example
* note("c4").oschost('127.0.0.1').oscport(57120).osc();
diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs
index 8cb30e155..e8cd3d23f 100644
--- a/packages/core/pattern.mjs
+++ b/packages/core/pattern.mjs
@@ -3128,6 +3128,7 @@ export const extend = stepRegister('extend', function (factor, pat) {
* `stepcat("a b".fast(2), "c d")` would be the same as `"[a b] [a b] c d"`.
*
* TODO: find out how this function differs from extend
+ * @tags temporal
* @example
* stepcat(
* sound("bd bd - cp").replicate(2),
@@ -3697,6 +3698,7 @@ export const morph = (frompat, topat, bypat) => {
* Soft-clipping distortion
*
* @name soft
+ * @tags fx
* @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion
*
@@ -3705,6 +3707,7 @@ export const morph = (frompat, topat, bypat) => {
* Hard-clipping distortion
*
* @name hard
+ * @tags fx
* @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion
*
@@ -3713,6 +3716,7 @@ export const morph = (frompat, topat, bypat) => {
* Cubic polynomial distortion
*
* @name cubic
+ * @tags fx
* @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion
*
@@ -3721,6 +3725,7 @@ export const morph = (frompat, topat, bypat) => {
* Diode-emulating distortion
*
* @name diode
+ * @tags fx
* @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion
*
@@ -3729,6 +3734,7 @@ export const morph = (frompat, topat, bypat) => {
* Asymmetrical diode distortion
*
* @name asym
+ * @tags fx
* @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion
*
@@ -3737,6 +3743,7 @@ export const morph = (frompat, topat, bypat) => {
* Wavefolding distortion
*
* @name fold
+ * @tags fx
* @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion
*
@@ -3745,6 +3752,7 @@ export const morph = (frompat, topat, bypat) => {
* Wavefolding distortion composed with sinusoid
*
* @name sinefold
+ * @tags fx
* @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion
*
@@ -3753,6 +3761,7 @@ export const morph = (frompat, topat, bypat) => {
* Distortion via Chebyshev polynomials
*
* @name chebyshev
+ * @tags fx
* @param {number | Pattern} distortion amount of distortion to apply
* @param {number | Pattern} volume linear postgain of the distortion
*
diff --git a/website/src/repl/components/panel/Reference.jsx b/website/src/repl/components/panel/Reference.jsx
index 2a7dcc2a8..3053f03dc 100644
--- a/website/src/repl/components/panel/Reference.jsx
+++ b/website/src/repl/components/panel/Reference.jsx
@@ -11,8 +11,13 @@ const availableFunctions = (() => {
for (const doc of jsdocJson.docs) {
if (!isValid(doc)) continue;
if (seen.has(doc.name)) continue;
- doc.tags = doc.tags?.filter((t) => t && typeof t === 'string') || [];
+
+ // jsdoc also uses "tags" for when you use @something in the comments and it doesn't know what
+ // @something is. We only want data from comments like `@tags fx, superdough` here.
+ // If nothing is specified, we default to "untagged" for debugging
+ doc.tags = doc.tags?.filter((t) => t && typeof t === 'string') || ['untagged'];
functions.push(doc);
+
const synonyms = doc.synonyms || [];
seen.add(doc.name);
for (const s of synonyms) {
@@ -38,16 +43,6 @@ const getInnerText = (html) => {
return div.textContent || div.innerText || '';
};
-const GROUP_DISPLAY_NAMES = {
- external_io: 'External I/O',
- effects: 'Effects',
- untagged: 'Untagged',
- structure: 'Structure',
- transforms: 'Transforms',
-};
-
-const GROUP_ORDER = ['effects', 'transforms', 'structure', 'untagged', 'external_io'];
-
export function Reference() {
const [search, setSearch] = useState('');
const [selectedTag, setSelectedTag] = useState(null);
@@ -80,29 +75,6 @@ export function Reference() {
});
}, [search, selectedTag]);
- const visibleFunctionsByGroup = (() => {
- const groups = {};
- for (const doc of visibleFunctions) {
- const group = (doc.tags || ['untagged'])[0];
- if (!groups[group]) {
- groups[group] = [];
- }
- groups[group].push(doc);
- }
- return groups;
- })();
- // console.log(visibleFunctionsByGroup);
-
- // Sort and map group entries
- const sortedGroups = Object.entries(visibleFunctionsByGroup).sort(([a], [b]) => {
- const ai = GROUP_ORDER.indexOf(a);
- const bi = GROUP_ORDER.indexOf(b);
- if (ai === -1 && bi === -1) return a.localeCompare(b);
- if (ai === -1) return 1;
- if (bi === -1) return -1;
- return ai - bi;
- });
-
const tagCounts = {};
for (const doc of availableFunctions) {
(doc.tags || ['untagged']).forEach((t) => {
@@ -114,7 +86,7 @@ export function Reference() {
return (
-
);
From 726e5ef14a6de2aab36202434ac52ae45c5e551f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Va=CC=81clav=20Volhejn?=
Date: Sat, 10 Jan 2026 07:18:29 -0800
Subject: [PATCH 070/124] Fix formatting
---
packages/midi/midi.mjs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs
index 9b32f6de4..63faeaf41 100644
--- a/packages/midi/midi.mjs
+++ b/packages/midi/midi.mjs
@@ -488,7 +488,7 @@ const refsByChan = {};
* MIDI input: Opens a MIDI input port to receive MIDI control change messages.
*
* The output is a function that accepts a midi cc value to query as well as (optionally) a midi channel
- * @tags external_io
+ * @tags external_io
* @param {string | number} input MIDI device name or index defaulting to 0
* @returns {function(number, number=): Pattern} A function from (cc, channel?) to a pattern.
* When queried, the pattern will produces the most recently received midi value (normalized to 0 to 1)
From d753eedb901c1ead239f8f288d887af292f3ce66 Mon Sep 17 00:00:00 2001
From: Aria
Date: Sat, 10 Jan 2026 11:20:17 -0600
Subject: [PATCH 071/124] Make latency consistent across all cps
---
packages/core/repl.mjs | 3 ++-
packages/core/time.mjs | 9 +++++++++
packages/midi/midi.mjs | 6 ++++--
3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs
index 4d59f5990..77ceac8c5 100644
--- a/packages/core/repl.mjs
+++ b/packages/core/repl.mjs
@@ -2,7 +2,7 @@ import { NeoCyclist } from './neocyclist.mjs';
import { Cyclist } from './cyclist.mjs';
import { evaluate as _evaluate } from './evaluate.mjs';
import { errorLogger, logger } from './logger.mjs';
-import { setTime } from './time.mjs';
+import { setCpsFunc, setTime } from './time.mjs';
import { evalScope } from './evaluate.mjs';
import { register, Pattern, isPattern, silence, stack } from './pattern.mjs';
@@ -61,6 +61,7 @@ export function repl({
// 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);
+ setCpsFunc(() => scheduler.cps);
let pPatterns = {};
let anonymousIndex = 0;
let allTransform;
diff --git a/packages/core/time.mjs b/packages/core/time.mjs
index 80daaf53c..3d94a694c 100644
--- a/packages/core/time.mjs
+++ b/packages/core/time.mjs
@@ -1,4 +1,5 @@
let time;
+let cpsFunc;
export function getTime() {
if (!time) {
throw new Error('no time set! use setTime to define a time source');
@@ -9,3 +10,11 @@ export function getTime() {
export function setTime(func) {
time = func;
}
+
+export function setCpsFunc(func) {
+ cpsFunc = func;
+}
+
+export function getCps() {
+ return cpsFunc?.();
+}
diff --git a/packages/midi/midi.mjs b/packages/midi/midi.mjs
index d4f6093a0..6233bf60d 100644
--- a/packages/midi/midi.mjs
+++ b/packages/midi/midi.mjs
@@ -5,7 +5,7 @@ This program is free software: you can redistribute it and/or modify it under th
*/
import * as _WebMidi from 'webmidi';
-import { Hap, Pattern, TimeSpan, getTime, isPattern, logger, ref, reify } from '@strudel/core';
+import { Hap, Pattern, TimeSpan, getCps, getTime, isPattern, logger, ref, reify } from '@strudel/core';
import { noteToMidi, getControlName } from '@strudel/core';
import { Note } from 'webmidi';
import { scheduleAtTime } from '../superdough/helpers.mjs';
@@ -586,7 +586,9 @@ export async function midikeys(input) {
const [note, velocity] = dataBytes;
const noteoff = message.command === 8;
const key = `${input}_${note}`;
- const t = getTime() + 0.03; // slight delay so it's not too late for cyclist to catch
+ const cps = getCps() ?? 0.5;
+ const latencySeconds = 0.06; // slight delay so it's not too late for cyclist to catch
+ const t = getTime() + latencySeconds * cps;
const span = new TimeSpan(t, t);
let value = { midikey: key };
if (noteoff) {
From dab16767612e88e2337c46e938d387f361fdceda Mon Sep 17 00:00:00 2001
From: Aria
Date: Sat, 10 Jan 2026 11:26:30 -0600
Subject: [PATCH 072/124] Add license for time file
---
packages/core/time.mjs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/packages/core/time.mjs b/packages/core/time.mjs
index 3d94a694c..2d4caecf5 100644
--- a/packages/core/time.mjs
+++ b/packages/core/time.mjs
@@ -1,3 +1,9 @@
+/*
+time.mjs - Core time module. Used to expose parameters from the Scheduler like `time` and `cps`
+Copyright (C) 2026 Strudel contributors - see
+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 .
+*/
+
let time;
let cpsFunc;
export function getTime() {
From 0cf11adc2c8416ed1df1563b3f6c16cc7dc637fd Mon Sep 17 00:00:00 2001
From: Aria
Date: Sat, 10 Jan 2026 13:07:54 -0600
Subject: [PATCH 073/124] Allow naked distortions for the purpose of FX
---
packages/core/pattern.mjs | 37 +++++++++++++++++++++++++++++--------
1 file changed, 29 insertions(+), 8 deletions(-)
diff --git a/packages/core/pattern.mjs b/packages/core/pattern.mjs
index 02cf91881..58c83a6f8 100644
--- a/packages/core/pattern.mjs
+++ b/packages/core/pattern.mjs
@@ -3586,6 +3586,20 @@ export const morph = (frompat, topat, bypat) => {
return frompat.innerBind((from) => topat.innerBind((to) => bypat.innerBind((by) => _morph(from, to, by))));
};
+const _distortWithAlg = function (name) {
+ const func = function (args, pat) {
+ const argsPat = reify(args).fmap((v) => (Array.isArray(v) ? [...v, name] : [v, 1, name]));
+ if (!pat) {
+ return pure({}).distort(argsPat);
+ }
+ return pat.distort(argsPat);
+ };
+ Pattern.prototype[name] = function (args) {
+ return func(args, this);
+ };
+ return func;
+};
+
/**
* Soft-clipping distortion
*
@@ -3594,6 +3608,8 @@ export const morph = (frompat, topat, bypat) => {
* @param {number | Pattern} volume linear postgain of the distortion
*
*/
+export const soft = _distortWithAlg('soft');
+
/**
* Hard-clipping distortion
*
@@ -3602,6 +3618,8 @@ export const morph = (frompat, topat, bypat) => {
* @param {number | Pattern} volume linear postgain of the distortion
*
*/
+export const hard = _distortWithAlg('hard');
+
/**
* Cubic polynomial distortion
*
@@ -3610,6 +3628,8 @@ export const morph = (frompat, topat, bypat) => {
* @param {number | Pattern} volume linear postgain of the distortion
*
*/
+export const cubic = _distortWithAlg('cubic');
+
/**
* Diode-emulating distortion
*
@@ -3618,6 +3638,8 @@ export const morph = (frompat, topat, bypat) => {
* @param {number | Pattern} volume linear postgain of the distortion
*
*/
+export const diode = _distortWithAlg('diode');
+
/**
* Asymmetrical diode distortion
*
@@ -3626,6 +3648,8 @@ export const morph = (frompat, topat, bypat) => {
* @param {number | Pattern} volume linear postgain of the distortion
*
*/
+export const asym = _distortWithAlg('asym');
+
/**
* Wavefolding distortion
*
@@ -3634,6 +3658,8 @@ export const morph = (frompat, topat, bypat) => {
* @param {number | Pattern} volume linear postgain of the distortion
*
*/
+export const fold = _distortWithAlg('fold');
+
/**
* Wavefolding distortion composed with sinusoid
*
@@ -3642,6 +3668,8 @@ export const morph = (frompat, topat, bypat) => {
* @param {number | Pattern} volume linear postgain of the distortion
*
*/
+export const sinefold = _distortWithAlg('sinefold');
+
/**
* Distortion via Chebyshev polynomials
*
@@ -3650,14 +3678,7 @@ export const morph = (frompat, topat, bypat) => {
* @param {number | Pattern} volume linear postgain of the distortion
*
*/
-const distAlgoNames = ['scurve', 'soft', 'hard', 'cubic', 'diode', 'asym', 'fold', 'sinefold', 'chebyshev'];
-for (const name of distAlgoNames) {
- // Add aliases for distortion algorithms
- Pattern.prototype[name] = function (args) {
- const argsPat = reify(args).fmap((v) => (Array.isArray(v) ? [...v, name] : [v, 1, name]));
- return this.distort(argsPat);
- };
-}
+export const chebyshev = _distortWithAlg('chebyshev');
/**
* Turns a list of patterns into a single pattern which outputs list-values
From 447692106923167d3c0ddc308041bb79d4a944ca Mon Sep 17 00:00:00 2001
From: "Jade (Rose) Rowland"
Date: Sat, 10 Jan 2026 16:46:11 -0500
Subject: [PATCH 074/124] use releasenode
---
packages/superdough/superdough.mjs | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs
index dea314ea2..41b5ce976 100644
--- a/packages/superdough/superdough.mjs
+++ b/packages/superdough/superdough.mjs
@@ -419,7 +419,7 @@ class Chain {
return this;
}
releaseNodes() {
- this.audioNodes.forEach((n) => (isPoolable(n) ? releaseNodeToPool(n) : n?.disconnect()));
+ this.audioNodes.forEach((n) => (isPoolable(n) ? releaseNodeToPool(n) : releaseAudioNode(n)));
this.audioNodes = [];
this.tails = [];
}
@@ -536,10 +536,17 @@ export const superdough = async (value, t, hapDuration, cps = 0.5, cycle = 0.5)
nodes.main['source'] = [sourceNode];
} else if (getSound(s)) {
const { onTrigger } = getSound(s);
- const onEnded = () => {
- chain.releaseNodes();
- activeSoundSources.delete(chainID);
- };
+
+ const onEnded = () =>
+ webAudioTimeout(
+ ac,
+ () => {
+ chain.releaseNodes();
+ activeSoundSources.delete(chainID);
+ },
+ 0,
+ endWithRelease,
+ );
const soundHandle = await onTrigger(t, value, onEnded, cps);
From 741ff3f3f0117298b5c665869979d4144a706984 Mon Sep 17 00:00:00 2001
From: "Jade (Rose) Rowland"
Date: Sat, 10 Jan 2026 16:55:53 -0500
Subject: [PATCH 075/124] fix import
---
packages/superdough/superdough.mjs | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/packages/superdough/superdough.mjs b/packages/superdough/superdough.mjs
index 41b5ce976..d2baa9398 100644
--- a/packages/superdough/superdough.mjs
+++ b/packages/superdough/superdough.mjs
@@ -10,7 +10,17 @@ import './vowel.mjs';
import { clamp, nanFallback, _mod, cycleToSeconds, pickAndRename } from './util.mjs';
import workletsUrl from './worklets.mjs?audioworklet';
import { getNodeFromPool, isPoolable, releaseNodeToPool } from './nodePools.mjs';
-import { createFilter, effectSend, gainNode, getCompressor, getDistortion, getLfo, getWorklet } from './helpers.mjs';
+import {
+ createFilter,
+ effectSend,
+ gainNode,
+ getCompressor,
+ getDistortion,
+ getLfo,
+ getWorklet,
+ releaseAudioNode,
+ webAudioTimeout,
+} from './helpers.mjs';
import { map } from 'nanostores';
import { logger } from './logger.mjs';
import { connectLFO, connectEnvelope, connectBusModulator } from './modulators.mjs';
From 0571a8dc7d706f2fbd2647668b8acba18625ece0 Mon Sep 17 00:00:00 2001
From: gueejla
Date: Sat, 10 Jan 2026 22:11:13 -0600
Subject: [PATCH 076/124] fixes Serial onTrigger() params #1633
---
packages/serial/serial.mjs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/serial/serial.mjs b/packages/serial/serial.mjs
index 692109522..e007b24b9 100644
--- a/packages/serial/serial.mjs
+++ b/packages/serial/serial.mjs
@@ -68,7 +68,7 @@ Pattern.prototype.serial = function (br = 115200, sendcrc = false, singlecharids
if (!(name in writeMessagers)) {
getWriter(name, br);
}
- const onTrigger = (t_deprecate, hap, currentTime, cps, targetTime) => {
+ const onTrigger = (hap, currentTime, _cps, targetTime) => {
var message = '';
var chk = 0;
if (typeof hap.value === 'object') {
From 604a1b770cab5f55d6cada4915bccff4de460435 Mon Sep 17 00:00:00 2001
From: "Jade (Rose) Rowland"
Date: Sun, 11 Jan 2026 00:27:07 -0500
Subject: [PATCH 077/124] dialog
---
.../panel/ImportPrebakeScriptButton.jsx | 15 +++++++-
.../src/repl/components/panel/SettingsTab.jsx | 36 ++++++-------------
website/src/repl/util.mjs | 16 +++++++--
3 files changed, 39 insertions(+), 28 deletions(-)
diff --git a/website/src/repl/components/panel/ImportPrebakeScriptButton.jsx b/website/src/repl/components/panel/ImportPrebakeScriptButton.jsx
index c997f6b6e..64ce198be 100644
--- a/website/src/repl/components/panel/ImportPrebakeScriptButton.jsx
+++ b/website/src/repl/components/panel/ImportPrebakeScriptButton.jsx
@@ -1,6 +1,7 @@
import { errorLogger } from '@strudel/core';
import { useSettings, storePrebakeScript } from '../../../settings.mjs';
import { SpecialActionInput } from '../button/action-button';
+import { confirmDialog, SETTING_CHANGE_RELOAD_MSG } from '@src/repl/util.mjs';
async function importScript(script) {
const reader = new FileReader();
@@ -23,7 +24,19 @@ export function ImportPrebakeScriptButton() {
type="file"
label="import prebake script"
accept=".strudel"
- onChange={(e) => importScript(e.target.files[0])}
+ onChange={async (e) => {
+ const file = e.target.files[0];
+ const confirmed = await confirmDialog(SETTING_CHANGE_RELOAD_MSG);
+ if (!confirmed) {
+ return;
+ }
+ try {
+ await importScript(file);
+ window.location.reload();
+ } catch (e) {
+ errorLogger(e);
+ }
+ }}
/>
);
}
diff --git a/website/src/repl/components/panel/SettingsTab.jsx b/website/src/repl/components/panel/SettingsTab.jsx
index f46fa661c..7f488c544 100644
--- a/website/src/repl/components/panel/SettingsTab.jsx
+++ b/website/src/repl/components/panel/SettingsTab.jsx
@@ -1,13 +1,13 @@
import { defaultSettings, settingsMap, useSettings } from '../../../settings.mjs';
import { themes } from '@strudel/codemirror';
import { Textbox } from '../textbox/Textbox.jsx';
-import { isUdels } from '../../util.mjs';
+import { confirmAndReloadPage, isUdels } from '../../util.mjs';
import { ButtonGroup } from './Forms.jsx';
import { AudioDeviceSelector } from './AudioDeviceSelector.jsx';
import { AudioEngineTargetSelector } from './AudioEngineTargetSelector.jsx';
import { confirmDialog } from '../../util.mjs';
import { DEFAULT_MAX_POLYPHONY, setMaxPolyphony, setMultiChannelOrbits } from '@strudel/webaudio';
-import { ActionButton, SpecialActionButton } from '../button/action-button.jsx';
+import { SpecialActionButton } from '../button/action-button.jsx';
import { ImportPrebakeScriptButton } from './ImportPrebakeScriptButton.jsx';
function Checkbox({ label, value, onChange, disabled = false }) {
@@ -86,8 +86,6 @@ const fontFamilyOptions = {
galactico: 'galactico',
};
-const RELOAD_MSG = 'Changing this setting requires the window to reload itself. OK?';
-
export function SettingsTab({ started }) {
const {
theme,
@@ -127,11 +125,8 @@ export function SettingsTab({ started }) {
isDisabled={started}
audioDeviceName={audioDeviceName}
onChange={(audioDeviceName) => {
- confirmDialog(RELOAD_MSG).then((r) => {
- if (r == true) {
- settingsMap.setKey('audioDeviceName', audioDeviceName);
- return window.location.reload();
- }
+ confirmAndReloadPage(() => {
+ settingsMap.setKey('audioDeviceName', audioDeviceName);
});
}}
/>
@@ -141,11 +136,8 @@ export function SettingsTab({ started }) {
{
- confirmDialog(RELOAD_MSG).then((r) => {
- if (r == true) {
- settingsMap.setKey('audioEngineTarget', target);
- return window.location.reload();
- }
+ confirmAndReloadPage(() => {
+ settingsMap.setKey('audioEngineTarget', target);
});
}}
/>
@@ -175,12 +167,9 @@ export function SettingsTab({ started }) {
label="Multi Channel Orbits"
onChange={(cbEvent) => {
const val = cbEvent.target.checked;
- confirmDialog(RELOAD_MSG).then((r) => {
- if (r == true) {
- settingsMap.setKey('multiChannelOrbits', val);
- setMultiChannelOrbits(val);
- return window.location.reload();
- }
+ confirmAndReloadPage(() => {
+ settingsMap.setKey('multiChannelOrbits', val);
+ setMultiChannelOrbits(val);
});
}}
value={multiChannelOrbits}
@@ -297,11 +286,8 @@ export function SettingsTab({ started }) {
label="Sync across Browser Tabs / Windows"
onChange={(cbEvent) => {
const newVal = cbEvent.target.checked;
- confirmDialog(RELOAD_MSG).then((r) => {
- if (r) {
- settingsMap.setKey('isSyncEnabled', newVal);
- window.location.reload();
- }
+ confirmAndReloadPage(() => {
+ settingsMap.setKey('isSyncEnabled', newVal);
});
}}
disabled={shouldAlwaysSync}
diff --git a/website/src/repl/util.mjs b/website/src/repl/util.mjs
index 4a7cb26a8..06dad2467 100644
--- a/website/src/repl/util.mjs
+++ b/website/src/repl/util.mjs
@@ -1,4 +1,4 @@
-import { code2hash, evalScope, hash2code, logger } from '@strudel/core';
+import { code2hash, errorLogger, evalScope, hash2code, logger } from '@strudel/core';
import { settingPatterns } from '../settings.mjs';
import { setVersionDefaults } from '@strudel/webaudio';
import { getMetadata } from '../metadata_parser';
@@ -107,7 +107,19 @@ export function confirmDialog(msg) {
resolve(confirmed);
});
}
-
+export const SETTING_CHANGE_RELOAD_MSG = 'Changing this setting requires the window to reload itself. OK?';
+export function confirmAndReloadPage(onSuccess) {
+ confirmDialog(SETTING_CHANGE_RELOAD_MSG).then((r) => {
+ if (r == true) {
+ try {
+ onSuccess();
+ return window.location.reload();
+ } catch (e) {
+ errorLogger(e);
+ }
+ }
+ });
+}
//RIP due to SPAM
// let lastShared;
// export async function shareCode(codeToShare) {
From 0174e086399ae0411e7f6da31cc3fd2bf8df0840 Mon Sep 17 00:00:00 2001
From: Felix Roos
Date: Sun, 11 Jan 2026 10:50:44 +0100
Subject: [PATCH 078/124] fix: add trem to top level
---
packages/core/controls.mjs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/core/controls.mjs b/packages/core/controls.mjs
index 8fef91294..f15b3d4cd 100644
--- a/packages/core/controls.mjs
+++ b/packages/core/controls.mjs
@@ -877,7 +877,7 @@ export const { coarse } = registerControl('coarse');
* note("d d d# d".fast(4)).s("supersaw").tremolo("<3 2 100> ").tremoloskew("<.5>")
*
*/
-export const { tremolo } = registerControl(['tremolo', 'tremolodepth', 'tremoloskew', 'tremolophase'], 'trem');
+export const { tremolo, trem } = registerControl(['tremolo', 'tremolodepth', 'tremoloskew', 'tremolophase'], 'trem');
/**
* Modulate the amplitude of a sound with a continuous waveform
From c74707e804f926ffc3910a3e80aa8bda8e86d5a4 Mon Sep 17 00:00:00 2001
From: Felix Roos
Date: Sun, 11 Jan 2026 10:58:13 +0100
Subject: [PATCH 079/124] fix: export start cycle min 0
---
website/src/repl/components/panel/ExportTab.jsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/website/src/repl/components/panel/ExportTab.jsx b/website/src/repl/components/panel/ExportTab.jsx
index 9671ff1a3..cbb132e44 100644
--- a/website/src/repl/components/panel/ExportTab.jsx
+++ b/website/src/repl/components/panel/ExportTab.jsx
@@ -66,7 +66,7 @@ export default function ExportTab(Props) {
{
let v = parseInt(e.target.value);
From 8f3dc8daea3759330f4a7bd930a42d5653d500a1 Mon Sep 17 00:00:00 2001
From: yaxu
Date: Sun, 11 Jan 2026 11:34:55 +0100
Subject: [PATCH 080/124] Update website/src/pages/learn/faq.mdx
---
website/src/pages/learn/faq.mdx | 35 ++++++++++++++++-----------------
1 file changed, 17 insertions(+), 18 deletions(-)
diff --git a/website/src/pages/learn/faq.mdx b/website/src/pages/learn/faq.mdx
index b91b48cca..7fbc0d572 100644
--- a/website/src/pages/learn/faq.mdx
+++ b/website/src/pages/learn/faq.mdx
@@ -8,27 +8,26 @@ import { JsDoc } from '../../docs/JsDoc';
# Frequently Asked Questions
-This page contains frequently asked questions. Usually, the topic is explained in more detail in a section which is linked in the answer. This page's aim is to give an overview over topics which are important to the users of strudel.
+This page contains frequently asked questions, with answers. Usually, the topic is explained in more detail in a section which is linked in the answer.
## Is Strudel/Tidal free?
-Yes - there is no charge, this is a collective open source project, and the music you make with it is your own.
+Yes - there is no charge, this is a collective open source project, and the music you make with it is your own. However if you can, please make a one-off or regular donation to our [opencollective fund](https://opencollective.com/tidalcycles), that supports the software and cultural development of Strudel and other Uzu languages.
-However there are some caveats - the source code must stay free, i.e. you cannot distribute strudel or tidal as part of projects with incompatible licenses - see the [license](https://www.gnu.org/licenses/agpl-3.0.en.html) for details. The contributed examples and tracks are also separately licensed, and must not e.g. be used to train AI models without permission.
+While there is no charge there are some caveats, e.g.:
+
+* the source code must stay free, i.e. you cannot distribute strudel or tidal as part of projects with incompatible licenses - see the [license](https://www.gnu.org/licenses/agpl-3.0.en.html) for details.
+* the contributed examples and tracks are also separately licensed, and must not e.g. be used to train AI models without permission.
## How to record or export audio?
-There are multiple ways to record the audio -- and video -- output of Strudel:
+Strudel is not a digital audio workstation and does not operate following the same principles shared by most traditional audio softwares. However, there are multiple ways to record the audio -- and video -- output of Strudel:
- - capture the raw stereo signal coming out of your web browser.
-
- - use the alternative SuperDirt audio engine. Read [this page](/learn/input-output/#oscsuperdirtstrudeldirt) to know more about it.
-
- - capture the audio/video stream using a capture tool such as [OBS]().
-
- - don't record anything and code it again in front of your friends.
-
-You will need an external audio editor/DAW such as Reaper/Audacity/Ardour, etc. Strudel itself does not have functionality for exporting stems / individual tracks to an audio or midi file. Strudel is not a digital audio workstation and does not operate following the same principles shared by most traditional audio softwares.
+* Use the 'export' tab to render and download as an audio file.
+* capture the raw stereo signal coming out of your web browser. You will need an external audio editor/DAW such as Reaper/Audacity/Ardour, etc.
+* use the alternative SuperDirt audio engine. Read [this page](/learn/input-output/#oscsuperdirtstrudeldirt) to know more about it.
+* capture the audio/video stream using a capture tool such as [OBS](), which is designed for live streaming, but also works very well for recording.
+* don't record anything and code it again in front of your friends.
## Can I use strudel with my IDE?
@@ -37,13 +36,13 @@ Yes you can. There are experimental modes, made by community members, for severa
- VS Code: [Strudel VS](https://marketplace.visualstudio.com/items?itemName=cmillsdev.strudelvs): an experimental mode for Microsoft VSCode. A revived version of [TidalStrudel](https://marketplace.visualstudio.com/items?itemName=roipoussiere.tidal-strudel), which is defunct.
- nvim: [strudel.nvim](https://github.com/gruvw/strudel.nvim)
-## How can I record samples?
+## How can I use my own samples?
-You can use your own samples with Strudel. There are multiple ways to load your sample collection. Some methods are good for quick experimentation, some others are good to share your audio collection with other musicians:
+There are multiple ways to load your sample collection. Some methods are good for quick experimentation, some others are good to share your audio collection with other musicians:
- - Import folders [from the interface](/learn/samples/#from-disk-via-import-sounds-folder)
- -
- - Host your sound library e.g. on github and [load them from an URL](/learn/samples/#loading-custom-samples)
+- Import folders [from the interface](/learn/samples/#from-disk-via-import-sounds-folder). These are stored locally in your web browser, and not uploaded.
+- Serve a folder of samples locally using the [strudel 'sampler' commandline tool](https://strudel.cc/learn/samples/#from-disk-via-strudelsampler). This can be most reliable method, but requires [nodejs](https://nodejs.org) to be installed.
+- Host your sound library online on the web and [load them from an URL](/learn/samples/#loading-custom-samples)
## Can I use Strudel with AI/LLM tools?
From 25dbfe4c7d38330892a2e8000eb75f8569b7dcfa Mon Sep 17 00:00:00 2001
From: Felix Roos
Date: Sun, 11 Jan 2026 11:43:04 +0100
Subject: [PATCH 081/124] fix: remove faulty default readme
---
website/README.md | 184 +---------------------------------------------
1 file changed, 1 insertion(+), 183 deletions(-)
diff --git a/website/README.md b/website/README.md
index 115d6d556..84bf732e1 100644
--- a/website/README.md
+++ b/website/README.md
@@ -3,186 +3,4 @@
This is the website for Strudel, deployed at [strudel.cc](https://strudel.cc).
It includes the REPL live coding editor and the documentation site.
-## Run locally
-
-```bash
-# from project root
-npm run setup
-npm run repl
-```
-
-## Build
-
-```bash
-cd website
-npm run build # <- builds repl + tutorial to ../docs
-npm run preview # <- test static build
-```
-
-## Generate PWA icons
-
-```sh
-cd website/public
-npx pwa-asset-generator icon.png icons
-```
-
-# Standard Readme of Astro Starter Kit: Docs Site
-
-```bash
-npm create astro@latest -- --template docs
-```
-
-[](https://stackblitz.com/github/withastro/astro/tree/latest/examples/docs)
-[](https://codesandbox.io/s/github/withastro/astro/tree/latest/examples/docs)
-
-
-
-
-## Features
-
-- ✅ **Full Markdown support**
-- ✅ **Responsive mobile-friendly design**
-- ✅ **Sidebar navigation**
-- ✅ **Search (powered by Algolia)**
-- ✅ **Multi-language i18n**
-- ✅ **Automatic table of contents**
-- ✅ **Automatic list of contributors**
-- ✅ (and, best of all) **dark mode**
-
-## Commands Cheatsheet
-
-All commands are run from the root of the project, from a terminal:
-
-| Command | Action |
-| :--------------------- | :----------------------------------------------- |
-| `npm install` | Installs dependencies |
-| `npm run dev` | Starts local dev server at `localhost:4321` |
-| `npm run build` | Build your production site to `./dist/` |
-| `npm run preview` | Preview your build locally, before deploying |
-| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
-| `npm run astro --help` | Get help using the Astro CLI |
-
-To deploy your site to production, check out our [Deploy an Astro Website](https://docs.astro.build/guides/deploy) guide.
-
-## New to Astro?
-
-Welcome! Check out [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).
-
-## Customize This Theme
-
-edit: removed, as css styles have been replaced with tailwind styles
-
-### Site metadata
-
-`src/config.ts` contains several data objects that describe metadata about your site like title, description, default language, and Open Graph details. You can customize these to match your project.
-
-## Page metadata
-
-Astro uses frontmatter in Markdown pages to choose layouts and pass properties to those layouts. If you are using the default layout, you can customize the page in many different ways to optimize SEO and other things. For example, you can use the `title` and `description` properties to set the document title, meta title, meta description, and Open Graph description.
-
-```markdown
----
-title: Example title
-description: Really cool docs example that uses Astro
-layout: ../../layouts/MainLayout.astro
----
-
-# Page content...
-```
-
-For more SEO related properties, look at `src/components/HeadSEO.astro`
-
-### Sidebar navigation
-
-The sidebar navigation is controlled by the `SIDEBAR` variable in your `src/config.ts` file. You can customize the sidebar by modifying this object. A default, starter navigation has already been created for you.
-
-```ts
-export const SIDEBAR = {
- en: [
- { text: "Section Header", header: true },
- { text: "Introduction", link: "en/introduction" },
- { text: "Page 2", link: "en/page-2" },
- { text: "Page 3", link: "en/page-3" },
-
- { text: "Another Section", header: true },
- { text: "Page 4", link: "en/page-4" },
- ],
-};
-```
-
-Note the top-level `en` key: This is needed for multi-language support. You can change it to whatever language you'd like, or add new languages as you go. More details on this below.
-
-### Multiple Languages support
-
-The Astro docs template supports multiple languages out of the box. The default theme only shows `en` documentation, but you can enable multi-language support features by adding a second language to your project.
-
-To add a new language to your project, you'll want to extend the current `src/pages/[lang]/...` layout:
-
-```diff
- 📂 src/pages
- ┣ 📂 en
- ┃ ┣ 📜 page-1.md
- ┃ ┣ 📜 page-2.md
- ┃ ┣ 📜 page-3.astro
-+ ┣ 📂 es
-+ ┃ ┣ 📜 page-1.md
-+ ┃ ┣ 📜 page-2.md
-+ ┃ ┣ 📜 page-3.astro
-```
-
-You'll also need to add the new language name to the `KNOWN_LANGUAGES` map in your `src/config.ts` file. This will enable your new language switcher in the site header.
-
-```diff
-// src/config.ts
-export const KNOWN_LANGUAGES = {
- English: 'en',
-+ Spanish: 'es',
-};
-```
-
-Last step: you'll need to add a new entry to your sidebar, to create the table of contents for that language. While duplicating every page might not sound ideal to everyone, this extra control allows you to create entirely custom content for every language.
-
-> Make sure the sidebar `link` value points to the correct language!
-
-```diff
-// src/config.ts
-export const SIDEBAR = {
- en: [
- { text: 'Section Header', header: true, },
- { text: 'Introduction', link: 'en/introduction' },
- // ...
- ],
-+ es: [
-+ { text: 'Encabezado de sección', header: true, },
-+ { text: 'Introducción', link: 'es/introduction' },
-+ // ...
-+ ],
-};
-
-// ...
-```
-
-If you plan to use Spanish as the default language, you just need to modify the redirect path in `src/pages/index.astro`:
-
-```diff
-
-```
-
-You can also remove the above script and write a landing page in Spanish instead.
-
-### What if I don't plan to support multiple languages?
-
-That's totally fine! Not all projects need (or can support) multiple languages. You can continue to use this theme without ever adding a second language.
-
-If that single language is not English, you can just replace `en` in directory layouts and configurations with the preferred language.
-
-### Search (Powered by Algolia)
-
-[Algolia](https://www.algolia.com/) offers a free service to qualified open source projects called [DocSearch](https://docsearch.algolia.com/). If you are accepted to the DocSearch program, provide your API Key & index name in `src/config.ts` and a search box will automatically appear in your site header.
-
-Note that Aglolia and Astro are not affiliated. We have no say over acceptance to the DocSearch program.
-
-If you'd prefer to remove Algolia's search and replace it with your own, check out the `src/components/Header.astro` component to see where the component is added.
+more setup info, see [project setup](../CONTRIBUTING.md#project-setup)
\ No newline at end of file
From f3e6f868577a0f3e3ed50c97c9022a5972ac17e3 Mon Sep 17 00:00:00 2001
From: yaxu
Date: Sun, 11 Jan 2026 11:55:40 +0100
Subject: [PATCH 082/124] Update website/src/pages/learn/faq.mdx
Trimmed all the DAW talk a little!
---
website/src/pages/learn/faq.mdx | 61 +++++++++++++++++++--------------
1 file changed, 35 insertions(+), 26 deletions(-)
diff --git a/website/src/pages/learn/faq.mdx b/website/src/pages/learn/faq.mdx
index 7fbc0d572..f8ebcb0fb 100644
--- a/website/src/pages/learn/faq.mdx
+++ b/website/src/pages/learn/faq.mdx
@@ -46,21 +46,34 @@ There are multiple ways to load your sample collection. Some methods are good fo
## Can I use Strudel with AI/LLM tools?
-You are free to do what you like with Strudel, within the terms of the free/open source AGPLv3 license. However as a community we are interested in exploring human creativity. AI is _way_ over-hyped right now, including by people with very shady motives. Many in the community are very wary of people training models on their tunes that they've poured their love into. So please keep discussion and questions around AI and LLMs to channels dedicated to the topic and be fully respectful of other people's work.
+You are free to do what you like with Strudel, within the terms of the free/open source AGPLv3 license.
+However as a community we are interested in exploring human creativity. AI is _way_ over-hyped right now,
+including by people with very shady motives. Many in the community are very wary of people training models
+on their tunes that they've poured their love into. So please keep discussion and questions around AI and
+LLMs to channels dedicated to the topic and be fully respectful of other people's work.
-Furthermore, tools like ChatGPT generally give wrong answers. Please don't ask the community to fix those answers for you, as generally they will be timewasting nonsense.
+Furthermore, tools like ChatGPT generally give wrong answers. Please don't ask the community to fix those
+answers for you, as generally they will be timewasting nonsense.
-Human questions only!
+Human questions are always welcome!
+
+## Where can I download loads of patterns to train my LLM?
+
+You cannot, as there is no such place. For details regarding our stance towards AI/LLM, see [above](/learn/faq/#can-i-use-strudel-with-aillm-tools)
## How to run offline?
-Strudel works offline just fine! There are multiple techniques to run it yourself, see [this explanation](learn/pwa/#using-strudel-offline).
+Strudel works offline just fine! There are multiple techniques for this, see [this explanation](learn/pwa/#using-strudel-offline).
## How to change tempo? How do I translate BPM to cpm?
-If you have your tempo in beats per minute and use 4 beats per cycle (e.g. if your track is in 4/4ths) then you can do `setcpm(BPM/4)` where BPM is your beats per minute.
+Strudel works in cycles, rather than beats, but if you assume a certain number of beats per cycle, you can convert between them.
-If you have a different number of beats per bar or are using more or less beats per cycle (e.g. If you want to put only half a bar or two bars into one cycle), adjust accordingly.
+For example, if you have your tempo in beats per minute and use 4 beats per cycle (e.g. if your track is in 4/4ths) then you can do `setcpm(BPM/4)`
+where BPM is your beats per minute.
+
+If you have a different number of beats per bar or are using more or less beats per cycle (e.g. If you want to put only half a bar or
+two bars into one cycle), adjust accordingly.
## Where can I see all the functions?
@@ -72,11 +85,17 @@ If you pop open the sidetab of strudel.cc (small white < on the right hand side)
## How do I use this exactly like a DAW?
-Short answer: you don't.
+Strudel has different design aims for a DAW, and so treating it like one will likely be frustrating. DAWs are geared towards
+sequencing notes over time in predictable ways, whereas Strudel and similar Uzu languages are geared towards combining and
+transforming patterns in ways that can be hard to predict.
-Long answer: you can use Strudel to work along your creative work in a DAW. There are many ways to do so.
+If you want to emulate the functionality of a DAW in Strudel, you'll have to identify the operations
+executed by the DAW (sequencing, repeating, applying filters and envelopes) and write code that is equivalent to these
+operations. For example in Strudel, the 'arrange' and 'pick' methods are useful for sequencing patterns over time (see question on these later in this document).
-If you want to emulate the functionality of a DAW in a live coding language, you'll have to identify the operations executed by the DAW (sequencing, repeating, applying filters and envelopes) and write code that is equivalent to these operations. You might then find that the typical DAW workflow is not really adapted to live coding (because, despite both being ways of making music on the computer, they are two very different tools) and adapt your way of proceeding to the medium of code. This might mean leaving more place to serendipity and writing code that you don't predict the output of.
+You might still find that the typical DAW workflow is not really adapted to live coding because, despite
+both being ways of making music on the computer, they are two very different tools. You could then adapt your way of proceeding
+to the medium of code, which might mean leaving more place to serendipity and writing code that you don't predict the output of.
## Why doesn't everyone just use a DAW?
@@ -84,39 +103,29 @@ There is no easy answer to this question. Here are some thoughts:
- Live coding tools such as Strudel are excellent for improvising music and visuals using a computer. DAWs are valuable and robust companions for other activities such as producing, mastering and mixing audio, among other usages. Using a tool does not exclude from using any another tool, just build a toolbox.
-- Live coding has been practiced for quite some time as a performative activity. Artists like to show their screens while playing in front of an audience. It is an essential part of what they do, of the way they share their activity with everybody.
+- Live coding has developed over decades as a distinct creative practice. For example, live coding artists like to show their screens while playing in front of an audience. It is an essential part of what they do, of the way they share their activity with everybody.
-- Code is a human language, it is made for other humans to read it. You can read the code and enjoy the music too. It has meaning, value, and there might even be something poetic/important about it! - Strudel is free and open source, you can inspect the code, reshape it, contribute to it if you can/want. It is not opaque and this matters for many people. There is no black box, no obscure abstractions, no business model or hidden features. We need open tools in the arts! - Live coders don't shy away from using DAWs. They use them all of the time, especially when it makes their life easier for... live coding!
+- Code is a human language, it is made for other humans to read it. You can read the code and enjoy the music too. It has meaning, value, and there might even be something poetic/important about it! - Strudel is free and open source, you can inspect the code, reshape it, contribute to it if you can/want. It is not opaque and this matters for many people. There is no black box, no obscure abstractions, no business model, no user tracking or hidden features. We need open tools in the arts! - Live coders don't all shy away from using DAWs. Many use them all of the time, especially when it makes their life easier for... live coding!
- Code is an artistic material like any other. There is something valuable in the process of making music through code. More generally speaking, it is nice to tackle creative problems through the use of a programming language: creative thinking, building up your own solutions, DIY approach to music-making, unexpected outcome of algorithms, funny human errors, etc.
- There are pianos and trumpets in your DAW: why do people continue playing the piano or the trumpet? Think of live coding tools as instruments that you activate through the act of programming.
-## Is it more efficient to use Strudel than a DAW?
-
-Strudel was not build to be a DAW, yet it can still be used to make covers, arrange tracks, or prepare patterns for jamming. When playing concerts or jamming, some livecoders prepare their code, some perform from scratch.
-
-It might be interesting for you to check out for yourself how strudel can be used to express yourself creatively. Also you are free to combine a language like Strudel with a DAW.
-
## How can I interface Strudel with my favorite music software? What can I do with it?
Strudel can send [MIDI and OSC](/learn/input-output/), which are protocols for communicating musical information.
-Another music software (or hardware!) can then listen to these messages and process them according to its capabilities.
+Other music software (or hardware!) can then listen to these messages and process them according to its capabilities.
-A simple example would be to send livecoded audio to Ableton on different tracks and then use it to mix them.
+A simple example would be to send livecoded audio to a DAW like Ardour on different tracks and then use it to mix them.
You could also send the MIDI of a sequenced pattern to Musescore and then have it transcribe your livecoded work as a musical score.
-You could also send MIDI to your hardware synths because you think they sound better than the software synths built-in Strudel.
+You could also send MIDI to your hardware synths, if you like their sound.
-## How do I use this in my closed source webgame?
+## How do I use this in my closed source webgame or other software?
-You don't. You would need to re-license your game to AGPLv3 to fulfill the license Strudel is distributed under.
-
-## Where can I download loads of patterns to train my LLM?
-
-You cannot, as there is no such place. For details regarding our stance towards AI/LLM, see [above](/learn/faq/#can-i-use-strudel-with-aillm-tools)
+You don't. You need to license your game to a free/open source license fulfill the [AGPLv3 license](https://codeberg.org/uzu/strudel/src/branch/main/LICENSE) Strudel is distributed under.
## How to play different patterns simultaneously?
From 85fd567fb2e2ac40e1aac886af103dc83744201c Mon Sep 17 00:00:00 2001
From: yaxu
Date: Sun, 11 Jan 2026 12:21:05 +0100
Subject: [PATCH 083/124] Format and remove link to open document
---
website/src/pages/learn/faq.mdx | 46 ++++++++++++++-------------------
1 file changed, 20 insertions(+), 26 deletions(-)
diff --git a/website/src/pages/learn/faq.mdx b/website/src/pages/learn/faq.mdx
index f8ebcb0fb..e43839dc3 100644
--- a/website/src/pages/learn/faq.mdx
+++ b/website/src/pages/learn/faq.mdx
@@ -16,18 +16,18 @@ Yes - there is no charge, this is a collective open source project, and the musi
While there is no charge there are some caveats, e.g.:
-* the source code must stay free, i.e. you cannot distribute strudel or tidal as part of projects with incompatible licenses - see the [license](https://www.gnu.org/licenses/agpl-3.0.en.html) for details.
-* the contributed examples and tracks are also separately licensed, and must not e.g. be used to train AI models without permission.
+- the source code must stay free, i.e. you cannot distribute strudel or tidal as part of projects with incompatible licenses - see the [license](https://www.gnu.org/licenses/agpl-3.0.en.html) for details.
+- the contributed examples and tracks are also separately licensed, and must not e.g. be used to train AI models without permission.
## How to record or export audio?
Strudel is not a digital audio workstation and does not operate following the same principles shared by most traditional audio softwares. However, there are multiple ways to record the audio -- and video -- output of Strudel:
-* Use the 'export' tab to render and download as an audio file.
-* capture the raw stereo signal coming out of your web browser. You will need an external audio editor/DAW such as Reaper/Audacity/Ardour, etc.
-* use the alternative SuperDirt audio engine. Read [this page](/learn/input-output/#oscsuperdirtstrudeldirt) to know more about it.
-* capture the audio/video stream using a capture tool such as [OBS](), which is designed for live streaming, but also works very well for recording.
-* don't record anything and code it again in front of your friends.
+- Use the 'export' tab to render and download as an audio file.
+- capture the raw stereo signal coming out of your web browser. You will need an external audio editor/DAW such as Reaper/Audacity/Ardour, etc.
+- use the alternative SuperDirt audio engine. Read [this page](/learn/input-output/#oscsuperdirtstrudeldirt) to know more about it.
+- capture the audio/video stream using a capture tool such as [OBS](https://obsproject.com/fr), which is designed for live streaming, but also works very well for recording.
+- don't record anything and code it again in front of your friends.
## Can I use strudel with my IDE?
@@ -40,19 +40,19 @@ Yes you can. There are experimental modes, made by community members, for severa
There are multiple ways to load your sample collection. Some methods are good for quick experimentation, some others are good to share your audio collection with other musicians:
-- Import folders [from the interface](/learn/samples/#from-disk-via-import-sounds-folder). These are stored locally in your web browser, and not uploaded.
+- Import folders [from the interface](/learn/samples/#from-disk-via-import-sounds-folder). These are stored locally in your web browser, and not uploaded.
- Serve a folder of samples locally using the [strudel 'sampler' commandline tool](https://strudel.cc/learn/samples/#from-disk-via-strudelsampler). This can be most reliable method, but requires [nodejs](https://nodejs.org) to be installed.
- Host your sound library online on the web and [load them from an URL](/learn/samples/#loading-custom-samples)
## Can I use Strudel with AI/LLM tools?
-You are free to do what you like with Strudel, within the terms of the free/open source AGPLv3 license.
-However as a community we are interested in exploring human creativity. AI is _way_ over-hyped right now,
-including by people with very shady motives. Many in the community are very wary of people training models
-on their tunes that they've poured their love into. So please keep discussion and questions around AI and
+You are free to do what you like with Strudel, within the terms of the free/open source AGPLv3 license.
+However as a community we are interested in exploring human creativity. AI is _way_ over-hyped right now,
+including by people with very shady motives. Many in the community are very wary of people training models
+on their tunes that they've poured their love into. So please keep discussion and questions around AI and
LLMs to channels dedicated to the topic and be fully respectful of other people's work.
-Furthermore, tools like ChatGPT generally give wrong answers. Please don't ask the community to fix those
+Furthermore, tools like ChatGPT generally give wrong answers. Please don't ask the community to fix those
answers for you, as generally they will be timewasting nonsense.
Human questions are always welcome!
@@ -69,7 +69,7 @@ Strudel works offline just fine! There are multiple techniques for this, see [th
Strudel works in cycles, rather than beats, but if you assume a certain number of beats per cycle, you can convert between them.
-For example, if you have your tempo in beats per minute and use 4 beats per cycle (e.g. if your track is in 4/4ths) then you can do `setcpm(BPM/4)`
+For example, if you have your tempo in beats per minute and use 4 beats per cycle (e.g. if your track is in 4/4ths) then you can do `setcpm(BPM/4)`
where BPM is your beats per minute.
If you have a different number of beats per bar or are using more or less beats per cycle (e.g. If you want to put only half a bar or
@@ -85,16 +85,16 @@ If you pop open the sidetab of strudel.cc (small white < on the right hand side)
## How do I use this exactly like a DAW?
-Strudel has different design aims for a DAW, and so treating it like one will likely be frustrating. DAWs are geared towards
-sequencing notes over time in predictable ways, whereas Strudel and similar Uzu languages are geared towards combining and
+Strudel has different design aims for a DAW, and so treating it like one will likely be frustrating. DAWs are geared towards
+sequencing notes over time in predictable ways, whereas Strudel and similar Uzu languages are geared towards combining and
transforming patterns in ways that can be hard to predict.
-If you want to emulate the functionality of a DAW in Strudel, you'll have to identify the operations
-executed by the DAW (sequencing, repeating, applying filters and envelopes) and write code that is equivalent to these
+If you want to emulate the functionality of a DAW in Strudel, you'll have to identify the operations
+executed by the DAW (sequencing, repeating, applying filters and envelopes) and write code that is equivalent to these
operations. For example in Strudel, the 'arrange' and 'pick' methods are useful for sequencing patterns over time (see question on these later in this document).
-You might still find that the typical DAW workflow is not really adapted to live coding because, despite
-both being ways of making music on the computer, they are two very different tools. You could then adapt your way of proceeding
+You might still find that the typical DAW workflow is not really adapted to live coding because, despite
+both being ways of making music on the computer, they are two very different tools. You could then adapt your way of proceeding
to the medium of code, which might mean leaving more place to serendipity and writing code that you don't predict the output of.
## Why doesn't everyone just use a DAW?
@@ -329,9 +329,3 @@ s increase by one semitone, i.e. sharp, works for steps of scales, note names
$: at the start of a line, defines a member of the stack. is the only stack name that should occur multiple names
_ before a stack name: mutes the stack, i.e. hush(), for example _$: s("bd"), see above for a different usage.
```
-
-## Are there more FAQ items?
-
-These pages have been taken from [this pad](https://doc.patternclub.org/_CgofWouTciXXHexUP9AVg?both). Some of the items there have not been brushed up and brought here.
-
-These include the following items: 9, 11, 12 and 19
From 550d7ff6cb84fe3273256c2153cb869bc27d1263 Mon Sep 17 00:00:00 2001
From: Felix Roos
Date: Sun, 11 Jan 2026 12:32:54 +0100
Subject: [PATCH 084/124] fix: react error
---
website/src/repl/components/panel/Reference.jsx | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/website/src/repl/components/panel/Reference.jsx b/website/src/repl/components/panel/Reference.jsx
index 3053f03dc..34701036d 100644
--- a/website/src/repl/components/panel/Reference.jsx
+++ b/website/src/repl/components/panel/Reference.jsx
@@ -1,4 +1,4 @@
-import { useMemo, useState } from 'react';
+import { useMemo, useState, Fragment } from 'react';
import jsdocJson from '../../../../../doc.json';
import { Textbox } from '../textbox/Textbox';
@@ -109,9 +109,8 @@ export function Reference() {
From 9ffd0e496fcb71fcbc46add25eef7e40f56d4fb6 Mon Sep 17 00:00:00 2001
From: Felix Roos
Date: Sun, 11 Jan 2026 12:33:03 +0100
Subject: [PATCH 085/124] fix: all doc
---
packages/core/repl.mjs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/packages/core/repl.mjs b/packages/core/repl.mjs
index 047989f7f..9fe8eef81 100644
--- a/packages/core/repl.mjs
+++ b/packages/core/repl.mjs
@@ -120,7 +120,9 @@ export function repl({
// 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
+ let allTransforms = [];
+ /**
+ * 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")
@@ -135,7 +137,6 @@ export function repl({
*
* @tags combiners
*/
- let allTransforms = [];
const all = function (transform) {
allTransforms.push(transform);
return silence;
From a659c89385b84e08c001c47669fb98253ffb55f9 Mon Sep 17 00:00:00 2001
From: floy
Date: Sun, 11 Jan 2026 13:25:44 +0100
Subject: [PATCH 086/124] fix code formatting
---
website/src/repl/components/panel/SoundsTab.jsx | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/website/src/repl/components/panel/SoundsTab.jsx b/website/src/repl/components/panel/SoundsTab.jsx
index 2060c64a9..5a7df5ba9 100644
--- a/website/src/repl/components/panel/SoundsTab.jsx
+++ b/website/src/repl/components/panel/SoundsTab.jsx
@@ -210,10 +210,11 @@ export function SoundsTab() {
) : (
''
)}
- {!soundEntries.length && soundsFilter !== 'importSounds' ?
- search == '' ? 'No sounds loaded' : 'No sounds found'
- : ''
- }
+ {!soundEntries.length && soundsFilter !== 'importSounds'
+ ? search == ''
+ ? 'No sounds loaded'
+ : 'No sounds found'
+ : ''}