Organic gallery layouts
for React
A lightweight component that arranges images into beautiful, organic collages. No grid. No masonry. Just art.
npm install @inkorange/penduWhy Pendu?
Organic Layouts
No grid lines, no rigid columns. Images arrange themselves into natural, gallery-wall collages that fill your container.
Animated Transitions
FLIP animations smoothly move images when the gallery changes. Add, remove, or reorder — every transition feels intentional.
Container Aware
Automatically adapts to any container size — fixed, percentage, or viewport units. Images scale and reflow to fill the space.
Tiny Footprint
~6 KB gzipped. Zero dependencies beyond React. Ships ESM and CJS with full TypeScript types.
CSS Variable Theming
Customize gap, radius, and background via CSS custom properties. No prop drilling needed.
Deterministic Seeds
Same seed + same images = identical layout. Reproducible across renders, servers, and sessions.
Get started in seconds
Basic Usage
import { Pendu } from '@inkorange/pendu';
function Gallery() {
return (
<Pendu gap={12} seed={42}>
<Pendu.Image src="/photo-1.jpg" width={1200} height={800} alt="Sunset" />
<Pendu.Image src="/photo-2.jpg" width={800} height={1200} alt="Portrait" />
<Pendu.Image src="/photo-3.jpg" width={1600} height={1000} alt="Landscape" />
</Pendu>
);
}Dynamic Arrays
import { Pendu } from '@inkorange/pendu';
import { useState } from 'react';
function DynamicGallery({ photos }) {
return (
<Pendu gap={12}>
{photos.map((photo) => (
<Pendu.Image
key={photo.id}
src={photo.src}
width={photo.width}
height={photo.height}
alt={photo.alt}
/>
))}
</Pendu>
);
}CSS Variable Theming
/* Override via CSS variables — no props needed */
.my-gallery {
--pendu-gap: 16px;
--pendu-radius: 8px;
--pendu-bg: #1a1a1a;
}Ready to build?
Explore interactive examples or dive into the API docs.