Two small servers you run yourself

Recognition happens in the visitor's browser, so most of millirec needs no server at all. Two things do — counting votes, and resolving a code someone wrote by hand — and both are yours to run: there is no hosted version. Each is one small folder that runs standalone, in Docker, as a Node library inside a server you already have, or on Cloudflare Workers with nothing to set up.

Widgets server

Reactions and ratings your visitors draw instead of click: a heart, a check, a row of stars. The drawing is read in the visitor's browser; the server counts the vote, once per visitor, with no accounts and no cookies. Drawings shown on the wall are re-checked and drawn by the server itself, so a word or a doodle counts as the vote but never appears on your page.

Standalone

Unzip, then:

npm install
npm start      # :3013

Docker

In the unzipped folder:

docker compose up -d

Node library

In your own Express or http server:

const w = createWidgetsServer(
  { basePath: '/widgets' })
app.use(w.listener)

Cloudflare Workers

Votes in a Durable Object, nothing to create:

npx wrangler deploy

Then, on any page:

<script async src="https://YOUR-SERVER/embed/millirec-widget.js"></script>
<div data-millirec="reactions" data-widget="default" data-target="this-page"></div>
<div data-millirec="ratings" data-widget="default" data-target="this-page"></div>
  • The server's own front page is the editor: your own reactions, colours and symbols, with a snippet and an edit token.
  • A moderation page: every drawing that passed the check, to show, hide or delete — and a switch to hold new drawings for your review instead of showing them at once. It also shows your reaction symbols, so you can check them.
  • Totals without a drawing pad (reactions-count, rating-average), and a badge with no script: /badge/default/this-page.svg.

Embedding in detail →

Codes server

Short codes people write by hand to open a page or join a room — six characters from an alphabet with no lookalikes (no O/0, no l/1/I, no case twins), so the recognizer and the eye both read them right. Written one character on top of the last in a single box, or typed.

  • A code for a page: your app asks for one (a shared puzzle, a document, a checkout); whoever writes it is taken there.
  • A room: a code and a shared JSON state that everyone in it sees change live, plus messages relayed and never stored — strokes, cursors, moves.

Standalone

npm install
npm start      # :3014

Docker

docker compose up -d

Node library

const c = createCodesServer()
const { code } = await c.createCode(
  'https://example.com/puzzle/42')

Cloudflare Workers

Codes, rooms and their live streams in one Durable Object:

npx wrangler deploy

The handwritten code box, on any page:

<script async src="https://YOUR-SERVER/embed/millirec-code.js"></script>
<div data-millirec-code></div>

It is the code system behind digitizer.fun's two-player games and shared puzzles, with the games taken out.

What you get in each zip

  • The server, its tests (npm test), a Dockerfile and docker-compose.yml, a wrangler.toml, and a README with every setting.
  • Everything a page loads from it: the embed, the recognizer and its templates. Nothing is fetched from millirec.com.
  • Node 20 or newer for standalone and library use; storage is one SQLite file you can copy to back up.
  • One setting limits a server to your own sites (WIDGETS_ALLOWED_ORIGINS / CODES_ALLOWED_ORIGINS, wildcards allowed): pages anywhere else are refused.
  • MIT licensed, like the millirec package.