flowRS Open the IDE
Browser-native dataflow · emits Rust

Wire the system you are building.
Get Rust you can check.

flowRS is a dataflow environment that runs in your browser. You build a program as a graph of typed nodes, for signals and data, EEG and other biosignals, laboratory instruments, microcontroller firmware and the seams to ROS 2. It runs in the page while you draw it, it can become an app with its own controls, and it emits ordinary Rust you can compile, test and keep.

Runs in the page · nothing to install · Apache-2.0

block diagram
source gain clock filter.iir
generated Rust
let x = source.read()?;
let x = gain(x, 2.0);
let y = filter_iir(&x, &coeffs);
display.update(&y);
What it is for

One graph model, many kinds of work.

The same editor, the same typed wires and the same checks, whichever of these you came for. Each card counts the nodes the palette gives it, read from the registry when this page was built.

Signals and data

Filter, measure, learn

Read measurement files and live streams, filter and transform them, take spectra and statistics, and train small networks, all in the tab. Statistics run one implementation in the page and in the generated program, and the IIR filter family is held to SciPy's numbers by tests.

data 20dsp 24stats 21ml 15nodes

Design a filter →
Neuroscience

EEG and biosignals

Open EDF, BDF, WFDB, XDF and BrainVision recordings in the browser, where the file stays. Band power, notch filtering, epochs and evoked averages are held to MNE-Python by oracle tests, and a course walks through them on PhysioNet EEG.

For research, education and engineering development. Not a medical device. Not intended to diagnose, treat, cure, mitigate, prevent, screen for or monitor any disease or condition.

neuro 49nodes

Signals of the Brain →
Test and measurement

Instruments on the bench

Pick an instrument from the catalogue and set its parameters. The configuration is checked against the instrument's constraints and compiled to SCPI before anything is sent. When an agent wants to act on hardware it files a proposal, a person decides it in the Review level, and every decision is kept in a hash-chained audit log. Mock instruments let you try all of it with no bench attached.

instrument 6nodes

Compose an instrument program →
Embedded

Firmware and board twins

The Code view lowers a graph of embedded nodes (GPIO, PWM, timers, ADC, SPI, I2C, UART) to a no_std Embassy or RTIC application, and names any node it cannot lower. An RTIC build can run on a simulated STM32F4 and be compared, pin by pin, with the graph's run in the page. Twins of AVR, RP2040, ESP32 and STM32 boards run in the tab.

embedded 12nodes

From graph to firmware →
Robotics

The seams to ROS 2

Interfaces carry their units, clock domains and named axes. flowRS computes ROS 2's own type hash, tested against every interface in the ROS 2 Lyrical base image, and an identity of its own that also covers units and clocks, so a changed field or unit shows up where two sides connect. Sessions record as MCAP in ROS 2's message format.

ros 2nodes

Open the IDE →
Apps

Apps from graphs

The App view turns a graph's controls and readings into an app, drawn from one component library on the Instrument or the Paper skin. Share it as a link, run it on its own at /ide/#app, or export the project that builds it.

96components

Open the IDE →
How it works

The signal graph emits Rust you own.

Emission runs one way. The Rust is not parsed back into the signal graph. A second diagram, the visual syntax tree, is what round-trips source.

01

Design

Every port carries a type and its named axes, so the editor offers you the connections that make sense and explains the ones that do not. You design with the rules in view.

02

Run

The graph executes in the page while you are still drawing it, on real threads: the page is cross-origin isolated, so it gets shared memory and a thread pool.

03

Verify

The emitted source is ordinary Rust your own tests and compiler can judge, and the generated program and the page's run are compared where both can run.

Working with agents

An agent proposes. A compiler checks. You decide.

A typed graph is precise enough to hand to a model and structured enough to check afterwards.

Changes you review

Describe a change and the server's agent answers with a patch to your graph. The checker parses it, checks its types and structure, generates the Rust, compiles it, runs the tests and compares the page's run with the compiled program before you see it. Nothing is applied until you apply it.

A local model in the tab

Local AI runs a Llama or Qwen model on your GPU through WebLLM, loaded from this site's own pinned, checksummed mirror. It runs the same edit loop; the compile and the comparison it cannot do in a browser are reported as not run, never as passed.

Tools for other agents

flowrs-mcp speaks the Model Context Protocol, and the page offers its graph tools to in-browser agents through WebMCP. An action on hardware stays a proposal a person decides. How the AI features work →

Worth knowing

Details that keep it honest.

Statechart

A machine on the graph

flow.statechart keeps the state, takes the events, and emits Rust that runs the same chart the page executes. That generated program is not parsed back. A delay reads the elapsed wire. It does not sleep. A parallel state raises done on itself when every region is final. One region finishing does not. Assigned keys live on the data wire. A guard reads them. A transition can write one key before entry.

Syntax tree

Rust in, Rust out

A second diagram parses Rust you already have and emits it again. That visual syntax tree round-trips source. The signal graph does not.

TDMS

Measurement files open

flowRS reads interleaved numeric channels, DAQmx scalers, and string channels from measurement files. data.tdms puts one channel on a signal port, and the sample rate is a sibling port on that node, because a signal wire does not carry the rate. Interleaved channels come back as each channel's samples. DAQmx raw data, format-changing and digital-line scalers, comes back as the values those scalers select. String channels come back as their text.

Energy

Two energy numbers, kept apart

The page prices a graph with a per-node picojoule model: an order-of-magnitude estimate on a baseline substrate, computed in the page, and not a measurement. Host readings are separate, and native-only: flowrs-energy reads power counters on the machine running the host. The browser tab does not measure those joules.

Ownership

Ownership you can see

Move, borrow and mutable borrow are wire modes. Rust's clearest idea becomes something you point at, which is why it is a fine way to learn it.

Circuit

Firmware on a breadboard

Run firmware in the page: the circuit simulator executes STM32F4 firmware on a pure-Rust Cortex-M core in the tab, wired to LEDs, a button and an LCD.

In the box

Counted from the running registry.

These counts are read when this page is built. The editor's palette holds 322 widgets: 273 built into flowrs-core and 49 from the neuroscience libraries (flowrs-neuro, flowrs-neuroviz) it installs beside them. 0 widgets generate a seam: the emitted Rust compiles, then panics at unimplemented!. 16 are stand-ins: the program compiles and runs, but a deterministic substitute answers in place of the model or device the node is named after. 306 ship: no seam and no stand-in. Of the palette's 419 nodes (97 language primitives and 322 widgets), 412 run in the browser as you draw: 396 compute there what the exported Rust computes, and 16 of them are stand-ins. 7 run only in the exported program, and the palette marks each of those, with the reason, before it is dropped. The graph diagnostic names a seam before a run, and the editor badges a stand-in with the model or device it stands in for.

322
widgets
0
seams
16
stand-ins
306
shipping
412
run in the browser
7
export only
35
pillars

It runs in the tab you already have open.

Open the editor and start from the field you work in.