Slate A collaborative whiteboard built for the way classrooms actually work.

How We Built It: Slate runs on tldraw, a best-in-class open-source canvas that gave us shapes, text, and freehand drawing on an infinite surface from day one. Making that canvas truly collaborative is where the hard work started, and where we made a bet that shaped everything else. We built the backend on SpacetimeDB, and it changed how we think about software. SpacetimeDB isn't a database with a REST API bolted on top. It's a relational database that is also the server. You write your logic in Rust, compile it to WebAssembly, and upload it straight into the database. There's no web server, no API routes, no ORM. Clients subscribe to SQL queries and get real-time updates the instant any row changes. That model let us build over 100 custom reducers, atomic transactional functions for every action in the system: create a board, join a class, launch a quiz, cast a poll vote, spotlight a student, flag content. Every client sees the same state, always. We wired SpacetimeDB's subscriptions into tldraw's sync API so strokes, shapes, and cursor positions propagate to every student live. Teachers sign in with Google OAuth 2.0, and students join anonymously with a class code. No account creation, because friction kills adoption in a classroom. On top of that, we layered the features that make Slate a teaching tool rather than a drawing app. There's an AI chat system you invoke directly from the canvas, which sends board context to the model and renders the answer inline. For content safety, we lazily load TensorFlow.js and nsfwjs to run an on-device compliance monitor that flags inappropriate content before it ever reaches the class feed. Google Drive integration pulls Docs and Slides onto the canvas, KaTeX renders math inline, PDF.js handles document uploads, and PhET simulations and Canva embeds work out of the box.

Challenges We Ran Into: Real-time sync at this scale is genuinely hard. tldraw manages a complex internal graph of shape state, and mapping that onto SpacetimeDB's row-based subscription model meant making careful decisions about what to sync, when, and at what granularity. Making it feel instant without flooding the database took real iteration. SpacetimeDB's reducers demand a kind of discipline we weren't used to. They can't touch the network, the filesystem, or even the clock. They have to be fully deterministic. That's the right constraint for a collaborative system, but it broke our first instinct for AI, because you can't call a model from inside a reducer. So we built a separate agent layer that polls for pending jobs, calls the model, and writes the results back into the database. We are also students, not professional engineers. We built this in a sprint, learning SpacetimeDB, tldraw's sync API, and Rust WebAssembly modules largely from scratch. We rearchitected the schema mid-build when our data model didn't match our access patterns. We spent late nights chasing reducers that looked correct but silently panicked. And getting the compliance monitor to load without tanking our bundle size meant lazy-loading the entire TensorFlow stack and only activating it for student sessions.

Accomplishments We're Proud Of: Honestly, opening two browser tabs, drawing a circle in one, and watching it appear instantly in the other. It sounds small. It took days. And when it finally worked, we knew we had something real. Beyond that, we're proud of how complete Slate feels. It isn't a whiteboard with a chat box bolted on. It's a full teaching platform with live quizzes and leaderboards, teacher-controlled spotlighting, real-time polls, class timers, Google Docs and Slides embeds, AI explanations, content moderation, and session snapshots, all living inside one canvas that any teacher could open tomorrow and actually use. We're also proud that students join with zero friction. No account, no download, no setup, just a code and a name. That was a deliberate product decision, and making anonymous identity work cleanly inside SpacetimeDB's auth model took real architectural work.

What We Learned: The gap between a whiteboard app and a whiteboard that works for a real classroom is enormous, and almost all of it lives in the teacher-facing tools. The canvas is table stakes. What makes Slate different is Drop to Class, Spotlight, Polls, Timers, Quizzes, and the AI layer, the infrastructure that lets a teacher actually run a class instead of just sharing a screen. We also learned that SpacetimeDB's database-as-server model is one of the most underrated patterns in real-time collaborative software. Removing the server layer doesn't just cut latency, it deletes an entire category of bugs. And we learned the lesson that's obvious in hindsight: the best products come from building something you needed yourself. Every feature in Slate exists because one of us sat in a classroom and thought, why can't this just work?

What's Next for Slate: The most requested feature we haven't built yet is persistent class history, the ability for a student to replay any moment from a past lesson, scrubbing through board state the way you'd scrub through a video. The snapshot infrastructure is already in the codebase. Turning it into a full replay experience is the next milestone. We also want to make the AI more proactive. Right now it answers questions. We want it to notice when a student's work on their personal slate diverges from the correct approach and offer a nudge, not a correction, just a question. The kind of thing a good teacher does when walking the room. And we want to bring Slate to more subjects. The math and science tooling is strong, but a history class building a timeline on the canvas, or an English class annotating a shared passage in real time, are one or two integrations away. The foundation is already built for it.

Built With

  • code:
  • demo:
  • google-docs-api
  • google-drive-api
  • google-oauth-2.0
  • google-slides-api
  • https://slate-mu-red.vercel.app
  • katex
  • live
  • nsfwjs
  • pdf.js
  • phet-interactive-simulations
  • react
  • rust
  • source
  • spacetimedb
  • tensorflow.js
  • tldraw
  • typescript
  • vite
  • webassembly
Share this project:

Updates