
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.
5.4 KB Gzipped
Zero runtime dependencies. Only 6 files installed — nothing beyond React as a peer dependency. 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.