Bundles
A directory of nodes and the packages they import. Everything goofi ships is one, but two of them are the engines' own and the rest are optional packs.
node-bundles/eeg/
eeg_playback.py eeg_power_bands.py fooof.py lsl_in.py
requirements.txtEvery shipped bundle is built at goofi's build time and embedded, so cargo run carries them all without a flag. A type is namespaced by
the plane it runs on, as signal:Psd or audio:Osc, which is why two
bundles can both hold a node called Gain without either shadowing the other.
--extra-nodes adds a root outside the repo the same way. It is a folder of node
files, .py and .rs, scanned after the shipped bundles and before the
open patch's own workspace:
cargo run -- --extra-nodes ~/my-nodesA bundle with Python nodes names the packages they import in a requirements.txt. goofi-init installs every shipped bundle's
requirements, and at startup goofi checks every scanned root's against both interpreters. A terminal is asked before anything is installed, and without one the nodes
are unavailable: greyed in the palette and naming what is missing.
A library that installs a bundle by name is designed but unbuilt; it lives in the project's
backlog as roadmap/library.md, one file per unbuilt feature.
Core, and the rest
A bundle named after an engine is that engine's own node set: signal and audio today. Those are the core. They are Rust for the most
part, they carry no dependency you have to install, and every clone has them.
The others are packs: Python nodes for one domain, depending on packages
named in their requirements.txt. They ship too, but a node in one goes unavailable when its packages are missing, and says which. A core node always
works; a pack node works once its imports do.
| Bundle | Kind | Nodes | Written in |
|---|---|---|---|
audio | core | 14 | rust |
signal | core | 38 | python + rust |
complexity | pack | 9 | python |
eeg | pack | 3 | python |
node-bundles/audio core · 14 nodes
| Node | What it does |
|---|---|
Delay | An echo, one line per channel, at a delay that may move while it sounds. |
Env | An ADSR in [0, 1] over `gate`, one voice per channel of it. |
Feedback | Its input one block late: the one way a loop closes. It runs first each block, reading what its producer left in the last one. |
Filter | A resonant state-variable filter, low, band or high, at audio-rate cutoff. |
FreqShift | Every partial moved by the same number of hertz, which no interval survives. |
Gain | Its input times `gain`; the wires into `input` sum. |
Limiter | One gain across every channel, so nothing leaves above the ceiling and the picture holds. |
Mixdown | Many channels become few, each one placed across the field it lands in. |
Noise | Noise in [-1, 1], white or pink, on as many channels as are asked for. |
Osc | An oscillator in [-1, 1], one channel per channel of `pitch`. |
Quantize | A pitch in volts pulled to the nearest note of a scale. |
Reverb | A room around the sound: eight delay lines fed back through each other, out in stereo. |
SignalIn | The in-order crossing: a `[C, T]` signal frame with `sfreq` enters as `C` audio channels, resampled to the rate. A frame with no `sfreq` enters one sample per sample, so a control value is held until the next. |
Slew | Its input with a rate limit: a step becomes a ramp, a gate an envelope, a knob a glide. |
node-bundles/signal core · 38 nodes
| Node | What it does |
|---|---|
Buffer | Rolling window along one axis: keeps the most recent `size` entries, rank unchanged. |
Constant | A number, given a shape: the way a scalar becomes an array of the size a node downstream wants. |
Delay | The stream as it was a moment ago, counted in samples, seconds or updates. |
Eigen | The eigenvalues and eigenvectors of a square symmetric matrix, or of its Laplacian. |
Emd | Pull a frame apart into the oscillations it is made of, fastest first. |
Fft | The spectrum both ways: samples into one-sided bins, and those bins back into samples. |
Filter | Keep one band of the spectrum, run both ways so nothing comes out shifted in time. |
Format | Several strings become one, joined in order or placed into a template. |
FreqShift | Move a signal up or down the spectrum by a fixed number of hertz, without changing its speed. |
FromJson | The first object in a piece of text becomes a table. |
Function | One elementwise function over the frame, chosen by name. Shape and metadata are untouched. |
Hilbert | How big a signal's swing is, where in its cycle it stands, and how fast that is turning. |
Join | Lay several frames end to end along one axis, or stack them onto a new axis named after their senders. |
LFO | A low-frequency oscillator: one sample per update to modulate a param, or a block of samples to feed a signal. |
LslIn | Receive an LSL stream: [channels, samples] per tick, with its labels and rate. |
LslOut | Publish a frame as an LSL stream, with the labels and rate it arrived with. |
Math | Scale and shift every value, then map one range onto another. Shape and metadata are untouched. |
Meta | Write the sample rate or the channel names onto a frame, for a source that does not carry its own. |
MidiIn | Receive MIDI: the velocity of every held note, and the value of every controller. |
MidiOut | Send MIDI: note-on for a number that appears, note-off for one that goes. |
Noise | Uniform, normal or pink noise, one independent stream per channel. |
Normalize | Put a signal on a common scale, from statistics over a window of its own past. |
Operation | Combine several frames: arithmetic folded left with numpy broadcasting, a matrix product, or a correlation. |
OscIn | Receive OSC messages: one table entry per address, the latest value each. |
OscOut | Send a table as OSC messages, one address per entry. |
Psd | How much power sits at each frequency, in Hz, over the last axis. |
Reduce | Collapse one axis to a single value per position on the others: a mean, a spread, an extreme or a total. |
Resample | Change a signal's sample rate, filtering as it goes so nothing folds back. |
Reshape | Reorder the axes of a frame, then re-cut the entries into a new shape. |
Select | Keep part of one axis, named by label, by position, or by the coordinate range it carries. |
Smooth | Take the edge off a signal, as a running mean or as an exponential decay. |
Switch | Let one of several wires through, chosen by number, so a signal can pick the route. |
Table | Several wires become one table, each under a key. |
TableSelect | One field out of a table, on the output that matches what the field holds. |
Text | A string, which an expression can build out of anything else in the patch. |
Threshold | Turn a signal into a decision: one where it is past the level, zero where it is not. |
ToJson | A table becomes JSON text: an object, with arrays as lists and strings as strings. |
Wavelet | How a signal's frequencies come and go across the frame, which one spectrum cannot show. |
node-bundles/complexity pack · 9 nodes
| Node | What it does |
|---|---|
DetrendedFluctuation | DFA exponent: how far a signal remembers its own past. |
FractalDimension | Fractal dimension: how much the trace fills the plane, 1 (smooth) to 2 (filling). |
Hjorth | Hjorth mobility and complexity: mean frequency, and distance from a sine. |
LempelZiv | LZ76 complexity: how much a signal repeats itself. |
PermutationEntropy | Permutation entropy: disorder in the ORDER of neighbouring samples. |
SampleEntropy | Sample entropy: how rarely a pattern that recurred keeps recurring. |
SpectralEntropy | Spectral entropy: how flat the power spectrum is, tone to noise. |
SvdEntropy | SVD entropy: how many independent components the signal's history spans. |
ZeroCrossings | Zero crossings: how often the signal changes sign over the window. |
node-bundles/eeg pack · 3 nodes
| Node | What it does |
|---|---|
EegPlayback | Replay an EEG recording at its own rate, as if it were live. |
EegPowerBands | Band power per channel: delta to gamma, absolute or as a share of the whole spectrum. |
Fooof | FOOOF: the aperiodic 1/f slope and the peaks that rise above it. |
Your own
--extra-nodes is repeatable, and a later root wins a type name it shares with an
earlier one. A patch's own workspace is scanned last of all, so a patch can always override
what it was given.
This reference describes goofi 3.1.0(537cd394), generated from a running instance on 2026-09-06.