Manual

How this thing works

titles categories backend none trackers none

The build

Static HTML, CSS and plain JavaScript on the front. No framework, no bundler. The catalog lives in data/games.json — mirrored as data/games.js so it also works straight off a filesystem — and every page reads from that one list.

Accounts, friends and messages are served by a small Node + SQLite backend in server/. It is entirely optional: without it the site is still a complete, deployable static arcade.

Cover art is real where a game ships its own icon, and generated from the title's id where it doesn't — a deterministic geometric plate, so no two entries look alike and there are no placeholder images to ship.

There are no webfonts either. Everything uses the fonts already on your machine, which means nothing breaks when a network blocks font CDNs.

Compatibility flags

Separately, each title says whether it plays in page or opens a new tab. Some games refuse to be framed; those get a one-click launch instead, and the player tells you which you're getting before you click.

Flags describe reliability, not permission. Follow whatever rules apply where you are.

Accounts (optional)

You never need one. Browsing, playing, pinning and playtime all work signed out, exactly as they always have. An account adds three things: your save follows you to other devices, you get friends, and you get direct messages.

What's stored

There are no analytics and no ad trackers. Pins, history, ratings, playtime and your skin choice sit in this browser's localStorage under the ach: prefix. Signed in, everything except your skin also syncs to the hub's own server — nowhere else.

Friends and messages

Images in chat

You can share a screenshot, take a photo with your camera, or attach an image from disk. Everything is downscaled and re-encoded in your browser before it is sent, so a huge PNG becomes a reasonable JPEG rather than being rejected.

Calling

You can ring a friend for voice, video or a shared screen from their profile, or from the chat dock while a game is running. The audio and video go straight from one browser to the other; the hub's server only passes the few setup messages needed to introduce you. Nothing is recorded and nothing is relayed through us.

Support

Feedback is a one-way note — send it and someone reads it. A support ticket is a conversation that stays open until it's sorted, which is what you want for a lost save or a problem with another person. Tickets need an account so there's somewhere to reply to; you can have five open at once, and you can close your own any time.

Keys

Adding a title

The owner can add one from the browser: Admin → Games takes a title, a host and a path, and it is live for everyone on their next page load. That layers over the shipped list rather than editing it, so it also lets you repoint a game whose host moved, or hide one, without touching a file. The same screen puts a hidden title back.

For a bulk change, or anything you want in version control, append an object to data/games.json and regenerate the derived files:

{
  "id": "my-game",
  "title": "My Game",
  "category": "arcade",
  "description": "One line about it.",
  "gradient": "linear-gradient(135deg, #ff5c33, #7c2d12)",
  "source": "/games/my-game/index.html",
  "direct": "/games/my-game/index.html",
  "platform": "local",
  "embed": "allowed",
  "schoolRisk": "low"
}

embed is "allowed"/true for in-page play or false to force a new tab. preferDirect: true skips the player even when framing works. schoolRisk is low | medium | high. gradient seeds the generated cover. Unknown categories fall back to Other. Where the game files are served from is set once in js/config.js via gameBase.

Disclaimer

Hobby build. Games are third-party works owned by their creators and are provided as-is; how and where you use this is on you.

Open the index