High-performance infinite canvas library for React with WebAssembly-powered rendering. Handle 2000+ media items at 60 FPS.
npm install @convadraw/cloudgridA high-performance, infinite canvas library for React with WebAssembly-powered rendering
CloudGrid is a production-ready React library for building infinite canvas applications with support for images, videos, and text. Built with performance in mind, it uses WebAssembly (AssemblyScript) for critical operations and Web Workers for non-blocking rendering.



- ๐ High Performance: WebAssembly-powered canvas operations
- ๐จ 2000+ Items: Handle thousands of media items smoothly
- ๐ Undo/Redo: Full history management with batch operations
- ๐ฏ Smart Selection: Single and multi-select with rubber band selection
- ๐ Grid Snapping: Configurable grid with dynamic visual feedback
- ๐ Smooth Zoom: Animated camera controls with easing
- ๐ญ LOD System: Level-of-detail rendering for optimal memory usage
- ๐งต Web Workers: Non-blocking grid rendering and image loading
- ๐จ Color Sorting: Sort media by dominant RGB colors
- ๐ฆ TypeScript: Full type safety and IntelliSense support
- ๐จ Customizable UI: Optional toolbar with Tailwind CSS styling
- โฟ Accessible: Keyboard shortcuts for common operations
``bash`
npm install @convadraw/cloudgrid
Peer Dependencies:
`bash`
npm install react react-dom
`tsx
import { CloudGrid } from '@convadraw/cloudgrid';
import '@convadraw/cloudgrid/cloudgrid.css';
function App() {
return (
$3
`tsx
import { CloudGrid, useCamera, selectItems, zoomToSelected } from '@convadraw/cloudgrid';
import '@convadraw/cloudgrid/cloudgrid.css';function App() {
const camera = useCamera();
const handleFocusCenter = () => {
camera.animateToPosition(0, 0, 1, 500);
};
const handleZoomIn = () => {
camera.zoom(1.2);
};
return (
);
}
`$3
`tsx
import { CloudGrid } from '@convadraw/cloudgrid';
import '@convadraw/cloudgrid/cloudgrid.css';function App() {
return (
toolbarPosition="top-left"
statsPanelPosition="top-right"
/>
);
}
`๐ฏ Core Concepts
$3
CloudGrid uses a centralized camera system for viewport management:
`tsx
import { useCamera } from '@convadraw/cloudgrid';function MyComponent() {
const camera = useCamera();
// Current state
console.log(camera.scale); // Current zoom level (1 = 100%)
console.log(camera.stagePos); // Camera position {x, y}
// Basic controls
camera.zoom(1.5); // Zoom by factor
camera.zoomTo(2.0); // Zoom to specific scale
camera.pan(100, -50); // Pan by delta
camera.resetView(); // Reset to origin
// Animated controls
camera.animateToPosition(x, y, scale, duration);
camera.zoomToFit(bounds, padding, duration);
}
`$3
`tsx
import { selectItems, zoomToSelected } from '@convadraw/cloudgrid';// Programmatically select items
selectItems(['img-1', 'img-2', 'img-3']);
// Zoom to selected items
zoomToSelected();
// Delete selected items
deleteSelected();
`$3
`tsx
import { addMedia, sortByColor } from '@convadraw/cloudgrid';// Trigger file upload
addMedia();
// Sort by dominant colors (RGB gradient)
sortByColor();
`๐ API Reference
$3
####
Main canvas component.
Props:
-
toolbarPosition?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'
- Position of the tools toolbar (default: 'top-left')
- statsPanelPosition?: 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'
- Position of the stats/controls panel (default: 'top-right')Example:
`tsx
toolbarPosition="bottom-left"
statsPanelPosition="top-right"
/>
`$3
####
useCamera()Access camera controls and state.
Returns:
`typescript
interface CameraControls {
scale: number;
stagePos: { x: number; y: number };
setScale: (scale: number) => void;
setStagePos: (pos: { x: number; y: number }) => void;
zoom: (factor: number, centerX?: number, centerY?: number) => void;
zoomTo: (newScale: number, centerX?: number, centerY?: number) => void;
pan: (dx: number, dy: number) => void;
resetView: () => void;
animateToPosition: (x: number, y: number, targetScale?: number, duration?: number) => void;
zoomToFit: (bounds: { x: number; y: number; width: number; height: number }, padding?: number, duration?: number) => void;
}
`$3
####
selectItems(ids: string[])
Programmatically select items by their IDs.####
zoomToSelected()
Animate camera to fit currently selected items in view.####
zoomToBounds(bounds, padding?, duration?)
Animate camera to specific bounds.####
addMedia()
Trigger the file upload dialog.####
deleteSelected()
Delete currently selected items.####
sortByColor()
Sort all items by dominant RGB colors (creates diagonal gradient).๐จ Styling
CloudGrid uses Tailwind CSS with a custom dark theme. The default theme uses
oklch color space for consistent, vibrant colors.$3
You can override the default theme by adding CSS variables:
`css
:root {
--background: oklch(0.09 0.01 255);
--foreground: oklch(0.80 0.19 145);
--primary: oklch(0.40 0.19 145);
/ ... more variables /
}
`See
cloudgrid.css for all available CSS variables.โจ๏ธ Keyboard Shortcuts
| Shortcut | Action |
|----------|--------|
|
Cmd/Ctrl + Z | Undo |
| Cmd/Ctrl + Shift + Z | Redo |
| Scroll | Pan canvas |
| Cmd/Ctrl + Scroll | Zoom in/out |
| Drag (Select Tool) | Rubber band selection |
| Shift + Click | Toggle selection |
| Delete / Backspace | Delete selected |๐๏ธ Architecture
$3
1. WebAssembly: Critical operations (spatial indexing, viewport culling) run in WASM
2. Web Workers: Grid rendering and image processing off main thread
3. LOD System: Dynamic image resolution based on zoom level
4. Viewport Culling: Only visible items are rendered
5. Blob Caching: Compressed images cached in worker, decoded on-demand
6. Batch Operations: Group actions create single undo/redo entries
$3
- React 18 - UI framework
- Konva.js - Canvas rendering
- AssemblyScript - WebAssembly compilation
- Web Workers - Background processing
- Tailwind CSS - Styling
- TypeScript - Type safety
๐ Performance
- โ
2000+ media items at 60 FPS
- โ
<400MB memory usage with 2000 high-res images
- โ
Smooth animations with hardware acceleration
- โ
Non-blocking operations via Web Workers
- โ
Instant undo/redo for all operations
๐ค Examples
$3
`tsx
import { CloudGrid, useCamera } from '@convadraw/cloudgrid';
import { useEffect } from 'react';function App() {
useEffect(() => {
// Listen for custom events
window.addEventListener('items-added', (e) => {
const event = e as CustomEvent;
selectItems(event.detail.ids);
zoomToSelected();
});
}, []);
return ;
}
`$3
`tsx
import { CloudGrid, useCamera } from '@convadraw/cloudgrid';
import { useEffect } from 'react';function App() {
const camera = useCamera();
useEffect(() => {
const handleKeyPress = (e: KeyboardEvent) => {
if (e.key === 'f') zoomToSelected();
if (e.key === 'r') camera.resetView();
if (e.key === 'Home') camera.animateToPosition(0, 0, 1);
};
window.addEventListener('keydown', handleKeyPress);
return () => window.removeEventListener('keydown', handleKeyPress);
}, [camera]);
return ;
}
`$3
`tsx
import { CloudGrid, useCamera, addMedia, sortByColor } from '@convadraw/cloudgrid';function App() {
const camera = useCamera();
return (
Zoom: {Math.round(camera.scale * 100)}%
);
}
`๐ง Advanced Usage
$3
CloudGrid automatically handles uploaded images. For advanced use cases, you can dispatch custom events:
`tsx
window.dispatchEvent(new CustomEvent('add-item', {
detail: {
type: 'image',
src: 'https://example.com/image.jpg',
x: 0,
y: 0,
width: 400,
height: 300,
}
}));
`๐ Troubleshooting
$3
- Ensure CORS is enabled for external images
- Check browser console for network errors
- Verify image URLs are accessible$3
- Reduce number of items (recommended: <2000)
- Use lower resolution images
- Check if hardware acceleration is enabled in browser$3
- Ensure @types/react and @types/react-dom` are installedMIT ยฉ 2026
- Inspired by tldraw
- Built with Konva.js
- Icons by Phosphor Icons
- Styled with Tailwind CSS
- Documentation
- Demo
- Issues
- Changelog
---
Made with โค๏ธ by the CloudGrid team