The Outside World

Everything so far has been pure computation—strands transforming coordinates into values. But at some point, those values need to become light and sound. And the coordinates have to come from somewhere real: a canvas size, a sample rate, a moment in time.Backends are the bridge. A backend connects WEFT to actual hardware—screens, speakers, cameras, microphones. It provides the coordinates your code runs over, and it takes your output and makes it physical.

What backends provide

A backend brings three things to the table: coordinates, inputs, and outputs.

Coordinates are what go in the me bundle. The audio backend provides me.i for sample index, me.t for time, and me.sampleRate for playback rate. Your code doesn’t decide what’s in me, the backend does.

Inputs are how the outside world becomes strands and bundles. The standard WEFT backend has mouse and key for interaction. The visual backend comes with camera for live video and texture for loading images. Each of these is a spindle that returns data from hardware, turned into regular strands.

Outputs are the special bundle names the backend watches for. When you define a display[r,g,b], the visual backend recognizes it, knows it should render those values as pixel colors, and puts them on your screen. When you define a play[left,right] bundle, the audio backend picks it up, and sends those values to your speakers. Outputs take your abstract signals and make them real.

For a full list of coordinates, inputs, and outputs for each backend, see Reference

Domain-agnosticism

As we have seen, a strand is just a function from coordinates to values. It doesn’t know where those coordinates come from—it just takes whatever it’s given and computes a result.

osc.val = sin(me.t * 440 * 6.28)

This describes a 440 Hz sine wave. If the visual backend evaluates it, me.t advances at 60fps and you get a smoothly changing value, useful for animation. If the audio backend evaluates it, me.t advances at 44100 samples per second and you get an audible tone. The strand is identical. The backend decides how to interpret and output it.

This means you can write a function once and use it anywhere. An oscillator works for pixels or samples. A noise function works for textures or audio grain. The math doesn’t change—only the rate at which it gets evaluated.

The coordinates you use shape what you get. If you display something that never mentions me.x or me.y, every pixel computes the same value and you’ll get a flat color. If you play something that never mentions me.t or me.i, every sample is identical and you won’t hear sound. The backend provides the coordinates, but whether or not your code does something with them is up to you.

Multiple backends

A program can talk to multiple backends at once. Write to both display and play, and WEFT runs the visual backend for pixels and the audio backend for samples, in parallel.

WEFT figures out which backend owns each strand by looking at what it touches. If a strand calls camera, it belongs to the visual backend, since only that backend knows how to read from a camera. If a strand calls microphone, it belongs to audio. Pure math that doesn’t touch any hardware can run in either context, and WEFT duplicates it into whichever backend needs it.

You don’t need to annotate anything or tell WEFT which backend to use. It traces the dependencies and routes each strand to the right place.

Strands can also flow between backends. A visual strand can depend on something computed in audio, or vice versa.

loud.val = abs(microphone(0, 0))

display[r,g,b] = [loud.val, loud.val, loud.val]

The loud.val strand uses microphone, so it belongs to the audio backend. But display belongs to visual. WEFT computes loud.val in audio and routes the result to visual. Each domain runs on its own backend, but strands can cross boundaries.

Choosing backends

Planned feature, not yet implemented

Right now when you run WEFT, you automatically get the two builtin backends (visual and audio). I am working on implementing more backends to extend what WEFT can do. Alongside this, there will be syntax to specify exactly which backends you want to include with your program.