Ripple a wave map
Refract and light a tiled sign through fine, fast-moving waves, with an unfiltered comparison toggle.
APIs demonstrated
Section titled “APIs demonstrated”- waterWaves from
@pibbl/core/textures - WaterWavesOptions from
@pibbl/core/textures - WaterWavesMessage from
@pibbl/core/textures
Complete example
Section titled “Complete example”Plain source. Run as a browser module after the document body exists. TSX uses jsx: "react-jsx" and jsxImportSource: "@pibbl/core".
import { pibbl, Group, Rectangle, Circle, Text, signal } from "@pibbl/core";import { displacement, reflectedLight } from "@pibbl/core/filters";import { waterWaves, useTexture, type WaterWavesOptions, type WaterWavesMessage,} from "@pibbl/core/textures";
const width = 360, height = 240;const canvas = document.createElement("canvas");canvas.width = width;canvas.height = height;canvas.style.touchAction = "none";document.body.append(canvas);const enabled = signal(true);const toggle = document.createElement("input");toggle.type = "checkbox";toggle.checked = true;toggle.onchange = () => enabled.set(toggle.checked);const label = document.createElement("label");label.append(toggle, "Refraction + reflections");document.body.append(label);function Waves() { const options: WaterWavesOptions = { seed: 7, speed: 2.4, scale: 10, rippleStrength: 1.2, }; const water = useTexture(waterWaves(options), { resolution: { width, height }, }); const map = water.paint({ mode: "stretch" }); const region = { x: 0, y: 0, width, height }; const filters = [ displacement({ map, strength: 8, region }), reflectedLight({ map, region, source: "#ffffff", opacity: 0.65, direction: [-0.6, -0.8], }), ]; const send = (x: number, y: number) => { const message: WaterWavesMessage = { type: "ripple", x: Math.max(0, Math.min(1, x / width)), y: Math.max(0, Math.min(1, y / height)), }; water.send(message); }; return ( <> <Group style={{ filter: enabled.get() ? filters : undefined }}> <Rectangle style={{ width, height, fill: "#c3e7e8" }} /> {Array.from({ length: 54 }, (_, i) => ( <Rectangle key={i} style={{ left: (i % 9) * 40 + 2, top: Math.floor(i / 9) * 40 + 2, width: 36, height: 36, fill: (i + Math.floor(i / 9)) % 2 ? "#1d8597" : "#80c4ce", }} /> ))} <Circle style={{ cx: 180, cy: 120, radius: 65, fill: "#1d3948", stroke: "#f2d069", strokeWidth: 8, }} /> <Text style={{ left: 180, top: 133, font: "bold 38px sans-serif", textAlign: "center", fill: "#ffffff", }} > Pibbl </Text> </Group>
<Rectangle style={{ width, height, fill: "#00000000", cursor: "crosshair" }} onPointerDown={(event) => { event.currentTarget.setPointerCapture(event.pointerId); send(event.x, event.y); }} onPointerUp={(event) => event.currentTarget.releasePointerCapture(event.pointerId) } /> </> );}const controller = pibbl(canvas, <Waves />);window.addEventListener("pagehide", () => controller.dispose(), { once: true });Usage notes
Section titled “Usage notes”- Press anywhere on the image to add a ripple at that position. Turn off Refraction + reflections to see the undistorted source. Scale 10 produces finer periodic waves; speed 2.4 animates them more quickly. Both filters share the same numeric wave map and region.
Documentation version
Section titled “Documentation version”Documentation built with @pibbl/core 0.0.2, revision 272a94a. ALPHA — NOT FOR PRODUCTION USE.