- JavaScript 77.1%
- CSS 13.1%
- HTML 9.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| assets/bergamot | ||
| css | ||
| fonts | ||
| i18n | ||
| icons | ||
| js | ||
| test | ||
| .gitignore | ||
| config.json | ||
| index.html | ||
| LICENSE | ||
| manifest.webmanifest | ||
| README.md | ||
| sw.js | ||
Nightboard '83
ATTENTION: This project is created by making heavy use of LLM systems, if you don't want to use software created in this way this particular app may not be for you
Nightboard '83 is a static web client for Mastodon-compatible servers, written especially with GoToSocial in mind. It is a set of HTML, CSS, and JavaScript files with no build step and no backend of its own. The interface ships with German and English UI strings (default German), in an design trying to emulate the look of old FASA Pen-and-Paper rulebooks, and can be installed as a Progressive Web App.
Offline is the core idea: After an initial sync you can view your timelines, compose replies, react and create posts to push them back to the net the next time you have internet access.
The client talks to the instance you configure (or type in at login) using OAuth 2.0 with PKCE. After you authorize, the instance redirects back to Nightboard. A paste-the-code fallback remains for stubborn servers.
Homepage: https://nightboard83.de · Main Instance: https://nightboard83.de/app/
Features
- Four independently scrollable columns: Home, Local, Federated (public timeline), and Notifications
- Safe mode and a local circle (German: Kreis, English: Screened). The profile button adds or removes an account at any time. While safe mode is on, only that column and Notifications stay visible and update. Mentions and new posts from outside the circle are held back.
- Offline cache (last timelines and media) via PouchDB / IndexedDB
- Outbox: compose or reply while offline, send automatically when the connection returns
- Drafts stored locally; a drafts icon appears in the header when any exist
- Installable as PWA
- Threads with replies, boosts, favourites, and a reply composer
- Local in-browser post translation via Bergamot WASM engine (24 language pairs, privacy-friendly)
- Doomscrolling detector: Tracks scroll velocity,
session duration, post-consumption rate, and time of day to estimate a
"humanity" score. Escalating edge-glow warnings fire when humanity drops.
Configurable via
config.json(cyberpsych)
Requirements
- A web server that can serve static files (any origin is fine)
- A Mastodon-compatible instance with OAuth and the client API (GoToSocial is the primary target)
- A current browser (Chromium, Firefox, Safari).
file://will not work: the app loadsconfig.json, registers a service worker, and uses IndexedDB
For PWA install and a reliable service worker, serve the files over HTTPS (or http://localhost).
Installation
Copy the project directory onto the server as-is. There is nothing to compile.
Quick local preview
From the project root:
python3 -m http.server 8000
Open http://127.0.0.1:8000/.
Production
Point any static host (nginx, Caddy, Apache, Git forge pages, object storage with a website mode) at the directory where the files reside. Example with Caddy:
nightboard83.de {
root * /var/www/Nightboard83.de
file_server
}
The app checks for a new service worker on startup, when the tab becomes visible, and about every ten minutes. HTML, CSS, and JavaScript are fetched network-first (cache only if offline). If a new version is found, a SYS.UPDATE overlay runs a short install sequence, then the PWA reloads. If a compose or reply draft is open, the overlay pauses and dismisses so you can finish writing; the update resumes once the buffer is empty.
Configuration
Edit config.json in the program directory. The file is fetched at startup (cache: no-store) and is not baked into the service worker precache, so changing it does not require a rebuild.
{
"instance": "fediverse2.blackneon.net",
"poll_minutes": 2,
"lang_switch": true,
"federated": true,
"local": true,
"theme": "default",
"cyberpsych": true
}
| Key | Type | Default | Description |
|---|---|---|---|
instance |
string | (empty) | Hostname or URL used to prefill the instance field on the login screen. https:// is added if you omit the scheme. Trailing slashes are stripped. Aliases: url, host. |
poll_minutes |
number | 2 |
How often to look for new posts while you are logged in and no detail window is open. Allowed range: 0.25–1440 minutes (15 seconds to 24 hours). Aliases: pollMinutes, polling_minutes, poll. |
lang_switch |
boolean | true |
Show the **DE |
federated |
boolean | true |
Show the Federated (public timeline) column and its dock icon. Set to false to remove the column entirely — it is not loaded, polled, or streamed. Aliases: federatedTimeline, federated_timeline, showFederated. |
local |
boolean | true |
Show the Local column and its dock icon. Set to false to remove the column entirely — it is not loaded, polled, or streamed. Aliases: localTimeline, local_timeline, showLocal. |
theme |
string | default |
Color theme. Only default (Grid Protocol) is available. Unknown values fall back to default. Alias: skin. |
cyberpsych |
boolean | true |
Enable the Cyberpsychosis Danger doomscrolling detector. When true, a humanity HUD appears below the top bar after login; it decays with fast/continuous scrolling and recovers during pauses, escalating through five levels (STABLE → ELEVATED → UNSTABLE → CRITICAL → CYBERPSYCHOSIS) with edge-glow warnings and dialogs. Set to false to disable entirely. |
The login form can still point at a different instance. The last successful instance is stored in localStorage (nightboard83.instance) and wins over config.json on later visits. Changing the instance on login registers a new OAuth app on that server.
Polling is paused while a thread, profile, compose, media, drafts, outbox, or settings dialog is open, and while the tab is hidden.
Safe mode and backup
On someone else's profile, Screen / In den Kreis only changes membership in a circle stored on this device. It does not call the instance. Your own profile has no such button. Safe mode does not hide the button. Turn safe mode on in Settings when you want the circle to become the timeline: Home, Local, and Federated are hidden and are not loaded, polled, or streamed. Notifications are still fetched. Mentions and new posts from accounts outside the circle are held on this device (up to 200). Follows, follow requests, boosts, favourites, polls, and edits stay visible. Turning safe mode off asks whether to show the held mentions. The circle you built beforehand is still there.
Settings can also write an encrypted .nb83 file and read one back. The passphrase is typed at export and import. It is not stored and not included in the file. A lost passphrase makes that backup unreadable. Share uses the system share sheet when the browser can share files; Download always saves the file. Merge keeps the newer circle entry, the newer safe-mode stamp, and the newer read cursor, and leaves this device's language alone. Replace with this file overwrites safe mode, language, read cursors, and the circle. The file is tied to the account that exported it. It does not contain the login token, drafts, the outbox, media, or the timeline cache. Nothing is synced through a server.
Local data
All of this lives in the browser, not on your instance:
- Session:
localStoragekeys prefixednightboard83. - Circle, safe mode, and the device-local held-mention stack:
nightboard83.screened(separate per instance and account). The held stack is not part of the.nb83file. - Timeline cache, media blobs, outbox, drafts: IndexedDB databases
nightboard83-cache,nightboard83-media,nightboard83-outbox,nightboard83-drafts(PouchDB)
Clearing site data logs you out and deletes drafts and queued posts.
Local post translation (Bergamot)
Posts can be translated entirely in the browser with the Bergamot WASM engine. Post text never leaves the device.
- Engine:
assets/bergamot/(lazy-loaded). Models are downloaded on demand from the Bergamot registry and cached in the Cache API. They are released under CC-BY-SA-4.0 — seeassets/bergamot/NOTICE.txt - 24 language pairs (en↔de, es, fr, it, pt, ru, cs, bg, uk, zh, ja); pivot via English when no direct pair exists
- A "Translate" control appears only when source ≠ UI language and a registry path exists
- Falls back gracefully if WebAssembly or Workers are unavailable
License
- Application code: GNU Affero GPL v3 or later — see
LICENSE - Syne, IBM Plex Sans, and Oxanium: SIL Open Font License 1.1 — see
fonts/OFL.txt. These are the families the interface loads. - NB Mark (
fonts/NBMark-latin.woff2): a modified latin subset of Orbitron, renamed so it does not use the Reserved Font Name "Orbitron". SIL Open Font License 1.1 — seefonts/OFL.txt - PouchDB 8.0.1 (
js/pouchdb.min.js): Apache License 2.0 — seejs/pouchdb.Apache-2.0.txt - Bergamot translator engine (
assets/bergamot/): Mozilla Public License 2.0 — seeassets/bergamot/LICENSEandassets/bergamot/NOTICE.txt - Bergamot translation models (downloaded on demand, not bundled): Creative Commons Attribution-ShareAlike 4.0 — see
assets/bergamot/NOTICE.txt