Skip to content

Refract and light water

Read as Markdown

Compare an original tiled subject, displacement, reflected light, and their combined result.

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, useTexture } from "@pibbl/core";
import {
displacement,
reflectedLight,
type PibblDisplacementFilterOptions,
type PibblReflectedLightFilterOptions,
type PibblReflectedLightSource,
} from "@pibbl/core/filters";
import { waterWaves } from "@pibbl/core/textures";
function Scene({
mode,
}: {
mode: "original" | "displacement" | "light" | "both";
}) {
const waves = useTexture(waterWaves({ seed: 7, speed: 3 }));
const map = waves.paint({ mode: "stretch" });
const region = { x: 0, y: 0, width: 224, height: 156 };
const refraction: PibblDisplacementFilterOptions = {
map,
region,
strength: 12,
};
const lightColor: PibblReflectedLightSource = "#ffffff";
const highlights: PibblReflectedLightFilterOptions = {
map,
region,
source: lightColor,
opacity: 0.65,
direction: [-0.6, -0.8],
};
const filters =
mode === "original"
? []
: mode === "displacement"
? [displacement(refraction)]
: mode === "light"
? [reflectedLight(highlights)]
: [displacement(refraction), reflectedLight(highlights)];
return (
<Group style={{ filter: filters }}>
<Rectangle style={{ width: 224, height: 156, fill: "#165165" }} />
{Array.from({ length: 35 }, (_, i) => (
<Rectangle
key={i}
style={{
left: (i % 7) * 32 + 2,
top: Math.floor(i / 7) * 32 + 2,
width: 28,
height: 28,
fill: "#79bac5",
}}
/>
))}
<Circle
style={{
cx: 112,
cy: 78,
radius: 40,
fill: "#e4b852",
stroke: "#fff",
strokeWidth: 4,
}}
/>
</Group>
);
}
const grid = document.createElement("div");
grid.style.cssText =
"display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;max-width:480px";
document.body.append(grid);
const comparisons = [
["Original", "original"],
["Displacement", "displacement"],
["Reflected light", "light"],
["Both filters", "both"],
] as const;
const controllers = comparisons.map(([label, mode]) => {
const figure = document.createElement("figure");
figure.style.margin = "0";
const caption = document.createElement("figcaption");
caption.textContent = label;
const canvas = document.createElement("canvas");
canvas.width = 224;
canvas.height = 156;
figure.append(caption, canvas);
grid.append(figure);
return pibbl(canvas, <Scene mode={mode} />);
});
window.addEventListener(
"pagehide",
() => controllers.forEach((controller) => controller.dispose()),
{ once: true },
);
  • The map is a mount-owned texture; both filters use the same local region. Waves run at speed 3 so motion is clear. This comparison is automatic; Ripple a wave map demonstrates pointer-driven ripples.

Documentation built with @pibbl/core 0.0.2, revision 2dccb19. ALPHA — NOT FOR PRODUCTION USE.