said FRAN-kah
An image gallery library that makes pictures move like the real thing.
Use it for your sliders, image grids, galleries and more.
- A slider
- A lightbox
- A strip with a ruler
- Zero dependencies
- React
processionThe slider
A native scroll-snap track: the swipe is the browser's own, 1:1 with momentum. Photos past the first load as it comes near.
import { procession, unfurl } from "frankaa";
import "frankaa/style.css";
const items = [{ src: "/a-800.jpg", full: "/a.jpg", alt: "Terrace" }, "/b.jpg", "/c.jpg"];
const slider = procession(card, items, {
label: "Sea terrace",
onSelect: (i) => unfurl(items, { start: i, origin: (n) => slider.image(n), onChange: (n) => slider.go(n, false) }),
});
"use client";
import { useRef } from "react";
import { Procession, useUnfurl } from "frankaa/react";
import "frankaa/style.css";
export function Card({ items }) {
const slider = useRef(null);
const lightbox = useUnfurl(items, { origin: (n) => slider.current?.image(n) ?? null, onChange: (n) => slider.current?.go(n, false) });
return <Procession ref={slider} items={items} label="Sea terrace" onSelect={(i) => lightbox.open(i)} />;
}
unfurlThe lightbox
The photo lifts out of its spot and springs to full view. Swipe like a strip of film, pinch or double tap to zoom, pull down to close.
import { unfurl } from "frankaa";
thumbs.forEach((img, i) => img.closest("button").addEventListener("click", () =>
unfurl(items, { start: i, origin: (n) => thumbs[n], effect: "displacement" })));
const lightbox = useUnfurl(items, { origin: (n) => refs.current[n] ?? null });
// <button onClick={() => lightbox.open(i)}><img ref={(el) => (refs.current[i] = el)} ... /></button>
drumline (dondo, the talking drum)The strip
A strip of pictures under a ruler of ticks. Drag or flick it, scroll either way, run along the ruler. The picture in focus grows; a tap opens it.
import { drumline } from "frankaa";
drumline(el, items, { preset: "ruler" }); // ticks, story cards, WebGL bend
drumline(el, items, { preset: "numbers", fluid: "lerp" }); // "28 [29] 30", tall bars
drumline(el, items, { preset: "minimal", colorFocus: true, onChange: (i) => {} });
import { Drumline } from "frankaa/react";
<Drumline items={items} preset="ruler" onChange={(i) => setAt(i)} />
togetherOne list, one option
Every part takes the same items. Each picks the file it needs: src for the slider, full for the lightbox, thumb for strips.
unfurl(items, { start: i, strip: "ruler" }); // the lightbox with a drumline filmstrip
unfurl(items, { strip: { preset: "numbers", fluid: "off" } }); // any drumline options
drumline(el, items, { lightbox: { effect: "ripple", strip: "minimal" } }); // a tap opens the lightbox
const lightbox = useUnfurl(items, { strip: "ruler" });
<Drumline items={items} preset="minimal" />
effectsBetween two photos
Built-in shaders, or your own. Each one plays here when you open it. Without WebGL the CSS renderer stands in.
playgroundTry every option
The demos on this page follow these settings. Events print below as they fire.
Write a shader
- Open a photo or move a strip to see events.
for AI toolsPoint your assistant here
Plain files with the whole API, the recipes and the rules, shipped in the package too.