Open-source project
scribble-rs/scribble.rs avatar
scribble-rs/scribble.rs

Scribble.rs: self-hosting a WebSocket pictionary server in Go

The free and privacy respecting pictionary game - Play at https://scribblers.bios-marcel.link

657 stars217 forksGoBSD-3-Clause

At a glance

What is it?
Scribble.rs is a Go server that runs a browser pictionary game over WebSockets, with no accounts and no ads. It is easy to start with Docker, but the interesting parts are the reverse proxy requirement, the thin metrics endpoint and the small set of documented configuration keys.
Who is it for?
Adopt Scribble.rs if you want a small Go binary or container that serves a multiplayer drawing game and you already run a reverse proxy that can be configured for WebSockets. Do not adopt it if you need per-room moderation tooling, persistent accounts or a mature metrics surface; the README itself says the Prometheus endpoint at /v1/metrics does not expose a lot of information.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 9 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem Scribble.rs solves, and for whom

Scribble.rs is a pictionary game that runs in the browser and needs no account. The README describes it as an alternative to skribbl.io and states two properties directly: there are no advertisements and no account is required to play. Those two sentences define the audience. It is for people who want to play a drawing and guessing game with a group and do not want to hand over an email address or sit through ad slots to do it.

The second audience is the self-hoster. The repository carries the topics self-hosted and selfhosted, and the README lists three live instances: the official one at scribblers.bios-marcel.link, plus scribble.bixilon.de and scribble.drifty.win, the latter described as maintained for better latency in Asia. That list is the clearest signal of intended use. The project expects multiple independent deployments, and the README explicitly invites people to host their own instance and add it to that list.

A note on the official instance is worth reading before judging responsiveness: the README says it may not respond instantly because it automatically shuts down if no traffic is received. That is a hosting choice, not a property of the software, but it shapes the first impression of anyone who clicks through from the repository.

What the Go server actually runs

The build target is a single binary. The README's build instructions are `go build ./cmd/scribblers`, which produces a portable executable named `scribblers` on Linux and macOS, or `scribblers.exe` on Windows. The Go module requires version 1.25.0 or later, and git is listed as the other dependency, with the note that a downloaded .zip works too.

The transport is WebSockets. That is not stated as an architectural claim in the README so much as a deployment constraint: the nginx section says that because Scribble.rs uses WebSockets, a reverse proxy in front of it must be configured to support them, and points to a wiki page with an example configuration. Any other reverse proxy, the README adds, may need similar configuration. So the data flow that matters operationally is a long-lived upgraded connection per player, not a request and response cycle.

Configuration is read from environment variables or a `.env` file in the working directory. The README table lists PORT (HTTP port, default 8080, marked required), NETWORK_ADDRESS (TCP address the server listens to, no default given), ROOT_PATH (the path after your domain that the server listens to), CORS_ALLOWED_ORIGINS (default `*`), CORS_ALLOW_CREDENTIALS, LOBBY_CLEANUP_INTERVAL (default 90s) and LOBBY_CLEANUP_PLAYER_INACTIVITY_THRESHOLD (default 75s). For anything more current, the README redirects to internal/config/config.go. That redirect is honest but also a hint: the table is a summary, and the source file is the authority.

The two cleanup keys are the most revealing entries. They imply server-side lobby state that is swept on an interval, with players removed after a period of inactivity. The default threshold of 75 seconds sits below the 90 second sweep interval, so a player who goes quiet for a little over a minute can be collected on the next pass. On a slow connection or during a long round, that is the setting most likely to surprise an operator.

Getting an instance up: Docker first, source second

The README recommends Docker, on the grounds that it rules out almost all compatibility issues. Images are built only on tagged pushes from version 0.8.5 onward; each git tag becomes a Docker tag, and `latest` always points to the most recent GitHub release. The pull command is `docker pull biosmarcel/scribble.rs:latest`. A separate `biosmarcel/scribble.rs:windows-latest` tag exists for native Windows containers, and the README says to use the Linux variant otherwise, since that is the default mode on Windows.

The run command is a single line:

`docker run --pull always --env PORT=8080 -p <port>:8080 biosmarcel/scribble.rs:latest`

The README gives `-p 80:8080` as a concrete example. It also notes that the internal 8080 can be changed but normally should not be, which is consistent with the container expecting that port unless you say otherwise. Because `PORT` is marked required in the configuration table, passing it explicitly is the safe habit even though the default is 8080.

Building from source is two commands after the clone: `cd scribble.rs` then `go build ./cmd/scribblers`. Pre-compiled binaries are also available in the Releases section, with per-commit artifacts that expire after a certain time. The README attaches a caveat to those binaries: they might not be compatible with your system, in which case use Docker or compile them yourself. That caveat is worth taking literally, since a Go binary built for the wrong platform or libc will fail at startup rather than degrade gracefully.

The reverse proxy is not optional plumbing

Most of the operational difficulty in a Scribble.rs deployment sits in front of the process, not inside it. The README devotes a short section to nginx for one reason: WebSocket upgrades need explicit proxy configuration, and the example lives on a wiki page rather than in the repository. If your proxy terminates the upgrade incorrectly, the game will not work, and the failure will look like a client problem rather than a proxy problem.

The same section notes that other reverse proxies may require similar configuration and invites contributions of working configurations to the wiki. That is a fair description of the current state: nginx is documented, everything else is on you. If you run Caddy, Traefik or a cloud load balancer, expect to work out the upgrade handling yourself.

Two configuration keys interact with the proxy layer. ROOT_PATH changes the path after your domain that the server listens to, which matters if you mount the game under a subpath rather than at the root. NETWORK_ADDRESS sets the TCP address the server listens to and has no default in the README table, so the binding behaviour is something to confirm in internal/config/config.go rather than assume. CORS_ALLOWED_ORIGINS defaults to `*`, which is the permissive setting; if you serve the game from a specific origin, narrowing that value is a change you make deliberately, not one the defaults make for you.

Metrics, moderation and the limits of what is exposed

There is a Prometheus endpoint at `/v1/metrics`. The README is unusually direct about it: it currently does not expose a lot of information, and the author offers to extend it on request as long as no personal data is exposed. A dashboard exists but is not public, because the hoster, fly.io, does not support public dashboards. So an operator gets an endpoint that exists and is scrapeable, but should not plan a monitoring strategy around what it currently reports. Check the endpoint on your own instance before wiring alerts to it.

The privacy posture is consistent with the no-account design, but the README does not document moderation features, room administration, or what happens when a lobby turns hostile. Nothing in the supplied material describes reporting, kicking or banning. If you plan to run a public instance, that gap is the one to investigate first, because a game where anyone can join anonymously will eventually need an answer to it.

The README also notes that the community Discord exists but is not very active. For a self-hoster looking for help with an unusual proxy setup, that is relevant context about how quickly a question will be answered.

How it differs from skribbl.io

The README names skribbl.io as the thing Scribble.rs is an alternative to, and the difference it emphasizes is not gameplay. It is the absence of advertisements and the absence of an account requirement. skribbl.io is a hosted service; you go to the site and play. Scribble.rs is a Go program you can run yourself, which is why the README spends its length on Docker pulls, environment variables, build commands and reverse proxy notes rather than on game rules.

That difference cuts both ways. A hosted service carries no operational burden for the player and no infrastructure cost for anyone who just wants a game. Scribble.rs moves that burden to whoever runs the instance, in exchange for control over the deployment, the data and the path. The community instance list is the practical middle ground the project offers: if you do not want to operate anything, you can play on someone else's deployment, though the README gives no guarantees about uptime, capacity or moderation on those instances.

Compared with a generic web application, the WebSocket dependency is the other real distinction. A stateless HTTP service can be dropped behind almost any proxy and scaled horizontally without much thought. A game built on long-lived upgraded connections is a different operational shape, and the nginx section is the documentation acknowledging that.

Maintenance, releases and the licence

The project is active, not archived. The most recent release in the supplied material is v0.9.14, dated 2026-05-31, with v0.9.13 the same day and v0.9.12 in February 2026. The last push to the default branch, master, is dated 2026-09-06, so commits have continued past the last tagged release.

That release cadence has a practical consequence for Docker users. Since images are built only on tagged pushes, `latest` tracks GitHub releases, not master. If you want a fix that landed after v0.9.14, the container route will not give it to you until the next tag; building from source with `go build ./cmd/scribblers` will. The `--pull always` flag in the documented run command means each restart checks for a newer image, which is convenient but also means an unattended restart can move you to a new release without a deliberate decision.

The licence is BSD-3-Clause. That is a permissive licence, and the repository's own credits section shows the project taking attribution seriously for third-party resources, noting that not every one of them requires it under its own terms. For anyone planning to redistribute a modified build or run a public instance, read the licence text and the credits section together; this article is not legal advice, and the obligations that attach to your distribution are a question for your own review. The Go version floor of 1.25.0 or later is the other upgrade cost to plan for: a build environment pinned to an older toolchain will fail before anything else does.

Editorial conclusion

Adopt Scribble.rs if you want a small Go binary or container that serves a multiplayer drawing game and you already run a reverse proxy that can be configured for WebSockets. Do not adopt it if you need per-room moderation tooling, persistent accounts or a mature metrics surface; the README itself says the Prometheus endpoint at /v1/metrics does not expose a lot of information. Before deploying, verify three things against your own setup: that your nginx or equivalent passes the WebSocket upgrade, how PORT, NETWORK_ADDRESS and ROOT_PATH interact with your proxy path, and whether the LOBBY_CLEANUP_INTERVAL and LOBBY_CLEANUP_PLAYER_INACTIVITY_THRESHOLD defaults fit how your players idle between rounds.

Official sources

  1. Issues
  2. License: BSD-3-Clause
  3. README
  4. Releases
  5. scribble-rs/scribble.rs on GitHub
Community notes

Community notes