junkpile

11 · Tauri v1 OSC Input

A modernized Junkpile essential demonstrating how a Tauri v1 Rust backend can receive Open Sound Control messages over UDP and route them into a p5.js WebGL shader instrument.

This is the final legacy V1 project modernization. It intentionally remains smaller than the later OSC-driven applications: the goal is to make the native UDP → Tauri event → JavaScript parameter → GLSL path visible and easy to modify.

What it demonstrates

Signal flow

TouchOSC / Max / Pure Data / SuperCollider / another sender
                              │
                              │ OSC over UDP
                              ▼
                  Rust UdpSocket listener
                              │
                              ▼
                    rosc packet decoder
                              │
                              ▼
                  Tauri "osc-event" event
                              │
                              ▼
                 address route + value scale
                              │
                              ▼
                    p5.js parameter state
                              │
                              ▼
                        GLSL uniforms
                              │
                              ▼
                       WebGL output

The browser cannot open a raw UDP socket. Rust owns that system-level input and forwards structured messages to the WebView.

Run

npm install
npm run dev

npm install installs both the local Tauri CLI and p5.js. The predev script copies p5.min.js into src/vendor, so the app does not require a CDN at runtime.

Production build

npm run build

On macOS, packaged output is normally created under:

src-tauri/target/release/bundle/

Unsigned applications may still trigger Gatekeeper warnings when distributed outside your own computer.

First test

  1. Run the app.
  2. Leave LAN devices and port 9000 selected.
  3. Press Send test burst.
  4. Confirm that the terminal receives eight packets and the visual changes.
  5. Configure another OSC application to send UDP to one of the listed endpoints.

Listener controls

Bind mode

Port

The default is UDP 9000. Change it when another application already owns that port.

Endpoint hints

The app displays loopback and likely LAN endpoints. Network interfaces and firewalls vary, so these are practical hints rather than a replacement for operating-system network inspection.

Default routes

OSC address Parameter Expected input
/hue Hue 0–1
/zoom Zoom 0–1
/speed Speed 0–1
/brightness Brightness 0–1
/distortion Distortion 0–1
/complexity Complexity 0–1
/saturation Saturation 0–1
/glow Glow 0–1

Routes can be edited directly. End an address with * to match a prefix, such as:

/visual/*

That route accepts /visual/a, /visual/fader/1, and any other address sharing the prefix.

Scaling modes

OSC learn

  1. Choose a visual parameter.
  2. Press Arm learn.
  3. Send one OSC message.
  4. The incoming address becomes that parameter’s route.

Routes are stored in WebView local storage and survive relaunches.

Supported packet data

The Rust listener reports common OSC argument types including:

The first numeric argument drives visual routing. All arguments remain visible in the packet terminal.

Nested OSC bundles are decoded recursively and report their bundle depth.

Keyboard shortcuts

Key Action
Space Pause/resume rendering
R Reset visual values
F Toggle fullscreen

Project structure

p5-tauri-osc-template/
├── README.md
├── MODERNIZATION-NOTES.md
├── package.json
├── scripts/
│   └── sync-p5.mjs
├── src/
│   ├── index.html
│   ├── styles.css
│   ├── sketch.js
│   └── vendor/
│       └── p5.min.js        generated after npm install
└── src-tauri/
    ├── Cargo.toml
    ├── build.rs
    ├── tauri.conf.json
    ├── icons/
    └── src/
        └── main.rs

Rust architecture

main.rs owns a restartable listener runtime:

OscState
└── Mutex<Option<OscRuntime>>
    ├── stop flag
    ├── listener thread
    └── active endpoint metadata

Starting a new listener safely stops and joins the previous listener thread before binding the replacement socket.

Troubleshooting

No packets arrive

Port already in use

Another process has bound the selected UDP port. Stop that process or choose a different port.

Values move incorrectly

Check the selected scaling mode. A sender producing 0–127 values will immediately saturate a route configured for normalized 0–1 values.

A sender uses different paths

Edit the route fields or use OSC learn. The app does not require the default address names.

Suggested extensions

Version note

This project intentionally uses Tauri v1. It is a WebView graphics example, not a native wgpu surface. The renderer is p5.js/WebGL and Rust supplies native UDP access.