A multi-user web-based controller for Processing.org visual sketches. Multiple users can connect via web browsers, interact with UI controls (touch areas, sliders, buttons), stream audio, and use phone motion sensors, all aggregated in real-time on a server-side Processing canvas.
- Features
- Prerequisites
- Getting Started
- Project Structure
- Configuration
- Browser UI
- API Endpoints
- Troubleshooting
- Development
- Architecture
- Customization
- Next Steps
- Technology Stack
- Acknowledgments
- Multi-user support: Multiple concurrent browser clients
- Real-time WebSocket communication: Low-latency bidirectional messaging
- Stronger session lifecycle handling: Session names, heartbeat updates, explicit browser close, and stale-session reaping
- Touch/mouse input: Position tracking with visual feedback
- Keyboard input: Desktop browser key events over the same WebSocket channel
- Audio streaming: Per-user audio buffering, visual level response, and optional dominant-frequency mapping in sample sketches
- Phone motion input: Tilt and shake from supported mobile browsers over HTTPS
- Selectable sketch classes: Launch alternate sketches with
processing.sketch-class - Local operator controls: Processing-window selection, drag, wheel adjustment, HUD, and pause/slow controls layered on top of browser input
- Gravity-orbit sketch samples: Physics-based sketch variants, including a gradient-background version
- HTTPS/TLS: Secure connections required for mobile microphone access
- Cross-device: Works on desktop and mobile browsers
Contents:
| Software | Version | Download |
|---|---|---|
| Java JDK | 21 minimum, 25+ recommended | Adoptium or Oracle |
| Maven | 3.9+ | Apache Maven |
| Git | Latest | Git SCM |
Windows (PowerShell):
$env:JAVA_HOME = "C:\Program Files\Java\jdk-25" # or jdk-21 minimumMac/Linux (Bash):
export JAVA_HOME=/usr/lib/jvm/jdk-25 # or jdk-21 minimum # or wherever JDK is installed
# Add to ~/.bashrc or ~/.zshrc for persistenceWindows (PowerShell):
java -version
mvn -version
echo $env:JAVA_HOMEMac/Linux (Bash):
java -version
mvn -version
echo $JAVA_HOMEContents:
- 1. Clone the Repository
- 2. Try It Locally Over HTTP
- 3. Enable HTTPS for LAN or Mobile Browsers
- 4. Build the Project
- 5. Run the Server
- 6. Access the Application
Windows (PowerShell):
cd C:\Users\yourname\Dev
git clone <repository-url> processing-server
cd processing-serverMac/Linux (Bash):
cd ~/Dev
git clone <repository-url> processing-server
cd processing-serverNo certificate is required for local testing on this machine.
Windows (PowerShell):
.\run.ps1Mac/Linux (Bash):
./run.shOpen http://localhost:8080.
HTTPS is only needed when you want to connect from another device on your LAN, especially for browser microphone access.
Windows (PowerShell):
# Auto-detect your local IP and write keystore.p12 to the project root
.\create-keystore.ps1
# Or specify your IP manually
.\create-keystore.ps1 192.168.1.100
# Use -Force to overwrite an existing keystore
.\create-keystore.ps1 -ForceMac/Linux (Bash):
chmod +x create-keystore.sh
# Auto-detect your local IP and write keystore.p12 to the project root
./create-keystore.sh
# Or specify your IP manually
./create-keystore.sh 192.168.1.100
# Use --force to overwrite an existing keystore
./create-keystore.sh --forceWhat the script does:
- Writes
keystore.p12to the project root. - Exports the CA certificate as
processing-server-ca.cer. - Adds SAN entries for
localhost,127.0.0.1, your current LAN IP, andhostname.local. - Leaves local HTTP unchanged and enables HTTPS only when you launch with the HTTPS config overlay.
To turn HTTPS on:
- Run one of the keystore scripts.
- Trust
processing-server-ca.ceron the devices that will use the HTTPS URL. - Start the server with
.\run-https.ps1or./run-https.sh. - Open
https://<hostname>.local:8443/orhttps://<LAN-IP>:8443/.
Windows (PowerShell):
$env:JAVA_HOME = "C:\Program Files\Java\jdk-25" # or jdk-21 minimum
mvn clean package -DskipTestsMac/Linux (Bash):
export JAVA_HOME=/usr/lib/jvm/jdk-25 # or jdk-21 minimum # adjust as needed
mvn clean package -DskipTestsPackaging note:
- This project intentionally builds an executable shaded jar so it can be launched with
java -jar target/processing-server-<version>.jar - That differs from the stock Helidon example layout in
processing-client, which follows the thinnertarget/libsruntime pattern - The tradeoff is a larger packaged jar and more shading warnings during build in exchange for a simpler launch experience for users
- For this application, that tradeoff is intentional because the app is used more like a runnable desktop/server tool than a minimal framework example
Option A: Using shell script
Windows (PowerShell):
.\run.ps1With extra Java properties:
.\run.ps1 -Properties "-Dprocessing.sketch-class=com.processing.server.GravityOrbitSketch"Notes:
- the run scripts accept a plain
propertiesargument and insert it before-jar - the run scripts now auto-build with
mvn -q -DskipTests packagewhen sources are newer than the packaged jar - because of that auto-build step,
mvnmust be available onPATH
Mac/Linux (Bash):
./run.shWith extra Java properties:
./run.sh "-Dprocessing.sketch-class=com.processing.server.GravityOrbitSketch"Option A2: Using shell script with HTTPS
Windows (PowerShell):
.\run-https.ps1With extra Java properties:
.\run-https.ps1 -Properties "-Dprocessing.sketch-class=com.processing.server.GravityOrbitGradientSketch"Mac/Linux (Bash):
./run-https.shWith extra Java properties:
./run-https.sh "-Dprocessing.sketch-class=com.processing.server.GravityOrbitGradientSketch"Option B: Using Maven
Windows (PowerShell):
$env:JAVA_HOME = "C:\Program Files\Java\jdk-25" # or jdk-21 minimum
mvn package -DskipTests
java -jar .\target\processing-server-1.0-SNAPSHOT.jarMac/Linux (Bash):
export JAVA_HOME=/usr/lib/jvm/jdk-25 # or jdk-21 minimum
mvn package -DskipTests
java -jar ./target/processing-server-1.0-SNAPSHOT.jarOption C: Using Java directly
Windows (PowerShell):
$env:JAVA_HOME = "C:\Program Files\Java\jdk-25" # or jdk-21 minimum
java -jar .\target\processing-server-1.0-SNAPSHOT.jarMac/Linux (Bash):
export JAVA_HOME=/usr/lib/jvm/jdk-25 # or jdk-21 minimum
java -jar ./target/processing-server-1.0-SNAPSHOT.jar| Access Point | URL |
|---|---|
| Local UI | http://localhost:8080/ |
| Local API | http://localhost:8080/api/status |
| LAN/Mobile UI | https://YOUR_HOSTNAME.local:8443/ or https://YOUR_IP:8443/ |
| WebSocket | ws://localhost:8080/ws locally, wss://YOUR_IP:8443/ws over HTTPS |
First-time local access:
- Open
http://localhost:8080/ - No certificate is required for same-machine testing
Mobile device access:
- Generate the keystore and trust
processing-server-ca.cer - Start the server with
.\run-https.ps1or./run-https.sh - On mobile, navigate to
https://YOUR_IP:8443/orhttps://YOUR_HOSTNAME.local:8443/ - Accept the certificate warning if the CA is not yet trusted
The keystore lives at the project root, and HTTPS is enabled through config/application-https.yaml plus -Dapp.config=... at launch time.
processing-server/
|-- pom.xml # Maven configuration
|-- README.md # This file
|-- ARCHITECTURE.md # Detailed architecture documentation
|-- CUSTOMIZATION.md # Guide for modifying and extending
|-- TODO.md # Follow-up tasks and ideas
|-- GRAVITY_ORBIT_SKETCH_TUTORIAL.md # Walkthrough of the gravity-orbit sample sketches
|-- run.ps1 # PowerShell run script
|-- run.sh # Bash run script
|-- run-https.ps1 # PowerShell HTTPS launch script
|-- run-https.sh # Bash HTTPS launch script
|-- create-keystore.ps1 # PowerShell keystore generator
|-- create-keystore.sh # Bash keystore generator
|-- keystore.p12 # Generated TLS keystore
|-- processing-server-ca.cer # Exported CA certificate
|-- config/
| `-- application-https.yaml # HTTPS overlay config for -Dapp.config
|-- generated-src/
| `-- main/java/com/processing/server/
| `-- ... # Reviewed generated sketches kept separate from handwritten server code
|-- src/
| `-- main/
| |-- java/com/processing/server/
| | |-- Main.java # Entry point and socket configuration
| | |-- ProcessingSketch.java # Processing canvas behavior
| | |-- GravityOrbitSketch.java # Alternate orbiting multi-user sketch
| | |-- GravityOrbitGradientSketch.java # Orbit sketch with attraction-based background field
| | |-- LocalOperatorLayer.java # Shared Processing-window operator controls for selectable sketches
| | |-- StarterSketch.java # Minimal alternate sketch example
| | |-- WebSocketHandler.java # WebSocket session and message handling
| | |-- InputService.java # REST API endpoints
| | |-- SessionManager.java # User session tracking
| | |-- EventQueue.java # Thread-safe event queue
| | |-- AudioBuffer.java # Per-session audio buffering
| | |-- AudioConfig.java # Audio configuration
| | |-- DebugConfig.java # Debug logging settings
| | `-- UserInputEvent.java # Event data structure
| `-- resources/
| |-- application.yaml # Default local HTTP configuration
| `-- static/
| `-- index.html # Browser UI
`-- target/ # Build output created after the first Maven build
target/ is created by Maven after the first build. It is not part of the files cloned from GitHub.
Generated-sketch workflow:
- raw converter output belongs under
target/pde-output/... - reviewed generated sketches that you want to compile with the app can live under
generated-src/main/java/... - Maven compiles
generated-src/main/javain addition tosrc/main/java
Contents:
server:
port: 8080 # HTTP port
host: "127.0.0.1" # Local-only HTTP listener
processing:
sketch-class: "com.processing.server.ProcessingSketch" # Sketch class to launch
width: 800 # Canvas width
height: 600 # Canvas height
fps: 60 # Target frame rate
audio:
mode: "high-quality-mono" # Audio mode
debug:
logging: false # Enable audio-analysis debug output
sample-limit: 5 # Max audio debug samples to print
modes:
high-quality-stereo:
sample-rate: 44100
channels: 2
description: "44.1kHz Stereo"
high-quality-mono:
sample-rate: 44100
channels: 1
description: "44.1kHz Mono"
voice:
sample-rate: 22050
channels: 1
description: "22.05kHz Mono"
buffer-size: 2048
max-buffer-chunks: 20
debug:
logging: false # Enable debug outputprocessing.sketch-class lets you run a different sketch class without editing Main.java. The class must:
- extend
PApplet - provide the same constructor shape as
ProcessingSketch - provide a public
runSketch()method
Example:
java "-Dprocessing.sketch-class=com.processing.server.StarterSketch" -jar .\target\processing-server-1.0-SNAPSHOT.jarUsing the helper script:
.\run.ps1 -Properties "-Dprocessing.sketch-class=com.processing.server.GravityOrbitSketch"Gradient variant:
.\run.ps1 -Properties "-Dprocessing.sketch-class=com.processing.server.GravityOrbitGradientSketch"StarterSketch is included as a minimal alternate sketch. It proves that the config switch works and reacts to browser touch, size-slider, and keyboard input.
Additional sample sketches included in src/main/java/com/processing/server/:
GravityOrbitSketch: orbiting multi-user circles with touch anchors, shake repulsion, and motion-modified attractionGravityOrbitGradientSketch: the same sketch plus a soft attraction-based background gradient
The default ProcessingSketch and the gravity sketches also share a local Processing-window operator layer. That local layer is separate from browser controls and currently supports:
- click to select a circle
- drag to move the selected user target
Shift + mouse wheelto adjust selected user sizeCtrl + mouse wheelto adjust selected user gainDtoggle the local HUDNtoggle on-canvas namesPpause local sketch physics/easing updatesSslow motionRscatter all circlesCre-center all circles
In the gravity sketches, the same layer also drives optional local overlays for velocity vectors and attraction lines.
See GRAVITY_ORBIT_SKETCH_TUTORIAL.md for a walkthrough of how those sketches were built by starting from ProcessingSketch and modifying key methods.
For reviewed converted sketches, keep the generated Java separate from the main server source tree:
- raw converter output:
target/pde-output/<sketch-name>/ - launchable reviewed sketch classes:
generated-src/main/java/com/processing/server/
Phone motion input is configured in src/main/resources/application.yaml:
motion:
update-hz: 20
clamp:
alpha-degrees: 180
beta-degrees: 60
gamma-degrees: 60
acceleration-g: 3.0
magnitude-g: 4.0
mapping:
tilt-offset-normalized: 0.12
shake-threshold-g: 0.6
shake-burst-scale: 1.8
debug:
logging: false
sample-limit: 5Adjustable motion settings:
motion.update-hz: browser send rate for combined motion samplesmotion.clamp.beta-degreesandmotion.clamp.gamma-degrees: max tilt accepted by the servermotion.clamp.acceleration-g: max absolute acceleration retained per axismotion.clamp.magnitude-g: max retained acceleration magnitudemotion.mapping.tilt-offset-normalized: how far tilt can offset the rendered position around the touch targetmotion.mapping.shake-threshold-g: minimum shake signal before a burst is triggeredmotion.mapping.shake-burst-scale: scales the shake-driven burst intensitymotion.debug.logging: enables a few motion debug samples in the server/sketch
Important:
- this file is packaged into the jar
- changing these values requires a rebuild with
mvn clean package -DskipTests
Edit application.yaml or pass system property:
Windows (PowerShell):
java -Dserver.port=9090 -jar .\target\processing-server-1.0-SNAPSHOT.jarMac/Linux (Bash):
java -Dserver.port=9090 -jar ./target/processing-server-1.0-SNAPSHOT.jarEdit application.yaml:
audio:
mode: "voice" # Options: high-quality-stereo, high-quality-mono, voiceAudio-analysis debug logging is configured separately from general debug logging:
audio:
debug:
logging: true
sample-limit: 12Or via system property:
.\run.ps1 -Properties "-Daudio.debug.logging=true -Daudio.debug.sample-limit=12 -Dprocessing.sketch-class=com.processing.server.GravityOrbitGradientSketch"With audio.debug.logging enabled, the gravity sketches emit audio debug lines only when the analyzed level is above the current detection threshold, so quiet buffers that merely retain the last frequency do not spam the log.
Contents:
The web interface (index.html) provides:
- Touch Area: Drag to move your circle on the canvas
- Size Slider: Adjust the core circle size while keeping the outer audio ring proportional
- Speed Slider: Adjust movement responsiveness and the decay speed of temporary effects
- Action Buttons:
Burst,Spin Color, andScattertrigger visual effects - Audio Input: Start or stop microphone audio (HTTPS is required for mobile and remote browsers)
- Audio Gain Slider: Attenuate or amplify how strongly incoming audio drives the sketch
- Motion Input: Enable phone motion sensors, view live tilt values, and send tilt/shake control over HTTPS
- Motion Trim Slider: Adjust motion sensitivity in the browser before motion samples are sent to the server
- Keyboard Input: Desktop browsers can send key events while the page has focus, and phones/tablets can open a compact on-screen keyboard with
Tap for simple keyboard input - Session Name: A browser client can save a short display name for its session, and the sketch will use that name as the on-canvas label when available
- Session Lifecycle: The browser sends heartbeats while connected and sends a best-effort close notification when the page is leaving, which helps remove stale circles more reliably
Separately from the browser UI, the Processing window now also has a local operator layer for the person sitting at the machine. Those controls do not travel over the WebSocket and do not replace browser-side session input.
The touch area uses touch-action: none, which helps avoid accidental browser text selection or gesture interference while dragging.
The motion trim is a client-only setting. It scales the browser's outgoing motion sample before transmission, so different devices can feel less or more responsive without changing the shared server config.
Keyboard notes:
- keyboard input depends on page focus
- on phones and tablets, use
Tap for simple keyboard inputto focus the compact keyboard field and open the on-screen keyboard - the default sketch uses arrows or WASD to nudge the circle and space to trigger a burst
- the browser UI also exposes the last key seen so you can confirm the protocol is active
- if a custom sketch also keeps local Processing
keyPressed()logic, that local keyboard path only works when the Processing window has focus - mobile soft keyboards are best for simple character input; important mobile controls should still prefer buttons, sliders, and touch
Processing-window local operator notes:
- these controls are separate from browser key events in
EventQueue - local controls only work when the Processing window has focus
- click selects the nearest visible circle
- drag moves that selected user's local target position
Shift + mouse wheelchanges selected sizeCtrl + mouse wheelchanges selected gainD,N,P,S,R, andCare reserved for local operator actions- the gravity sketches also support
Vfor velocity vectors andLfor attraction lines - the local HUD shows selected-user details;
freq=n/ain the default sketch and live dominant frequency in the gravity sketches
Add ?debug to the URL:
http://localhost:8080/?debug
This enables console logging in the browser.
Contents:
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/session |
Create new session (returns JSON with sessionId) |
GET |
/api/status |
Get status (session count, queue size, and session metadata such as saved names and lastSeenAt) |
POST |
/api/event |
Submit event (requires sessionId in body) |
Connect to ws://localhost:8080/ws for local HTTP, or wss://localhost:8443/ws when launched with -Dapp.config=config/application-https.yaml.
Server -> Client Messages:
{
"type": "session",
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"name": "Ava"
}{
"type": "session-meta-ack",
"name": "Ava"
}{
"type": "server-shutdown",
"reason": "Processing Server is shutting down."
}Client -> Server Messages:
{
"type": "touch",
"controlId": "touchArea",
"x": 0.5,
"y": 0.3,
"timestamp": 1234567890
}{
"type": "slider",
"controlId": "sizeSlider",
"value": 0.75,
"timestamp": 1234567890
}{
"type": "motion",
"controlId": "deviceMotion",
"alpha": 12.0,
"beta": -8.5,
"gamma": 24.0,
"ax": 0.1,
"ay": 0.4,
"az": 1.0,
"magnitude": 1.08,
"timestamp": 1234567890
}{
"type": "key",
"controlId": "keyboard",
"key": "ArrowLeft",
"keyCode": 37,
"action": "pressed",
"timestamp": 1234567890
}{
"type": "session-meta",
"name": "Ava"
}{
"type": "heartbeat",
"timestamp": 1234567890
}{
"type": "session-close",
"timestamp": 1234567890
}Audio is sent as binary WebSocket frames (not JSON).
Contents:
- "Port already in use"
- "SSL handshake failure" / "Can't connect"
- "Session ID: connecting..." or controls do nothing
- "The browser says the server disconnected"
- "Microphone not working on mobile"
- "Motion works, but shake is weak or invisible"
- "Audio not streaming"
- "Users initialize on same position"
- "Java version errors"
- "Maven not found"
- "IP address changed / certificate invalid"
Another process is using port 8080. Either:
- Stop the conflicting process
- Change the port in
application.yaml
Windows (PowerShell):
netstat -ano | findstr :8080Mac/Linux (Bash):
lsof -i :8080
# or
netstat -tulpn | grep 8080Ensure:
keystore.p12exists in the project root- The server was started with
.\run-https.ps1,./run-https.sh, or-Dapp.config=config/application-https.yaml - Keystore has proper structure (CA + signed server cert)
- Server started successfully (check console output)
Verify TLS is working:
# Local HTTP
curl http://localhost:8080/api/status
# Optional HTTPS socket when started with the HTTPS config overlay
curl -k https://localhost:8443/api/status# Local HTTP
curl http://localhost:8080/api/status
# Optional HTTPS socket
curl -k https://localhost:8443/api/status
# View certificate details
openssl s_client -connect localhost:8443 -showcertsExpected output: JSON with activeSessions, queueSize, etc.
If curl fails with SSL error, the keystore is malformed. Regenerate with create-keystore.ps1.
- Confirm the page is using the matching WebSocket URL for its current scheme
- Use
ws://localhost:8080/wsfor local HTTP orwss://<host>:8443/wsfor HTTPS - Check
http://localhost:8080/api/statusorhttps://localhost:8443/api/status - If the page is open and connected,
activeSessionsshould be greater than0
- On a clean shutdown, the server sends a final
server-shutdownWebSocket message before closing connections - The browser shows a banner and scrolls back to the top so the notice is visible
- On an unexpected disconnect, the browser also shows a banner and attempts to reconnect
- If a browser disappears abruptly, the server now reaps stale sessions after a timeout, so sketch-side user state should eventually be removed even when a clean close is missed
- Must use HTTPS (not HTTP)
- Local
http://localhost:8080works on the same machine but not for mobile microphone access - Must accept certificate warning
- Browser requires user gesture before microphone access
- Motion tuning in
src/main/resources/application.yamlrequires a rebuild - Restart after
mvn clean package -DskipTests - Try lowering
motion.mapping.shake-threshold-g - Try raising
motion.mapping.shake-burst-scale - Enable
motion.debug.logging: trueto inspect sample values
The current shake effect is driven by:
- acceleration magnitude change
- axis-to-axis acceleration change
So short sharp shakes should produce a stronger burst than slow movement.
- Check browser console for errors
- Verify HTTPS is active
- Try manual audio start: click "Start Audio" button
- Check debug output:
http://localhost:8080/?debug
Users are placed at random non-overlapping positions. If many users connect simultaneously, some overlap may occur. Refresh the browser page to reinitialize.
Ensure Java 21+ is installed and JAVA_HOME is set (Java 25+ recommended for best performance):
Windows (PowerShell):
$env:JAVA_HOME = "C:\Program Files\Java\jdk-25" # or jdk-21 minimum
java -versionMac/Linux (Bash):
export JAVA_HOME=/usr/lib/jvm/jdk-25 # or jdk-21 minimum
java -versionNo preview flags required for Java 21+.
Install Maven or use the full path:
Windows (PowerShell):
# If installed via Chocolatey
C:\ProgramData\chocolatey\lib\maven\apache-maven-3.9.14\bin\mvn
# Or add to PATH
$env:PATH += ";C:\ProgramData\chocolatey\lib\maven\apache-maven-3.9.14\bin"Mac/Linux (Bash):
# If installed via Homebrew (Mac)
/opt/homebrew/bin/mvn
# Or add to PATH
export PATH=$PATH:/opt/homebrew/binThe keystore certificate includes your local IP address in the Subject Alternative Name (SAN) extension. If your laptop connects to a different network, your IP will likely change, causing certificate validation errors in browsers.
Current behavior: You must regenerate the keystore when your IP changes.
Workarounds (choose one):
-
Regenerate keystore (current approach):
.\create-keystore.ps1 # auto-detects new IP .\run-https.ps1
-
Use hostname instead of IP:
The keystore scripts already include
HOSTNAME.localin the SAN list.Then connect via:
https://YOURHOSTNAME.local:8443/Works on most networks with mDNS/Bonjour (Windows 10+, macOS, Linux with avahi).
-
Accept browser warnings (not recommended for classrooms):
Proceed past the security warning. The connection still encrypts, but users see a scary warning.
-
Use a real domain with Let's Encrypt (production):
Requires a registered domain and DNS pointing to your server.
Contents:
Windows (PowerShell):
mvn package -DskipTestsMac/Linux (Bash):
mvn package -DskipTestsmvn testEnable in application.yaml:
debug:
logging: trueOr via system property:
Windows (PowerShell):
java -Ddebug.logging=true -jar .\target\processing-server-1.0-SNAPSHOT.jarMac/Linux (Bash):
java -Ddebug.logging=true -jar ./target/processing-server-1.0-SNAPSHOT.jarWith debug logging enabled, the app now logs more session-lifecycle detail, including:
- WebSocket open/close/error
- browser-requested
session-close - heartbeat receipt
- stale-session reaping and cleanup completion
General debug logging does not control the gravity sketches' audio-analysis traces. Use audio.debug.logging for those.
See ARCHITECTURE.md for detailed documentation on:
- Component interactions
- Threading model
- Audio streaming implementation
- Event processing flow
- HTTPS/TLS configuration details
See CUSTOMIZATION.md for guidance on:
- Changing canvas size, colors, and audio quality
- Adding new UI controls (sliders, buttons, color pickers)
- Creating your own Processing sketches
- Using audio data for visualizations
- Adding new event types
- Complete example: Building a particle system
- Using AI coding assistants to speed up development
Now that you have the server running:
- Try the demo: Open multiple browser tabs/mobile devices to see multi-user interaction
- Customize the sketch: See CUSTOMIZATION.md for step-by-step guides
- Learn the architecture: See ARCHITECTURE.md for technical details
| Component | Technology |
|---|---|
| Web Framework | Helidon 4.4 (SE) |
| WebSocket | Helidon WebSocket |
| HTTP Server | Helidon WebServer |
| Visual Output | Processing 4.5.3 (Java) |
| Audio | Raw PCM processing |
| Build Tool | Maven |
| Java Version | JDK 21 (min), 25+ recommended |
| HTTPS | Self-signed PKCS12 certificate |
- Processing Foundation - Visual arts programming
- Helidon - Lightweight Java web framework
- Oracle - Java Development Kit