Class Points
A points and rewards tracker for the classroom. Add the students, give each a customisable avatar, then award points as they take part. It runs in any modern browser, with nothing to install.








What it does
- One-tap points on each student card (+1, +5, +10), or type an exact total or a change such as -10. Select several students to reward them together.
- Each student gets an avatar built from a shape, eyes, mouth, glasses and colour, and there is a printable class photo view.
- Random groups of two or three, with pairs that should not be put together kept apart. A random student picker, search and sorting, and confetti for class achievements.
- CSV import and export for backups and moving a class.
- Works with no account. The class stays in the browser's own storage and works offline once loaded. Optionally, sign in with an email address (no password: a link is emailed) to keep the class in sync across a computer, tablet and phone, with changes appearing live on every device.
- Light and dark themes, and back and forward buttons that work between the full-screen views.
Under the hood
- A Cloudflare Worker serves both the API and the static front end from one origin, so there is no CORS to manage. Data lives in D1 with a relational schema: users, classes, students, exclusions and access tokens, with soft deletes rather than hard ones.
- Live sync runs over WebSockets through a Durable Object using the Hibernation API. Sockets are tagged with the class code, so one broadcast reaches every open tab and device for that class. Keep-alive pings are answered by Cloudflare's auto-response, so the object can sleep between real changes.
- The class code travels as the WebSocket subprotocol rather than in the URL, so it stays out of browser history and access logs.
- Edits from several devices are merged last-write-wins per field. Deleted students leave a timestamped tombstone so a stale device cannot bring them back, while a deliberate re-import can. A save that would take over a student owned by another class is refused, and only the sender is told.
- The front end is plain JavaScript and CSS with no framework or build step beyond cache-busting, plus a service worker for offline use. Student names are only ever written to the page as text, never as HTML.
- Tests run in two layers: Vitest inside the Workers runtime for the API and merge logic, and Playwright end to end against a throwaway local server with its own seeded database.
Without a login nothing leaves the browser. With one, the email address, class name and the students' names, points and avatars are stored so they can sync. First names or nicknames are all the app needs. The class in the screenshots is invented.