This application is a whiteboard editor built using tldraw, Next.js, and tRPC for type-safe API implementation.
- The PostgreSQL database on Render's free tier may experience cold starts, meaning the first connection after a period of inactivity might take a few seconds to establish
- The OpenAI API key used in production is on the free tier, which means the AI image generation feature will not work in the deployed version, but it will in a local built one
The application is deployed on:
- Frontend: Vercel (https://whiteboard-indol-nine.vercel.app)
- Database: PostgreSQL on Render
To deploy your own instance:
- Fork this repository
- Create a new project on Vercel and connect it to your repository
- Set up a PostgreSQL database on Render
- Configure the following environment variables in Vercel:
DATABASE_URL: Your Render PostgreSQL connection stringOPENAI_API_KEY: Your OpenAI API key
- Deploy!
- Next.js: App router for robust server-side rendering and API routes
- TailwindCSS: Utility-first CSS framework for styling
- Shadcn UI: Component library built on top of Tailwind for consistent design
- tRPC: End-to-end typesafe API layer
- tldraw: Feature-rich drawing library
- Prisma: Type-safe ORM for database operations
- PostgreSQL: Database for storing whiteboard data
- OpenAI: AI integration for image generation
- Create and manage multiple whiteboards
- Real-time saving of whiteboard state
- Shape styling controls (color, fill, stroke style)
- Export drawings as SVG
- Persistent storage of whiteboard data in PostgreSQL
- Type-safe API endpoints for retrieving and storing data
- AI-powered image generation for whiteboard elements
- Custom UI with tools panel, styles panel, and AI panel
- Node.js (v18 or higher)
- PostgreSQL database
- Clone this repository
git clone <repository-url>
cd whiteboard- Install dependencies
npm install- Set up environment variables
Create a .env file in the root directory with the following:
DATABASE_URL="postgresql://username:password@localhost:5432/whiteboard_db"
OPENAI_API_KEY="your-openai-api-key" # Required for AI image generation
- Run Prisma migrations to set up your database
npx prisma migrate dev --name init- Start the development server
npm run dev- Open http://localhost:3000 in your browser
The application uses tRPC for type-safe API calls. The main endpoints are:
drawing.getDrawing: Retrieves a specific whiteboard by IDdrawing.saveDrawing: Saves the current state of a whiteboarddrawing.listDrawings: Lists all available whiteboardsdrawing.deleteDrawing: Deletes a specific whiteboardopenAI.generateImage: Generates images using AI based on text prompts
The application uses tRPC for type-safe API calls. Here's how to test the API endpoints:
- Navigate to the whiteboard list page at http://localhost:3000/whiteboard
- Create a new whiteboard or select an existing one
- Make changes to the whiteboard and observe that they are automatically saved
- Check the browser's developer tools Network tab to see the tRPC API calls
You can test the API endpoints directly using cURL:
curl -X GET http://localhost:3000/api/trpc/drawing.listDrawings \
-H "Content-Type: application/json"curl -X GET http://localhost:3000/api/trpc/drawing.getDrawing \
-H "Content-Type: application/json" \
-d '{"json":{"0":{"json":"your-whiteboard-id"}}}'curl -X POST http://localhost:3000/api/trpc/drawing.saveDrawing \
-H "Content-Type: application/json" \
-d '{"json":{"0":{"json":{"id":"your-whiteboard-id","content":{"schemaVersion":1,"document":{},"session":{}}}}}}'curl -X POST http://localhost:3000/api/trpc/drawing.deleteDrawing \
-H "Content-Type: application/json" \
-d '{"json":{"0":{"json":"your-whiteboard-id"}}}'curl -X POST http://localhost:3000/api/trpc/openAI.generateImage \
-H "Content-Type: application/json" \
-d '{"json":{"0":{"json":{"prompt":"A happy dog playing with a ball"}}}}'You can also test the API calls programmatically using the tRPC client:
import { trpc } from '@/utils/trpc';
// List all whiteboards
const drawings = await trpc.drawing.listDrawings.query();
// Get a specific whiteboard
const drawing = await trpc.drawing.getDrawing.query('your-whiteboard-id');
// Save a whiteboard
const result = await trpc.drawing.saveDrawing.mutate({
id: 'your-whiteboard-id',
content: {
schemaVersion: 1,
document: {},
session: {}
}
});
// Delete a whiteboard
const deleteResult = await trpc.drawing.deleteDrawing.mutate('your-whiteboard-id');
// Generate an image using AI
const imageResult = await trpc.openAI.generateImage.mutate({
prompt: 'A happy dog playing with a ball'
});/app: Next.js app directory with page components/whiteboard: Whiteboard list page/whiteboard/[uuid]: Dynamic route for individual whiteboards/api: API routes
/components: Reusable UI components/tldraw: Custom tldraw UI components and tools/ui: Shadcn UI components/layout: Layout components/buttons: Button components/cards: Card components/lists: List components/skeletons: Loading skeleton components
/server: Server-side code/routers: tRPC router definitions/api: API route handlers/trpc.ts: tRPC server configuration/prisma.ts: Prisma client configuration/context.ts: tRPC context definition/actions.ts: Server actions/openAiClient.ts: OpenAI client configuration
/prisma: Database schema and migrations/hooks: Custom React hooks for whiteboard functionality/useDeleteKey.ts: Hook for handling delete key press/useImageUploader.ts: Hook for image upload functionality/useImageGeneration.ts: Hook for AI image generation
/utils: Utility functions/trpc.tsx: tRPC client configuration/uuidGenerator.ts: UUID generation utility
/lib: Library code/utils.ts: General utility functions
/data: Sample data/drawings.json: Sample drawing data
- Auto-saving: Changes to the whiteboard are automatically saved to the database
- Style Controls: Customize colors, fills, and stroke styles of shapes
- AI Integration: Generate images from text descriptions using OpenAI
- Status Indicators: Visual feedback when saving or encountering errors
- Shape Styling: Buttons to modify shape appearance (colors, fills, strokes)
- The application uses tRPC's optimistic updates for a smoother user experience
- The whiteboard state is persisted in PostgreSQL using a JSON data type
- Error handling is implemented at both client and server levels