Text Ocean SPH
Thousands of character particles simulate a fluid ocean via SPH — a boat floats on the letter waves.
Each character is a physics particle in a Smoothed Particle Hydrodynamics simulation. Gravity, pressure, and viscosity make the letters behave like water. Wave forces create swells that push the boat. The spatial hash grid enables efficient neighbor lookups for 2500+ particles at 60fps.
prepareWithSegments()layoutWithLines() What this demonstrates
A full SPH fluid simulation where every particle is a visible character extracted via Pretext's
layoutWithLines(). The letters collectively behave as water — they have density,
pressure, viscosity, and respond to gravity and wave forces. The boat floats on the particle surface.
Relevant Pretext API
prepareWithSegments(text, font)— extract characters from textlayoutWithLines(prepared, width, lh)— get line data for character extraction
Why this is impressive
2500 character particles running SPH physics at 60fps. Each particle is a letter from a real paragraph. The spatial hash grid makes neighbor searches O(n) instead of O(n²). The boat's buoyancy, tilt, and wake all emerge from the particle interactions — no pre-scripted animation.
Quick start
import { prepareWithSegments, layoutWithLines } from '@chenglou/pretext';
// Extract characters from text layout
const prepared = prepareWithSegments(text, '10px Inter');
const result = layoutWithLines(prepared, width, 14);
const chars = result.lines.flatMap(l => [...l.text].filter(c => c !== ' '));
// Each character becomes an SPH particle
const particles = chars.map((char, i) => ({
char, x: ..., y: ..., vx: 0, vy: 0, density: 0
}));
// SPH simulation loop (each frame):
// 1. Build spatial hash grid for O(n) neighbor search
// 2. Compute density per particle from neighbors within radius H
// 3. Apply forces: gravity + pressure + viscosity + wave
// 4. Boat repels nearby particles (hull collision)
// 5. Integrate velocities → positions
// 6. Boat Y tracks average particle surface (buoyancy)
// 7. Render each particle as its character on canvas