Our pixel-rendered planner with a Rust backend

Just because we're engineers, doesn´t mean we build ALL our applications ourselves. But sometimes inspiration hits and good things happen. So our company planner is now canvas-rendered, has a Rust backend and works like a charm.

Background

Tweede golf is by no means a mega-corporation (there's 18 of us), but keeping track of who works on which project, what they are currently doing and whether they're available to help out on an awesome project next week... is a bit of a hassle on paper.

In 2015, we were old-school and used a whiteboard. No lie. Here's a picture.

Whiteboard

But today (and for a while now), we have a pretty neat online version, home-made, with TypeScript and Rust of course!

The Tech

Where it came from

Once it was decided that the whiteboard had to go, we started developing, mostly in React, with a NodeJS backend, and have since had several versions of this planner called TGenda.

As the company grew, and the number of actual plans to be recorded grew with it, so did the number of DOM elements. This resulted in performance issues for the React/HTML build we were using, because we used the drag-and-drop functionality a lot. This was problematic: we needed that to be smooth, so it was time for a reimplementation.

Wanting to get rid of the DOM elements brought me to the Canvas API, which uses pixels instead, because who doesn't love awesomely fast animations? (More about that later.)

We had previously experienced that maintaining a TypeScript frontend with many dependencies is tricky and tends to bring about security issues. So for the greater good I deciced to challenge myself to not use any runtime dependencies for the frontend at all, except of course for TypeScript itself, as a direct dependency.

The backend was created using Rust with the excellent Axum and SQLX crates.

The current version in Rust

This version has an exceptionally clean and organized codebase:

  • A global state, that is updated through events and a reducer (inspired by redux)
  • State updates trigger a render of the whole canvas
  • Renders are quick - mere milliseconds
  • The Rust backend has the same event type as the frontend, and a bus that several services can listen to
  • A selection of frontend events is also sent to the backend through a websocket connection
  • The backend broadcasts these events to all other clients, creating a live update mechanism
  • The backend runs a service that listens to certain events and turns these into database updates

How it works How it's made: our digital company planner

This event-based mechanism is very flexible; by changing only one line, I was able to make the scroll position a shared state, which means every client then shared a scroll position (for fun, just to test the performance). The combination of a websocket and the Rust backend provides such low latencies that multi-client scrolling is smooth!

The frontend looks similar to this example - try dragging an event to a different day!

Other things I'm happy about:

  • Forms are rendered with HTML, by my own implementation of JSX, without Virtual DOM like in React. This makes the code readable and allows you to easily follow the logic behind it. It delivers excellent performance for our use-cases.
  • The application is only a single Rust binary! All static files (like JavaScript and CSS) are put into this binary at compilation time and served straight from memory.

The best features

And the features that get their own paragraph are confetti 🎉 and the snake 🐍︎ game.

Make confetti to celebrate never having to be bored: Confetti

And then play snake to literally eat your work:

Snake

Stay up-to-date

Stay up-to-date with our work and blog posts?

Related articles

The number of data centers worldwide is constantly increasing, and so is their electricity consumption. One way to become more power-efficient is certainly the constant development of better hardware, but we as developers should do our share. This post shows how coding in Rust can help to use existing resources more efficiently, to help preserve our planet — at least a little bit.
Asynchronous programming is pretty weird. While it is straightforward enough to understand in principle (write code that looks synchronous, but may be run concurrently yada yada yada), it is not so obvious how and when async functions actually perform work. This blog aims to shed light on how that works in Rust.
February 24, 2023

Introducing MailCrab!

MailCrab is an email test server for development, written entirely in Rust.