AI-powered collaborative presentation builder — think Figma canvas meets Google Slides, with live data connectors and Claude-generated insights.
Live demo → · Register for free · No credit card required
- Drag-and-drop elements — text, shapes, images, charts, arrows
- Real-time collaboration via Yjs CRDT — multiple users, live cursors, zero conflict
- Undo/redo with Yjs UndoManager (Cmd+Z / Cmd+Shift+Z)
- Rubber-band multi-select, snap-to-element guides, aspect-ratio lock (Shift+resize)
- Keyboard shortcuts: Delete, Arrow nudge (1px / 10px with Shift), Cmd+D duplicate, Escape
- CSV, Salesforce, BigQuery data connectors — live data bound to chart elements
- ECharts-powered charts: bar, line, area, pie, scatter
- Stale-data badges with one-click refresh
- Filter & query your data directly in the slide panel
- Per-slide AI analysis powered by claude-haiku-4-5
- Chart-aware insights that understand your data
- Streaming responses with cancel support
- Verify insight freshness — stale detection when data changes
- Fullscreen slides with keyboard navigation
- Speaker notes panel (toggle on/off)
- Auto-refresh slides from live data sources during presentation
- PDF export via Puppeteer (async, background job)
- PPTX export via pptxgenjs
- Download token system — no auth required for downloads
- Export status polling with toast notifications
- Workspaces with OWNER / EDITOR / VIEWER roles
- Email invitations to workspaces
- Public share links with configurable roles and expiry
- Share view is read-only, with insight generation support
| Layer | Tech |
|---|---|
| Framework | Next.js 16 App Router, TypeScript |
| Styling | Tailwind CSS v4, shadcn/ui (base-ui v3) |
| Real-time | Yjs CRDT, y-websocket v2 |
| State | Zustand v5 |
| Charts | ECharts v6 |
| AI | Anthropic SDK, claude-haiku-4-5 |
| Database | PostgreSQL, Prisma 7 (driver adapters) |
| Auth | NextAuth 4, bcryptjs |
| Exports | Puppeteer (PDF), pptxgenjs (PPTX) |
| Tests | Vitest |
- Node.js 20+
- PostgreSQL 14+ (or use Docker)
- An Anthropic API key
git clone https://github.com/FRAME-Project/frame.git
cd frame
npm installWith Docker:
docker compose up -d postgresOr set up manually:
CREATE USER frame_user WITH PASSWORD 'frame_pass123';
CREATE DATABASE frame_db OWNER frame_user;cp .env.example .env.localEdit .env.local:
DATABASE_URL="postgresql://frame_user:frame_pass123@localhost:5432/frame_db"
NEXTAUTH_SECRET="your-random-secret-here" # openssl rand -base64 32
NEXTAUTH_URL="http://localhost:3000"
ANTHROPIC_API_KEY="sk-ant-..."Generate a secret:
openssl rand -base64 32npx prisma migrate deploy
# or for a fresh dev setup:
npx prisma db push# Terminal 1 — Yjs WebSocket server (real-time collaboration)
npm run ws
# Terminal 2 — Next.js dev server
npm run devOpen http://localhost:3000, register an account, and start building.
npm run buildOn low-RAM machines (< 2GB):
NODE_OPTIONS="--max-old-space-size=1536" npm run build
# WebSocket server (background)
npm run ws &
# Next.js production server
npm start| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL connection string |
NEXTAUTH_SECRET |
Yes | Random 32-byte secret |
NEXTAUTH_URL |
Yes | Public URL of the app (e.g. https://frame.example.com) |
ANTHROPIC_API_KEY |
Yes | Anthropic API key for AI insights |
NEXT_PUBLIC_YJS_WS_URL |
No | WebSocket server URL (default: ws://localhost:1234) |
YJS_WS_PORT |
No | WebSocket server port (default: 1234) |
NEXT_PUBLIC_YJS_WS_URLmust point to your public WebSocket server. It is baked into the client bundle at build time.
frame/
├── src/
│ ├── app/ # Next.js App Router
│ │ ├── (app)/ # Authenticated routes
│ │ │ ├── dashboard/ # Deck listing
│ │ │ ├── deck/[id]/edit/ # Canvas editor
│ │ │ ├── deck/[id]/present/ # Presentation mode
│ │ │ └── workspace/ # Workspace settings
│ │ ├── (auth)/ # Login / register / reset
│ │ └── api/ # API routes
│ ├── components/
│ │ ├── canvas/ # Editor canvas, elements, toolbar, panels
│ │ └── sidebar/ # Slide sidebar + thumbnails
│ ├── hooks/ # useYArray, useYMap (Yjs ↔ React bridge)
│ ├── lib/ # Prisma client, auth, canvas helpers
│ └── store/ # Zustand canvas store
├── server/
│ └── yjs-server.ts # Standalone y-websocket server
└── prisma/
└── schema.prisma # Database schema
npm run dev # Next.js dev server (Turbopack)
npm run ws # Yjs WebSocket server
npm run build # Production build
npm start # Production server
npm test # Vitest unit tests
npm run lint # ESLintnpm test
# or with coverage
npm test -- --coverageEach slide has its own Yjs document, keyed by slideId. The CanvasProvider component creates a WebsocketProvider that connects to the Yjs server. All canvas state (elements Y.Array of Y.Map) is CRDT-backed — no manual conflict resolution needed.
Browser ──WS──► y-websocket server (port 1234)
│
persists Yjs updates
in-memory (dev) / can
be backed by a database
Prisma 7 requires @prisma/adapter-pg — the default engine was removed. The setup in src/lib/db.ts uses PrismaPg with a connection string.
Exports are async jobs:
POST /api/decks/[id]/export→ createsExportJobrecord, triggers background processing- Client polls
GET /api/export-jobs/[jobId]every 2s - On
COMPLETED, user downloads via token-gated URL (no auth required for 1h)
PRs welcome. Please open an issue first for significant changes.
- Fork the repo
- Create a branch:
git checkout -b feat/my-feature - Commit with conventional commits:
feat:,fix:,docs: - Open a PR
MIT
