RCWeb Fluid Simulation

The RCWeb Fluid Simulation app (app/fluid-sim) is a shared display for collaborative, relaxing color swirls. It pairs with app/fluid-sim-c, where many users can touch and drag to inject their own color into a WebGL fluid canvas.

icon

Screenshot

screenshot

What it does

  • WebGL Fluid Solver: A GPU velocity and dye simulation creates curls, pressure-driven motion, and soft paint-on-water blooms.
  • Momentum: Finger velocity is transferred into the display, so fast strokes keep drifting and slow strokes bloom gently.
  • Multi-User Color Trails: Every controller has its own color, letting several people create distinct swirls on the same screen.
  • Shared Display Flow: The display shows a QR code to open the controller for the current room.
  • Ambient Mode: When the display starts, and again after 30 seconds without controller input, it adds slow automatic swirls so the screen never feels empty.
  • OLED-Friendly Presentation: The base display is true black, with saturated dye colors rendered on top.

How to use it

  1. Open /fluid-sim/ on the main display.
  2. Scan the QR code from one or more phones to open /fluid-sim-c/ in the same room.
  3. Pick a color on each controller and drag on the touch pad.
  4. Use slow gestures for calm ink-like blooms, or faster gestures for energetic streaks and curls.

The centered information box appears on startup and returns after 30 seconds of inactivity. It fades when a real controller stroke is received. The QR code remains in the bottom-right corner and fades to 33% opacity after the first user stroke.

How it works

The controller sends normalized touch segments to fluidSim.addStroke using rc.sendFunctionCall. The display converts those segments into WebGL splats, disturbs a GPU velocity field, solves pressure to keep the motion fluid-like, and advects dye through the field over time. The graphics pipeline is inspired by Pavel Dobryakov's MIT-licensed WebGL Fluid Simulation.

Rendering pipeline

  • Velocity Buffer: Stores two-channel motion in floating-point WebGL textures.
  • Dye Buffer: Stores the visible color field separately from velocity.
  • Splat Pass: Adds controller input into both the velocity and dye buffers.
  • Curl and Vorticity Passes: Reintroduce swirling detail so motion feels fluid rather than linear.
  • Divergence and Pressure Solve: Projects velocity toward incompressible fluid-like motion.
  • Velocity Stabilization: Soft-compresses runaway velocity so the simulation does not accelerate into instability over time.
  • Advection: Moves both dye and velocity through the current flow field.
  • Display Shader: Renders the dye on a black background while preserving the selected controller hue.

Network API

The display exposes these functions globally under fluidSim:

  • fluidSim.addStroke(player, startX, startY, endX, endY, color, strength): Adds a normalized stroke segment from a controller.
  • fluidSim.setAimCursor(client, x, y, color, active): Shows or hides a transient remote cursor.
  • fluidSim.broadcastSize(): Sends the display aspect ratio to connected controllers.
  • fluidSim.clearCanvas(): Clears simulation buffers. This is retained as an internal API, although the controller no longer exposes a clear button.

Notes for maintainers

  • This app intentionally has no external JavaScript dependency.
  • The display requires WebGL with floating-point or half-float render targets. If unsupported, it shows a fallback message.
  • Brush size is controlled primarily by splatRadius in webgl-fluid.js.
  • Stability is controlled by velocity dissipation, curl strength, pressure iterations, and the stabilizeVelocity shader pass.
  • Ambient motion is generated locally by the display and is not broadcast to controllers.
DocumentationServer TelemetryServer StatsServer HTTP LogServer WebSocket Log