GLSL / WebGL Minimal

Hello World: WebGL / GLSL Minimal walkthrough

~40 lines. No GUI, no scene: just the solver, resize, splats and density output. This walkthrough explains what the demo is doing, which library outputs it uses, and which parameters matter.
Demo walkthrough

This version keeps the integration small so the moving parts are visible. It uses the WebGL / GLSL path from `three-fluid-fx`, where the effect is built with EffectComposer passes, ShaderMaterial uniforms, and WebGL render targets.

Live demo

Minimal WebGL Examples: Hello World Open example

What this demo teaches

Hello World is not an effect stack. It is the baseline proof that pointer input is writing energy into a GPU fluid field and that the render loop is stepping that field correctly. In this variant, the relevant fluid output is Texture objects: velocityTexture, densityTexture, and dyeTexture when dye is enabled.

  • Understand the smallest useful FluidSimulation lifecycle.
  • Know why the solver output is invisible until you render or sample it.
  • Keep resize, pixel ratio, and dt handling explicit.

Implementation path

  1. Create the renderer and solver together

    The renderer owns the GPU context. The simulation allocates its render targets against that context, so construction belongs near renderer setup.

  2. Attach pointer splats

    Pointer movement writes velocity and density impulses. The helper is intentionally thin, so splatRadius and splatForce remain normal runtime parameters.

  3. Render the density output

    The demo draws the fluid field itself. Later examples replace this final draw with overlays, distortion passes, or particles.

  4. Minimal scope

    It avoids GUI state and preset switching. Read it first when you need the smallest reliable version of the technique.

import { attachPointerSplats, FluidSimulation } from 'three-fluid-fx'

const fluid = new FluidSimulation(renderer, {
  profile: 'balanced',
  splatRadius: 0.001,
  splatForce: 6,
})

attachPointerSplats(renderer.domElement, fluid)

renderer.setAnimationLoop(() => {
  fluid.step(clock.getDelta())
  renderFluidDensity(fluid)
})

Parameters to tune

Parameter What it controls How to tune it
profile Chooses the default render-target sizes and pressure baseline. Use performance for embeds, balanced for normal pages, and quality for hero captures.
splatRadius Brush size in normalized UV units. Start small for crisp trails. Raise it when the pointer should feel like smoke or water.
splatForce Velocity gain from pointer movement. Raise it until the field clearly reacts. Lower it if fast mouse movement tears the shape.
densityDissipation How long the visible mask remains alive. High values make long trails. Lower values make quick puffs.

Source landmarks

Start from examples/glsl/minimal/helloworld/main.ts. These are the parts worth reading first:

  • Renderer setup and animation loop.
  • FluidSimulation construction options.
  • resize() and fluid.resize(width, height).
  • The draw path that turns density into pixels.

Production notes

  • Keep the simulation resize tied to the visible canvas size, not just window.innerWidth.
  • Clamp devicePixelRatio for small demos and documentation embeds.
  • Use this demo as a smoke test before debugging any higher-level effect.