Realtime canvas with Puppeteer, Go and Typescript



I quickly wrote an app that lets users paint on an HTML5 canvas together.

Puppeteer is used to simulate headless browser users (instead of direct API calls).

If you’ve read any of my gRPC with Typescript and Go posts, you’ll be familiar with the tech – it’s an RPC service with two methods


service DrawService {
  rpc SendDrawing(Drawing) returns (None);
  rpc GetDrawings(None) returns (stream Drawings) {}


Right now, Puppeteer simulates a single user. I’m surprised at how little code is needed to do headless browser testing!

import * as puppeteer from 'puppeteer';

function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('http://localhost:3000');

  console.log("Looping on move...");
  for (let i = 0; i < 1000; i++) {
    await page.mouse.move(Math.random() * 500, Math.random() * 500);
    await sleep(100);
  console.log("Looping on move...done");

  await browser.close();

The source is here.


For fun most of all – I love the HTML5 canvas.

But also because we’ll need some “real” code for upcoming blog posts.

This is a reminder about how hard session management is. I’ve made a couple1 sins2 just to be done in an afternoon. Even languages like Go let you compile a gun to shoot yourself in the foot with.

Stay tuned!

  1. Memory leak – sessions are never reaped ↩︎

  2. Race condition on new sessions ↩︎