bentogreed
Version:
A lightweight, framework-agnostic library for generating bento grid layouts
218 lines (168 loc) • 5.59 kB
Markdown
# Bento Grid
A lightweight, framework-agnostic library for generating bento grid layouts. Transform an array of tile areas into optimized rectangular layouts using proven treemap algorithms.
## Features
- 🎯 **Simple API** - Just provide tile areas and canvas dimensions
- 🔄 **Two Algorithms** - Choose between squarified (optimized) or binary (deterministic) layouts
- 📦 **Framework Agnostic** - Pure TypeScript, works with any framework or vanilla JS
- 🎨 **Flexible** - Configurable padding, gutters, and layout strategies
- 📐 **Precise** - Returns exact pixel coordinates for each tile
## Installation
```bash
npm install bentogrid
```
## Quick Start
```typescript
import { computeBentoLayout, BentoGridConfig } from 'bentogrid';
// Define your configuration
const config: BentoGridConfig = {
canvas: {
width: 1024,
height: 640,
padding: 16, // Optional, defaults to 0
},
tiles: [3, 1, 2, 1, 2.5, 1.2, 7.5, 2.34, 1], // Array of tile areas/weights
options: {
strategy: 'squarified', // 'squarified' or 'binary'
gutter: 8, // Optional, spacing between tiles
},
};
// Compute the layout
const layout = computeBentoLayout(config);
// Use the layout
layout.tiles.forEach((tile) => {
console.log(`Tile ${tile.id}:`, tile.rect);
// { x: 16, y: 16, width: 320, height: 200 }
});
```
## Usage Examples
### Basic Usage
```typescript
import { computeBentoLayout } from 'bentogrid';
const layout = computeBentoLayout({
canvas: { width: 800, height: 600 },
tiles: [1, 2, 3, 4],
});
// Access the computed rectangles
layout.tiles.forEach((tile) => {
const { x, y, width, height } = tile.rect;
// Render your tile at these coordinates
});
```
### With React
```tsx
import { computeBentoLayout, BentoGridConfig } from 'bentogrid';
import { useMemo } from 'react';
function BentoGrid({ config }: { config: BentoGridConfig }) {
const layout = useMemo(() => computeBentoLayout(config), [config]);
return (
<div style={{ position: 'relative', width: config.canvas.width, height: config.canvas.height }}>
{layout.tiles.map((tile) => (
<div
key={tile.id}
style={{
position: 'absolute',
left: tile.rect.x,
top: tile.rect.y,
width: tile.rect.width,
height: tile.rect.height,
border: '1px solid #ccc',
}}
>
Tile {tile.id}
</div>
))}
</div>
);
}
```
### With Canvas/SVG
```typescript
const layout = computeBentoLayout({
canvas: { width: 1200, height: 800, padding: 20 },
tiles: [3, 1, 2, 1, 2.5],
options: { strategy: 'squarified', gutter: 10 },
});
// SVG example
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.setAttribute('width', '1200');
svg.setAttribute('height', '800');
layout.tiles.forEach((tile) => {
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect.setAttribute('x', tile.rect.x.toString());
rect.setAttribute('y', tile.rect.y.toString());
rect.setAttribute('width', tile.rect.width.toString());
rect.setAttribute('height', tile.rect.height.toString());
svg.appendChild(rect);
});
```
## API Reference
### `computeBentoLayout(config: BentoGridConfig): BentoGridLayout`
Computes a bento grid layout from the provided configuration.
#### Configuration (`BentoGridConfig`)
```typescript
{
canvas: {
width: number; // Canvas width in pixels
height: number; // Canvas height in pixels
padding?: number; // Optional padding around the grid (default: 0)
};
tiles: number[]; // Array of tile areas/weights (proportional)
options?: {
strategy?: 'squarified' | 'binary'; // Layout algorithm (default: 'squarified')
gutter?: number; // Spacing between tiles (default: 0)
};
}
```
#### Return Value (`BentoGridLayout`)
```typescript
{
rect: {
x: number; // X position of the grid area
y: number; // Y position of the grid area
width: number; // Width of the grid area
height: number; // Height of the grid area
};
tiles: Array<{
id: string; // Unique tile identifier (e.g., "tile-0", "tile-1")
area: number; // Original area value
rect: {
x: number; // X position in pixels
y: number; // Y position in pixels
width: number;// Width in pixels
height: number;// Height in pixels
};
}>;
}
```
## Layout Strategies
### Squarified (Default)
Optimizes for square-like rectangles, minimizing aspect ratios. Best for visual appeal and readability.
```typescript
{ strategy: 'squarified' }
```
### Binary
Uses recursive binary splitting. More deterministic and predictable, but may produce less square-like tiles.
```typescript
{ strategy: 'binary' }
```
## How Tile Areas Work
The `tiles` array contains **proportional areas**. The library automatically normalizes them to fill the available canvas space:
- `[1, 1, 1]` → Three equal-sized tiles
- `[3, 1, 2]` → First tile is 3x larger than the second, 1.5x larger than the third
- `[1, 4, 7.5, 2.34]` → Any positive numbers work as proportions
## Development
```bash
# Install dependencies
npm install
# Run demo
npm run dev
# Build library
npm run build
```
## Architecture
- **Core engine** (`src/layout.ts`): Pure TypeScript layout computation
- **Algorithms** (`src/algorithms/`): Swappable layout strategies (squarified, binary)
- **Types** (`src/types.ts`): TypeScript definitions
- **Demo** (`src/demo/`): React visualization app
## License
MIT