react-webgl-fluid-play
v0.8.0
Published
Fluid simulation in React with webgl, pure typescript, no dependencies
Maintainers
Readme
react-webgl-fluid-play
Fluid simulation in React with WebGL, pure TypeScript, and zero runtime dependencies.
Installation
npm install react-webgl-fluid-play
# or
yarn add react-webgl-fluid-play
# or
pnpm add react-webgl-fluid-playRequires React 17+ and ReactDOM 17+ as peer dependencies.
Quick start
import Canvas from 'react-webgl-fluid-play';
export default function App() {
return (
<div style={{ position: 'fixed', inset: 0 }}>
<Canvas initialAnimation={{ path: 'oval' }} />
</div>
);
}The component fills 100 % of its parent, so wrap it in a positioned container that defines the size you want.
Public exports
import Canvas, {
PathFollower,
PREDEFINED_PATHS,
PREDEFINED_PATH_IDS,
cloneFluidPath,
createPredefinedPath,
getPredefinedPath,
getPredefinedPaths,
isPredefinedPathId,
type CanvasAnimationOptions,
type CanvasInitialAnimation,
type CanvasProps,
type CanvasRef,
type FluidPath,
type FluidPathOverrides,
type PathColor,
type PathPoint,
type PredefinedPathId,
} from 'react-webgl-fluid-play';Canvasdefault export (and named export)PathFollowerclass export- predefined path exports:
PREDEFINED_PATHS,PREDEFINED_PATH_IDS,createPredefinedPath,getPredefinedPath,getPredefinedPaths,isPredefinedPathId,cloneFluidPath - path/type exports:
FluidPath,FluidPathOverrides,PathPoint,PathColor,PredefinedPathId - canvas API types:
CanvasRef,CanvasProps,CanvasAnimationOptions,CanvasInitialAnimation
Predefined path ids
oval, infinity, spiral, wave, star, heart
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| width | number | window width | Fixed pixel width of the canvas. Omit to auto-track the viewport. |
| height | number | window height | Fixed pixel height of the canvas. Omit to auto-track the viewport. |
| className | string | — | CSS class applied to the outer wrapper <div>. |
| style | React.CSSProperties | — | Inline styles merged into the outer wrapper <div>. |
| onLoad | () => void | — | Called once the WebGL fluid simulation has successfully initialised. |
| onError | (error: string) => void | — | Called if WebGL initialisation fails, with a human-readable error message. |
| showPathManager | boolean | false | Show the built-in path-selector button and panel. Omit or set false for a completely bare canvas. |
| initialAnimation | { path: FluidPath \| PredefinedPathId; options?: CanvasAnimationOptions } | — | Starts a path animation automatically once the simulation is ready. |
| loadingFallback | React.ReactNode | spinning ring | Rendered while the simulation is initialising. Pass null to show nothing. |
| errorFallback | (error: string, retry: () => void) => React.ReactNode | minimal error + retry button | Rendered when initialisation fails. Receives the error message and a retry callback. |
CanvasAnimationOptions
maxLoops?: number(-1or omitted = infinite)predefinedOverrides?: FluidPathOverrides(used when path is a predefined id)
CanvasRef
playPath(path, options?)playPredefinedPath(pathId, options?)stopPath()clearPath()(alias ofstopPath())isPlayingPath()getCurrentPath()
Examples
Bare canvas — no UI whatsoever
<Canvas />With the built-in path manager
<Canvas showPathManager />Start a predefined path on init
<Canvas initialAnimation={{ path: 'heart', options: { maxLoops: 1 } }} />Fixed size
<Canvas width={800} height={600} />Lifecycle callbacks
<Canvas
onLoad={() => console.log('simulation ready')}
onError={(msg) => console.error('WebGL failed:', msg)}
/>Custom loading indicator
<Canvas loadingFallback={<MySpinner />} />
// hide loading UI entirely
<Canvas loadingFallback={null} />Custom error UI
<Canvas
errorFallback={(error, retry) => (
<div>
<p>{error}</p>
<button onClick={retry}>Try again</button>
</div>
)}
/>Styled wrapper
<Canvas
className="my-fluid-canvas"
style={{ borderRadius: '12px', overflow: 'hidden' }}
/>Use forwardRef to trigger animations imperatively
import { useRef } from 'react';
import Canvas, { type CanvasRef, createPredefinedPath } from 'react-webgl-fluid-play';
export default function App() {
const canvasRef = useRef<CanvasRef>(null);
return (
<>
<button onClick={() => canvasRef.current?.playPredefinedPath('infinity')}>Infinity</button>
<button onClick={() => canvasRef.current?.playPredefinedPath('heart', { maxLoops: 1 })}>
Heart Once
</button>
<button
onClick={() => {
const custom = createPredefinedPath('wave', { duration: 3, loop: false });
canvasRef.current?.playPath(custom);
}}
>
Custom Wave Variant
</button>
<button onClick={() => canvasRef.current?.stopPath()}>Stop</button>
<Canvas ref={canvasRef} />
</>
);
}Notes
- Mobile: the component automatically uses
window.visualViewportfor accurate dimensions on mobile browsers and prevents default touch scroll/zoom behaviour on the canvas. - Dimensions: when
width/heightprops are omitted the canvas trackswindow.innerWidth/window.innerHeight(andvisualViewporton mobile), reacting to resize and orientation-change events. - Path coordinates: custom paths use normalized coordinates (
x/yin[0,1]). - WebGL: requires a browser with WebGL support and hardware acceleration enabled. The
onErrorcallback (or the default error UI) is shown when the context cannot be created. - Layout: the component renders as
position: relative; width: 100%; height: 100%. Place it inside a container that defines the actual size (e.g.position: fixed; inset: 0for full-screen).
Development scripts
pnpm start- run the demo app in development mode.pnpm build- build the demo app (react-scripts build).pnpm build:lib- build library artifacts todist/(CJS, ESM, and.d.ts).pnpm lint- lintsrc/andscripts/with ESLint.pnpm lint:fix- lint with auto-fixes.pnpm prepublishOnly- build library artifacts before publishing.
Package metadata
- Module formats: ships both CommonJS (
main) and ESM (module) builds. - Type declarations: includes bundled TypeScript definitions (
types). - Tree-shaking: no side effects, so bundlers can safely drop unused imports.
License
MIT © Maifee Ul Asad
