Visuals, Come A-live!
A tale of how two livecoders engineer integrations with livecoding tools (Hydra / Strudel) to make compatible with third-party applications (TouchDesigner) or HTML-canvas-based visualization tool.
Background & Introduction
Before we take you on a journey through how (and why) we wrote our own livecode integrations with visual tools, we want to briefly introduce ourselves here:
Waveflower [Gooi]
Gooi has been always fascinated by audio-visual presentations using sounds to make patterns. Last year, he took a deep dive learning about the interaction between harmonics, physics and mathematics. Through his research, he started drawing connections between them.
In an attempt to present his findings in a simple-to-understand format, he built the Waveflower App, a tool for visualizing harmonic intervals in the form of geometric patterns.
In addition, he composes his own music using a piano before transcribing into the livecode editor Strudel.cc for layering synths and other instruments. He makes use of his own visualization tools to produce live Algorave shows.
GRNCH [Woody Poulard]
GRNCH is an artist/musician whose practice centers on transforming algorithmic and generative processes into tangible artifacts through printing methods such as risograph and pen plotting. Working with mathematical systems and computational tools, he creates zines, prints, posters, and sculptural works alongside his work as an electronic music producer.
His visual work explores pattern, texture, and algorithmic beauty through the distinctive aesthetic of risograph printing and the precise line work of pen plotters. These physical mediums bridge the gap between computational art and printed matter, creating works that exist as tangible objects rather than screen-based images. His practice also extends to audio-reactive visual installations and projection mapping performances that merge sound and visual art in real-time.
Motivation
While this article is not meant to be written like a research paper, we should at least set some background context here. We need to start with why we want to do this:
1. Lack of seamless integration between popular apps
The gap between Hydra and TouchDesigner isn't really a technical problem; it's a problem of creative context. Hydra was built for liveness: the code is the performance. TouchDesigner was built for power: the system is the performance. Building a bridge between them meant asking whether those two things could coexist, and whether the answer was yes or no would shape what kind of artist I wanted to be.
Closing that gap matters beyond my own practice. There's a whole community of artists who came up through Hydra and hit its ceiling: resolution limits, no 3D, no hardware I/O, no data pipelines. But when they looked at TouchDesigner, the node based paradigm felt like a different language entirely. Not harder, just...other. The improvisational fluency they'd built in Hydra didn't transfer. Meanwhile, TD artists who wanted that text-first, performative energy had no real on-ramp into live coding without leaving their entire ecosystem behind.
2. A specific tool did not exist
I had this idea of visualizing periodic waveforms in polar coordinates, I thought it was a simple enough concept that this tool might exist somewhere:

But I was wrong — I tried searching for existing projects for a polar-transformed oscilloscope, but I could not find any. I found plenty of Lissajous implementations (like osci-render) — it makes cool 2D shapes from two signals, but it’s still not quite what I’m looking for. I am looking for a single polar transformed visualization.
I did look into Desmos, because well, a math tool that makes sine tones should give me a way to polar-transform these waveforms. But it was quite disappointing when I found out it’s not design to interpret audio signals at all.1
So I decided to build one from scratch.
3. Make Visual Sets More “Live”
TouchDesigner has become a decent tool to help artists design and produce live visual projections. This is especially true if those visuals were projected alongside a musical/DJ performance.
However, there’s a major drawback here we don’t normally talk about — unless the audio frequency bands and amplitudes are being analyzed to animate those visuals, they can feel a bit like “DVD” sets — in other words, preset visuals that somewhat synchronizes with the audio but essentially not “alive”.
The solution usually involves painstakingly animating individual sets of elements, such that they respond to a specific audio layer / track. However this is often quite a time-consuming process, and while you can achieve very impressive audio-visual sets as a result, it gives very little room for the audio artist to change or re-mix their audio on the fly (because then it may break the carefully-calibrated preset visuals).
Within the livecoding community, there is a desire to see audio + visual sets becoming more “live”. In other words, the output visual elements should react to code changes made in real-time, such that to create a more dynamic audio/visual experience, one that can not only become a living, breathing art form, but also allowing the artist to render or destroy them at will.
In fact, such tools like p5.js / p5live is not new — it not only allows instantaneous visual updates via livecode, but also allows multiple external inputs (such as midi or audio) to animate its visual parameters in real-time.
That being said, there hasn’t been one that can integrate seamlessly with a popular tool like TouchDesigner until now…
Designing Integration Points with Livecoding Tools
Hydra to TouchDesigner by Grnch
The idea came from a simple frustration: I wanted to use Hydra more in my practice, but I didn't want to deal with the overhead of recording its output or setting up a Syphon or Spout server just to pipe a live image somewhere else on screen. That felt like fighting the tool rather than using it.
What changed everything was realizing that TouchDesigner has a built-in Web Render TOP, an operator that can run full HTML pages inside the network. Hydra already exposes itself as an embedded HTML sketch; you can load it in a browser, point it at a canvas element, and it just runs. So the question became: what if that browser was inside TD?
That realization was the proof of concept. Getting Hydra running inside a Web Render TOP took surprisingly little effort once the mental model clicked. From there, the goal was straightforward: I wanted to write and edit Hydra code from inside TD the same way I would in the browser, no round-tripping, no screen capture, no intermediary.
But once the plumbing was in place, the integration started pulling me toward something more interesting. The real breakthrough was being able to pass TD data into Hydra code directly; things like sensor values, parameter outputs, noise signals. Suddenly Hydra sketches could respond to what was happening in the rest of the network. And going the other direction, Hydra parameters could be bound to TD controls, so you get this feedback loop where the two environments are genuinely talking to each other rather than one just feeding into the other.
That two-way connection is what made this feel worth building out properly.
JavaScript / HTML integrations by Waveflower Gooi
The <canvas> element
The idea of slapping on an HTML <canvas> object that is animated by the audio signal isn’t new. In the livecoding environment Strudel.cc, the inline _scope() function literally creates a new <canvas> element such that the audio signal waveform data can be drawn directly onto the HTML.
In fact, Canvas API is already part of the official Web API specifications. Which means that I just need to write some JavaScript code to interact with the canvas (there is no need to pick up a JS framework library).
And separating visuals between each audio “track” is made easy through the built-in “Pattern” structure in Strudel.cc.2
In addition, I get to control how each and every frame draws at 60 times per second. Which allows tremendous freedom and flexibility for designing visual presentations exactly how I envision it to be.
The User Experience
My very first UI/UX that I came up for this is just a blank HTML page with one <input type=”number”> on it — which lets you specify the frequency of the audio signal you want my JavaScript to generate.
After all, I’ve got to start small as I don’t want to think about the intricacies of livecode integration just yet:

Proof-of-concept
The initial <canvas> element could only draw still frames —
Because initially, I need proof that the JavaScript controlling the <canvas> must work seamlessly with the Web Audio API’s OscillatorNode.
At first I tested with sine-type oscillating signal, drawing it onto the <canvas>. Then I started experimenting with triangle and square wave signals, before a sawtooth wave:
image caption: polar visualization of oscillating signals of various types:
triangle (left); square (middle); sawtooth (right)
of the harmonic ratio 3:1
Indeed, the math was just a simple polar-to-cartesian transformation formula,
Where I can simply plug x and y values into the lineTo(x,y) function.3
~
Method of Integration
Grnch: Hydra re-write
The technical core of the integration comes down to one key property of Hydra: it can run inside an HTML page. When you load Hydra in a browser, you are loading an HTML file that imports the Hydra synth engine and executes your sketch code against a canvas element. That portability is what makes the whole integration possible.
TouchDesigner’s Web Render TOP renders an HTML file from disk. But the less obvious capability is that TD can also execute JavaScript against that page after it loads. That’s the actual bridge.
The HTML file is static. It loads once and stays running. What it does on startup is initialize the Hydra engine and then hang a set of functions on the window object; updateFromTD, runHydraCode, setOutput, registerVideoStream, and others. Those functions just sit there waiting. TD is the one calling them.
From the TD side, whenever you want to push data into Hydra, you call window.updateFromTD() with a JSON payload of CHOP values. Whenever you want to run a sketch, you call window.runHydraCode() with the code as a string. Inside the page, helper functions like chop(), lfo(), midi(), and audioFFT() wrap that incoming data so Hydra sketches can reference TD values directly in their syntax; chop('lfo1', 0) inside a Hydra chain just returns whatever TD is currently sending for that channel.
The page never reloads. The file never changes. It’s a persistent runtime that TD talks to on demand.
That’s the insight that makes everything else possible. The HTML file isn’t a display target or a template. It’s a live environment with an API surface:
The HTML page loads once inside the Web Render TOP and initializes the Hydra engine.
The page exposes functions on
windowthat TD can call at any time:
window.updateFromTD = function(jsonData) { ... }
window.runHydraCode = function(code) { ... }
window.setOutput = function(index) { ... }TD sends CHOP data into the page by calling
updateFromTD()with a JSON payload; this updates a live data store inside the page:
window.tdData = { chops: {}, timestamp: Date.now(), updateCount: 0 };
window.updateFromTD = function(jsonData) {
const data = JSON.parse(jsonData);
window.tdData.chops = data;
window.tdData.timestamp = Date.now();
window.tdData.updateCount++;
};
TD sends sketch code as a string by calling
runHydraCode(); the page evals it against the running Hydra instance:
window.runHydraCode = function(code) {
eval(code);
};
Inside that sketch code, helper functions pull from the live data store so the visuals respond to whatever TD is currently sending:
window.chop = function(name, index) {
return function() {
return window.tdData.chops[name][index];
};
};
window.lfo = function(index) { return chop('lfo' + index, 0); };
window.midi = function(cc) { return chop('midi', cc); };
window.audioFFT = function(index) { return chop('audio_spectrum', index); };
So a sketch can reference TD data directly in Hydra syntax, like:
osc(lfo(1), 0.1, audioFFT(4)).rotate(midi(20)).out(o0)
Hydra renders to the canvas; the Web Render TOP captures that as a texture back in TD.
From there it routes through the rest of the network like any other TOP.
The flowchart below summarizes this process:
Waveflower Gooi: Exposing the AnalyserNode from within Strudel
The fact that almost everything in Strudel works within the context of Web Audio API is so that you can:
Expose a specific AudioNode and do something with it, like rerouting its audio destination to OSC instead of your speakers
Since AnalyserNode is also an AudioNode, so long as I can expose its AnalyserNode, I can call:
getFloatTimeDomainData()that returns aFloat32Arraybuffer that contains the audio signal information I need to draw onto the canvas:
The flowchart illustrates the flow of data via script called wave.js:

Each Pattern is appended with
._scope()This allows the AnalyserNode to be accessible via the
AnalysersJavaScript objectin
wave.js’s Visualizer class:class Visualizer { draw() { let data = new Float32Array(ENV.fftSize); analyser.getFloatTimeDomainData(data); // transform data to draw onto canvas using Canvas API } }The
draw()function is then called 60 times per second by utilizingrequestAnimationFrame()to continuously draw onto the canvasesEach Pattern will have its own Visualizer instance, such that multiple overlapping instances can be drawn at the same time:
This trick almost caught me by surprise! For what look like a complex integration suddenly became simple when you know how to work with the Web Audio API. The actual integration from importing Strudel REPL took only a few hours to basically work.
(Note: The Waveflower App respects Strudel’s APGL-3.0 Licensing and thus operate under the same license — read more here)
Final Showcase
Grnch: Hydra-TD Showcase by Grnch
The following video was performed live with the HYDRA2TD integration using 2 Intech midi controllers for some more in depth control, like changing of geometry, color palettes, and video EFX.
Strudel-Waveflower Showcase by Waveflower Gooi
The following music track was performed live during Chicago WNDR Algorave show on April 10th, 2026. It utilizes both Strudel REPL and Waveflower’s Canvas API implementation:
Final Thoughts
Making visual art with live code isn’t a new concept. However, integrating professional grade tools for live-code animations can open up unique possibilities that we could not have easily achieved with preset animations.
In livecoding we do not hide our code. We show it.
We express our art through code. Through multiple senses.
And therefore it deserves the same level of care and treatment as we do with more professional-grade tools. And through integration is how we make it happen.
Thank you for reading! If you like what you read, please consider subscribing to:
Or to this publication:
Footnotes
So I want to clarify a few things about Desmos’ audio accessibility features, in particular the tone() function and the “audio trace” feature:
The
tone(freq, gain)function is similar to evaluatings(“sine”).freq(freq).gain(gain)on Strudel.cc, a livecoding environment.
That’s it — it’s dead set to sine tone but allows you to pass in a frequency in which the signal will be generated. It cannot take a custom math function and turn it into a periodic wave before playing the tone. Disappointing, I know!
The “audio trace” feature is more of an accessibility tool for people who are visually impaired but able to “hear” the graph. Essentially the math function becomes a volume / pitch envelope. A tone is played such that its gain / frequency varies as it samples along the x-axis over time. It’s useful for some, but not quite what I am looking for.
In livecoding environments like Strudel.cc, a common way of structuring code is through separate “blocks of Pattern”. While the whole concept of Pattern deserves yet another article by itself, the basic concept is that each Pattern should contain only ONE instrument or drum loop, such that a user can selectively play / mute / solo tracks live on stage, with relative ease.
The r radius here represents the relative amplitude of the signal, from the baseline 0 up to 1 or -1. The angle, θ here represents the time, or the phase within a period interval, from 0 to 2π.










