From bcbe5fff225faae7a5189c6a5ffb9a6d6a6fb6bf Mon Sep 17 00:00:00 2001 From: reverse Date: Sat, 20 Jun 2026 06:34:12 +0000 Subject: [PATCH] Orbit documentation: docs, wiki and FAQ pages --- .gitignore | 3 ++ README.md | 15 ++++++ docs/architecture.md | 40 ++++++++++++++++ docs/branding.md | 51 ++++++++++++++++++++ docs/compiled-plugins.md | 100 +++++++++++++++++++++++++++++++++++++++ docs/config.md | 44 +++++++++++++++++ docs/deploy.md | 35 ++++++++++++++ docs/ircv3.md | 37 +++++++++++++++ docs/overview.md | 29 ++++++++++++ docs/plugins.md | 99 ++++++++++++++++++++++++++++++++++++++ docs/push-to-deploy.md | 38 +++++++++++++++ docs/quick-start.md | 46 ++++++++++++++++++ faq.md | 51 ++++++++++++++++++++ wiki/commands.md | 29 ++++++++++++ wiki/formatting.md | 22 +++++++++ wiki/orbit-channel.md | 31 ++++++++++++ wiki/themes.md | 17 +++++++ wiki/troubleshooting.md | 27 +++++++++++ 18 files changed, 714 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 docs/architecture.md create mode 100644 docs/branding.md create mode 100644 docs/compiled-plugins.md create mode 100644 docs/config.md create mode 100644 docs/deploy.md create mode 100644 docs/ircv3.md create mode 100644 docs/overview.md create mode 100644 docs/plugins.md create mode 100644 docs/push-to-deploy.md create mode 100644 docs/quick-start.md create mode 100644 faq.md create mode 100644 wiki/commands.md create mode 100644 wiki/formatting.md create mode 100644 wiki/orbit-channel.md create mode 100644 wiki/themes.md create mode 100644 wiki/troubleshooting.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7e4c83f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +*.swp +__pycache__/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..b62deeb --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Orbit — documentation + +Source for the Orbit IRC web client documentation, rendered at +**[orbit.tchatou.fr/docs](https://orbit.tchatou.fr/docs/)**. + +- **`docs/`** — documentation pages (overview, quick start, configuration, + branding, plugins, self-hosting, IRCv3, architecture) +- **`wiki/`** — user wiki (slash commands, formatting, themes, the `#orbit` + channel, troubleshooting) +- **`faq.md`** — frequently asked questions + +Every page is Markdown. Edit a page, commit, and the site serves it. + +The Orbit client itself lives at +**[codeberg.org/reversefr/orbit](https://codeberg.org/reversefr/orbit)**. diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..2547e83 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,40 @@ +# Architecture + +Orbit is a small, modular React app. No framework magic — a thin IRC layer feeds a zustand store, +which renders components. + +## Project tree + +``` +src/ + config.ts App.tsx main.tsx index.css + lib/ format.tsx editor.ts ← presentation + editor helpers + ui/ theme.ts prefs.ts viewport.ts + services/ notify.ts push.ts avatars.ts + irc/ parser client modes numerics casemap types caps ctcp + store.ts store/text.ts store/persistence.ts + components/ + Chat.tsx ← thin assembler + chat/ MessageList Composer Sidebar Topbar MemberList Banners + settings/ SettingsModal + profile/ ProfileModal + modals/ Modals + Avatar ConnectScreen Turnstile +``` + +## Layers + +- **`irc/`** — the protocol. `client.ts` is the WebSocket transport + CAP negotiation; `parser.ts`, + `modes.ts`, `casemap.ts`, `numerics.ts` are pure primitives. `caps.ts` lists the requested + capabilities. +- **`store.ts`** — turns IRC events into buffers, messages and members (zustand). Pure helpers split + into `store/text.ts` (masking, formatting) and `store/persistence.ts`. +- **`lib/`** — `format.tsx` renders mIRC formatting → React; `editor.ts` is the rich-composer + serialization. +- **`components/`** — the UI, grouped by area (`chat/`, `settings/`, `profile/`, `modals/`). + `Chat.tsx` is a ~30-line assembler. + +## Quality + +Vitest unit tests cover the pure modules (parser, casemap, masking). Lint + test + build run in CI, +and the self-hosted [push-to-deploy](/docs/push-to-deploy/) gates on the same. diff --git a/docs/branding.md b/docs/branding.md new file mode 100644 index 0000000..cacbabb --- /dev/null +++ b/docs/branding.md @@ -0,0 +1,51 @@ +# Branding & themes + +Everything that ties Orbit to a particular network or brand lives in +[`config.json`](/docs/config/) under `branding` and `defaults` — no code changes, no rebuild. + +## Rebrand + +```json +{ + "branding": { + "name": "ExampleChat", + "icon": "https://example.org/logo.svg", + "url": "https://example.org", + "tagline": "Chat with", + "taglineEm": "everyone.", + "subtitle": "Public rooms, private messages, no signup required." + } +} +``` + +This changes the connect screen, the console title, the network icon, and the CTCP VERSION/SOURCE +replies the client sends. + +## Themes + +Orbit ships four themes: + +- **light** — clean, default. +- **dark** — easy on the eyes. +- **yomirc** — a retro mIRC / Windows-95 skin (silver chrome, fixed-width log lines). +- **yomirc-dark** — the retro skin in a dark palette. + +Set the default for new users: + +```json +{ "defaults": { "theme": "dark" } } +``` + +Users can switch any time in **Settings → Appearance**. See the [Themes wiki page](/wiki/themes/). + +## Feature flags + +Hide whole features per deployment: + +```json +{ "features": { "push": true, "imageUpload": true, "register": false } } +``` + +- `push` — the Web Push notifications row. +- `imageUpload` — the composer image button + paste/drag upload. +- `register` — the "create an account" tab. diff --git a/docs/compiled-plugins.md b/docs/compiled-plugins.md new file mode 100644 index 0000000..481a088 --- /dev/null +++ b/docs/compiled-plugins.md @@ -0,0 +1,100 @@ +# Compiled plugins + +A quick `.js` plugin (see [Plugin system](/docs/plugins/)) is great for small +things. For anything substantial — real components with state and hooks — build +the plugin like a normal project and compile it down to **one droppable file**: a +compiled, externalized-React plugin model. + +## The trick: externalize React + +The output bundle must **not** carry its own copy of React. Two React instances +on one page break hooks ("invalid hook call"). Instead, mark `react`, `react-dom` +and `react/jsx-runtime` **external** and map them to Orbit's globals, so your +plugin shares the host's single React instance: + +| Module | Maps to | +|---|---| +| `react` | `Orbit.React` | +| `react-dom` | `Orbit.ReactDOM` | +| `react/jsx-runtime` | `Orbit.jsxRuntime` | + +Because your component is created with Orbit's React and rendered through a slot +into Orbit's tree, **hooks, state, context and effects all work**. + +## Vite config + +```ts +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [react()], + build: { + lib: { entry: 'src/index.tsx', formats: ['iife'], name: 'MyOrbitPlugin', + fileName: () => 'my-plugin.js' }, + rollupOptions: { + external: ['react', 'react-dom', 'react/jsx-runtime'], + output: { globals: { + react: 'Orbit.React', + 'react-dom': 'Orbit.ReactDOM', + 'react/jsx-runtime': 'Orbit.jsxRuntime', + } }, + }, + }, +}); +``` + +## Write normal TSX + +```tsx +import { useState } from 'react'; + +Orbit.plugin('my-plugin', (orbit) => { + orbit.addUi('composer_button', () => ); + orbit.addSettingsSection({ + label: 'My plugin', icon: '🧩', + render: () => , + }); +}); + +function Panel({ orbit }) { + const [count, setCount] = useState(() => orbit.storage.get('count', 0)); + const bump = () => { const n = count + 1; setCount(n); orbit.storage.set('count', n); }; + return ( +
+
+ Compiled plugin — real React with hooks. You are {orbit.state.nick()}. +
+
+ +
+
+ ); +} +``` + +The compiled bundle is tiny — it contains only your code, calling Orbit's React. + +## Starter template + +A ready-to-copy starter (Vite config with the externals set up, `tsconfig`, +ambient types and a working example) lives in the repo at +[`plugin-template/`](https://codeberg.org/reversefr/orbit/src/branch/main/plugin-template). + +```bash +git clone https://codeberg.org/reversefr/orbit.git +cd orbit/plugin-template +npm install +npm run build # → dist/orbit-plugin-template.js +``` + +## Deploy + +1. Copy the built `.js` to where Orbit can fetch it (e.g. `/app/plugins/`). +2. List it in the deployed `config.json` — no rebuild of Orbit needed: + + ```json + { "plugins": ["/app/plugins/my-plugin.js"] } + ``` + +3. Reload. Your composer button and Settings section appear. diff --git a/docs/config.md b/docs/config.md new file mode 100644 index 0000000..a27c234 --- /dev/null +++ b/docs/config.md @@ -0,0 +1,44 @@ +# config.json reference + +Orbit is configured at **runtime** by `config.json`. It is fetched on startup, deep-merged over the +built-in defaults, then the app renders — so you can re-point or rebrand **without rebuilding**. + +- **Source of truth:** `public/config.json` (copied into the build). +- **Served at:** `/app/config.json`. +- **Edit live:** the service worker serves it *network-first*, so editing the deployed file takes + effect on the next reload — no rebuild. + +Merge rules: objects merge key-by-key; **arrays and scalars replace** wholesale. + +## Options + +| Key | Type | What it does | +|-----|------|--------------| +| `server.url` | string | WebSocket URL of the IRCv3 server. | +| `startup.channels` | string[] | Channels auto-joined (first = active). A `?channel=` URL param overrides. | +| `branding.name` | string | App/network name shown in the UI + CTCP VERSION. | +| `branding.icon` | string | Logo / favicon URL. | +| `branding.url` | string | Homepage (used in CTCP VERSION/SOURCE). | +| `branding.tagline` / `taglineEm` / `subtitle` | string | Connect-screen copy. | +| `branding.projectUrl` | string | "Powered by Orbit" link in Settings. | +| `turnstile.enabled` / `sitekey` | bool / string | Cloudflare Turnstile on registration. | +| `report.target` | string | Channel that user reports are sent to. | +| `defaults.theme` | string | `light` · `dark` · `yomirc` · `yomirc-dark`. | +| `defaults.compact` / `sound` / `hideJoinQuit` / `clock24` | bool | Preset new-user prefs. | +| `features.push` / `imageUpload` / `register` | bool | Turn whole features on/off. | + +> `defaults.*` only seed a user's preferences the **first** time — once someone changes a setting, +> it's stored in their browser and the config no longer overrides it. + +## Example + +```json +{ + "server": { "url": "wss://irc.example.org/ws/" }, + "startup": { "channels": ["#lobby", "#help"] }, + "branding": { "name": "ExampleChat", "tagline": "Chat with", "taglineEm": "everyone." }, + "turnstile":{ "enabled": false, "sitekey": "" }, + "defaults": { "theme": "dark", "compact": true }, + "features": { "register": false } +} +``` diff --git a/docs/deploy.md b/docs/deploy.md new file mode 100644 index 0000000..5cdd37c --- /dev/null +++ b/docs/deploy.md @@ -0,0 +1,35 @@ +# Build & deploy + +Orbit builds to a **static** `dist/` you can serve from any web server. + +```sh +npm run build # → dist/ (index.html + hashed assets + config.json + sw.js) +``` + +## Serving + +Serve `dist/` under a path — conventionally `/app/`. The build's `vite.config.ts` sets +`base: '/app/'`. Example nginx: + +```nginx +location /app/assets/ { root /var/www/site; expires 7d; add_header Cache-Control "immutable"; } +location = /app/index.html { root /var/www/site; add_header Cache-Control "no-cache"; } +location /app/ { root /var/www/site; try_files $uri $uri/ /app/index.html; } +``` + +- **Hashed assets** are immutable → cache forever. +- **`index.html`** is `no-cache` so new builds load immediately. +- **`config.json`** is served *network-first* by the service worker, so edits apply without a rebuild. + +## Origin allow-list + +The IRC WebSocket server must allow the **Origin** Orbit is served from (e.g. InspIRCd +``). Otherwise the socket is rejected on connect. + +## Service worker + +On each deploy, bump the cache version in `public/sw.js` (`const CACHE = 'app-vN'`). The worker +calls `skipWaiting()` + `clients.claim()` and fires `controllerchange`, so existing PWA installs +auto-reload to the new build. + +For an automated pipeline, see [Push-to-deploy](/docs/push-to-deploy/). diff --git a/docs/ircv3.md b/docs/ircv3.md new file mode 100644 index 0000000..becf984 --- /dev/null +++ b/docs/ircv3.md @@ -0,0 +1,37 @@ +# IRCv3 capabilities + +Orbit negotiates the following capabilities when the server advertises them. Most features degrade +gracefully if a cap is missing, so it works on any compliant IRCv3 server. + +## Core + +| Capability | Purpose | +|------------|---------| +| `sasl` | Authenticate to your account during connection. | +| `message-tags` | The basis for msgids, reactions, replies, labels. | +| `server-time` | Accurate timestamps on every message. | +| `echo-message` | The server echoes your own messages back (consistent state). | +| `batch` | Groups related messages (history, netsplits). | +| `labeled-response` | Correlate a command with its replies. | +| `account-tag` | Each message carries the sender's account (avatars, badges). | + +## Presence & membership + +`away-notify` · `account-notify` · `extended-join` · `chghost` · `multi-prefix` · +`userhost-in-names` · `setname` · `invite-notify` + +## Drafts (modern features) + +| Capability | Feature in Orbit | +|------------|------------------| +| `draft/chathistory` + `draft/event-playback` | Server-side history replayed on join. | +| `draft/message-redaction` | Delete your own messages. | +| `draft/read-marker` | "New messages" divider, synced across devices. | +| `draft/multiline` | Send multi-line messages as one. | +| `draft/metadata-2` | Profile metadata. | +| `standard-replies` | Structured `FAIL`/`WARN`/`NOTE` handling. | +| `draft/account-registration` | Create an account from inside the client. | +| `draft/pre-away` | Set away during registration. | +| `draft/webpush` | Push notifications while the tab is closed (VAPID). | + +You can list the live set any time by typing `!caps` to the bot in [#orbit](/wiki/orbit-channel/). diff --git a/docs/overview.md b/docs/overview.md new file mode 100644 index 0000000..d0680a7 --- /dev/null +++ b/docs/overview.md @@ -0,0 +1,29 @@ +# Overview + +**Orbit** is a modern web client for **IRC** — the open chat protocol that has quietly run +communities for decades. It runs entirely in the browser: pick a nick and you're talking, with +**no install and no signup**. + +It powers [tchatou.fr](https://tchatou.fr/app/), and is built to be **re-pointed at any IRCv3 +network** and **rebranded** from a single `config.json` — without recompiling. + +## What makes it different + +- **Full IRCv3.** Orbit negotiates 24 capabilities — SASL, message-tags, reactions, typing + indicators, read-markers, multi-line messages, server-side history, account registration, and + Web Push. See [IRCv3 capabilities](/docs/ircv3/). +- **Pluggable at runtime.** A static `config.json` is fetched on startup and sets the server, + channels, branding, themes and feature flags. One build can serve any community. See + [config.json reference](/docs/config/). +- **Installable PWA.** Mobile-first layout, offline app shell, and notifications when the tab is + closed. +- **Self-hostable.** A static build behind any web server. The project even runs its own git + server with [push-to-deploy](/docs/push-to-deploy/). +- **Free software.** AGPL-3.0 — use it, modify it, self-host it. + +## Tech + +React 19 · TypeScript · Vite · zustand. Tested with Vitest, linted, and built in CI. The codebase +is a clean modular tree — see [Architecture](/docs/architecture/). + +> New here? Jump to the [Quick start](/docs/quick-start/) to run your own in a minute. diff --git a/docs/plugins.md b/docs/plugins.md new file mode 100644 index 0000000..1f3c259 --- /dev/null +++ b/docs/plugins.md @@ -0,0 +1,99 @@ +# Plugin system + +Orbit has a small, **operator-controlled** plugin system. A deployment lists +plugin scripts in `config.json`; each is loaded at startup and registers against +a global `Orbit` object to hook events, read state, send IRC, theme the UI, and +add UI in predefined slots. + +> **Experimental.** Orbit is a work in progress and this API may change between +> releases. Plugins are deployment-controlled — same trust level as the app +> itself. There is no user-uploaded plugin marketplace, by design. + +## Enabling plugins + +Add script URLs to `plugins` in [`config.json`](/docs/config/): + +```json +{ "plugins": ["/app/plugins/orbit-demo.js"] } +``` + +They load in order, after the app boots. Host them anywhere the page can reach +(same-origin recommended). + +## A quick plugin + +A plugin is a plain `.js` file that calls `Orbit.plugin()`. UI is authored with +the `html` tagged template (runtime markup, no build step), or with +`orbit.h(...)` (`React.createElement`). + +```js +Orbit.plugin('my-plugin', (orbit, log) => { + log('loaded, Orbit v' + orbit.version); + + orbit.on('message', (m) => log(m.from, 'said', m.text, 'in', m.target)); + + orbit.addUi('composer_button', () => + orbit.html``); +}); +``` + +For anything substantial — real components with state — build a compiled plugin +instead. See **[Compiled plugins](/docs/compiled-plugins/)**. + +## The `Orbit` API + +### Global + +| Member | Description | +|---|---| +| `Orbit.version` / `Orbit.commit` | app version + git commit (build-time) | +| `Orbit.plugin(name, fn)` | register a plugin; `fn(orbit, log)` | +| `Orbit.on/once/off/emit(event, …)` | the app event bus | +| `Orbit.config()` | the resolved runtime config | +| `Orbit.React` / `Orbit.ReactDOM` / `Orbit.jsxRuntime` / `Orbit.Fragment` / `Orbit.h` / `Orbit.html` | render primitives (externalization targets for compiled plugins) | + +### Inside `Orbit.plugin(name, (orbit) => …)` + +| Member | Description | +|---|---| +| `orbit.on/once/off/emit` | event bus (see events below) | +| `orbit.state.active()` | active buffer name | +| `orbit.state.nick()` / `account()` | your nick / logged-in account | +| `orbit.state.buffers()` | open buffer names | +| `orbit.state.get()` | full store snapshot (read-only) | +| `orbit.irc.send(line)` | send a raw IRC line | +| `orbit.irc.msg(target, text)` | PRIVMSG a target | +| `orbit.irc.say(text)` | send to the active buffer | +| `orbit.irc.join(chan)` / `part(chan)` | join / part | +| `orbit.irc.list()` | request the channel list | +| `orbit.themes.current()/list()/set(id)` | read/set the theme | +| `orbit.storage.get(key, def)/set(key, val)` | namespaced persistence | +| `orbit.addUi(slot, render)` | add UI to a slot (returns a remover) | +| `orbit.addSettingsSection({label, icon?, render})` | add a whole Settings section | +| `orbit.h / orbit.html` | render helpers | +| `log(…)` | namespaced console logger | + +### Events + +`ready`, `connected` (`{nick}`), `status` (connection status string), +`buffer.active` (buffer name), `message` (`{from, target, text, self}`), +`raw` (the parsed IRC message). + +### UI slots + +| Slot | Where | +|---|---| +| `composer_button` | a button in the message composer toolbar | +| `settings_section` | a whole section in Settings (own nav entry + pane) — use `orbit.addSettingsSection()` | + +More slots (message decorators, side panels) will be added as the core grows +stable homes for them. + +## Trust & security + +Plugins are **operator-controlled**: a deployment lists them in `config.json`, so +they run with the same trust as the app itself. There is no user-uploaded plugin +mechanism. Orbit deliberately does **not** expose internal modules or runtime +component replacement — that would couple plugins to internals that are still +moving. The API above is the stable surface. diff --git a/docs/push-to-deploy.md b/docs/push-to-deploy.md new file mode 100644 index 0000000..436a847 --- /dev/null +++ b/docs/push-to-deploy.md @@ -0,0 +1,38 @@ +# Push-to-deploy + +Orbit ships its own self-hosted git workflow: a `git push` runs the tests, builds, and publishes — +no external CI required. + +## How it works + +A **bare git repo** on the server has a `post-receive` hook. On a push to `main` it: + +1. Checks out the new commit. +2. Runs `npm ci && npm run test && npm run build` — **gated**, so a broken push never ships. +3. Publishes `dist/` to the web root with `rsync --delete` (keeping a backup for rollback). + +The whole loop is one command: + +```sh +git commit -m "…" +git push # test → build → deploy (+ mirror) +``` + +## The hook (sketch) + +```bash +#!/bin/bash +set -e; unset GIT_DIR +WORK=/path/to/checkout; WEBROOT=/var/www/site/app +while read -r _old new ref; do + [ "$ref" = "refs/heads/main" ] || continue + cd "$WORK"; git fetch -q self; git reset --hard -q self/main + npm ci --silent && npm run test && npm run build + rsync -a --delete dist/ "$WEBROOT/" +done +``` + +## Bonus: IRC announcements + +The same hook hands the commit list to a small bot that posts a GitHub-style summary to the +project's IRC channel. See [The #orbit channel & bot](/wiki/orbit-channel/). diff --git a/docs/quick-start.md b/docs/quick-start.md new file mode 100644 index 0000000..37e6128 --- /dev/null +++ b/docs/quick-start.md @@ -0,0 +1,46 @@ +# Quick start + +Run your own Orbit in about a minute. + +## 1. Clone & install + +```sh +git clone https://codeberg.org/reversefr/orbit.git +cd orbit +npm install +``` + +## 2. Point it at your server + +Edit **`public/config.json`** — at minimum set the WebSocket URL of your IRCv3 server: + +```json +{ + "server": { "url": "wss://irc.example.org/ws/" }, + "startup": { "channels": ["#lobby"] } +} +``` + +Your IRC server needs a **WebSocket listener** speaking the `text.ircv3.net` / `binary.ircv3.net` +sub-protocols (InspIRCd, Ergo, etc.), and its Origin allow-list must include where you serve Orbit. + +## 3. Develop + +```sh +npm run dev # http://localhost:5173 +``` + +## 4. Build & serve + +```sh +npm run build # → dist/ +``` + +Serve the static `dist/` behind any web server (commonly under `/app/`). See +[Build & deploy](/docs/deploy/) for nginx and service-worker details. + +## Next steps + +- [config.json reference](/docs/config/) — every option. +- [Branding & themes](/docs/branding/) — make it yours. +- [IRCv3 capabilities](/docs/ircv3/) — what works on your server. diff --git a/faq.md b/faq.md new file mode 100644 index 0000000..012e8a4 --- /dev/null +++ b/faq.md @@ -0,0 +1,51 @@ +## Is Orbit free? + +Yes — it's **free software under AGPL-3.0**. You can use, +modify, and self-host it. If you run a **modified** version as a network service, you must publish +your source. + +## Do I need to create an account? + +No. Pick a nick and start chatting. Accounts (SASL / registration) are optional and only needed to +reserve a nick, host images, or get push notifications while closed. + +## What servers does it work with? + +Any **IRCv3** server with a WebSocket listener — InspIRCd, Ergo, and others. The more capabilities +the server supports, the more features light up. See [IRCv3 capabilities](/docs/ircv3/). + +## Can I use it for my own network? + +Absolutely — that's the point. Re-point it at your server and rebrand it entirely from one +[`config.json`](/docs/config/), no rebuild. See [Branding & themes](/docs/branding/). + +## Does it work on mobile? + +Yes. Orbit is an installable **PWA** with a mobile-first layout, offline shell, and push +notifications. + +## Are my passwords safe? + +Orbit connects over TLS, and it **masks** services passwords in the message log. If you accidentally +type `IDENTIFY nick pass` without a leading slash, it intercepts it, sends it privately, and warns +you — it's never broadcast to the channel. + +## How do notifications work? + +In-tab alerts and sounds work everywhere. **Push** notifications while the tab is closed use the +`draft/webpush` capability (VAPID) and require being logged into an account. + +## Can I self-host it? + +Yes — it's a static build behind any web server. The project even runs its own git server with +[push-to-deploy](/docs/push-to-deploy/). Start with the [Quick start](/docs/quick-start/). + +## How do I report a bug or contribute? + +Issues and code live on [Codeberg](https://codeberg.org/reversefr/orbit). You can also clone it +straight from `https://orbit.tchatou.fr/orbit.git`. + +## Why IRC in 2026? + +Because it's **open, federated, and yours** — no platform lock-in, no ads, no data harvesting. Orbit +gives that protocol a modern, friendly face. diff --git a/wiki/commands.md b/wiki/commands.md new file mode 100644 index 0000000..556345e --- /dev/null +++ b/wiki/commands.md @@ -0,0 +1,29 @@ +# Slash commands + +Type these in the composer. Anything not starting with `/` is sent as a message. + +| Command | What it does | +|---------|--------------| +| `/join #channel` | Join a channel (and switch to it). | +| `/part` | Leave the current channel. | +| `/msg ` | Open a private message. | +| `/me ` | Send a `/me` action. | +| `/nick ` | Change your nick. | +| `/whois ` | Look up a user (opens their profile). | +| `/topic ` | Set the channel topic. | +| `/kick [reason]` | Kick a user (ops). | +| `/ban ` | Ban a user (ops). | +| `/op` / `/deop` / `/voice ` | Change a user's mode (ops). | +| `/ignore` / `/unignore ` | Hide / show a user's messages. | +| `/list` | Browse channels. | +| `/clear` | Clear the current buffer. | + +## Editor shortcuts + +- **↑ / ↓** — recall your previously sent messages (like a shell). +- **Tab** — complete nicks, `/commands`, and `:emoji:`. +- **Shift+Enter** — newline (multi-line message). + +> Heads-up: if you type a services command like `IDENTIFY nick pass` **without** the leading slash, +> Orbit catches it, sends it to NickServ privately, and warns you — your password is never +> broadcast. diff --git a/wiki/formatting.md b/wiki/formatting.md new file mode 100644 index 0000000..b3e4294 --- /dev/null +++ b/wiki/formatting.md @@ -0,0 +1,22 @@ +# mIRC formatting + +Orbit renders and lets you compose classic IRC formatting. Use the composer's toolbar (**B** / *I* / +underline / colour), or the keyboard: + +| Style | Key | Code | +|-------|-----|------| +| Bold | Ctrl/Cmd+B | `\x02` | +| Italic | Ctrl/Cmd+I | `\x1D` | +| Underline | Ctrl/Cmd+U | `\x1F` | +| Strikethrough | — | `\x1E` | +| Monospace | — | `\x11` | +| Colour | toolbar | `\x03FF,BB` | +| Hex colour | toolbar | `\x04RRGGBB` | +| Reset | — | `\x0F` | + +Colours use the 99-entry **mIRC palette** (`\x03` followed by a 1–2 digit foreground, optionally +`,background`). Orbit's composer writes these codes for you; incoming messages from any client are +rendered with full colour and styling. + +Formatting is "sticky" — turn on bold and it stays on for the next message, exactly like classic +clients. diff --git a/wiki/orbit-channel.md b/wiki/orbit-channel.md new file mode 100644 index 0000000..2d8638c --- /dev/null +++ b/wiki/orbit-channel.md @@ -0,0 +1,31 @@ +# The #orbit channel & bot + +**#orbit** is the project's live IRC channel. A bot named **`Pulsar`** stays connected there and does +two things. + +## Commit announcements + +Every push to the project's git server, Pulsar posts a GitHub-style summary to #orbit, with mIRC colours: + +``` +[orbit] alice pushed 2 commits to main [+0/-0/±2] https://…/compare/abc…def +[orbit] alice 1a2b3c4 - Fix a thing +[orbit] alice 5d6e7f8 - Add another thing +``` + +## Interactive commands + +Talk to the bot in-channel or by PM (the `!` prefix): + +| Command | Reply | +|---------|-------| +| `!help` | List of commands. | +| `!about` | What Orbit is + link. | +| `!commits [n]` | The latest commits, live from the repo. | +| `!stats` / `!version` | Repo stats / current version. | +| `!source` / `!app` | Repo and live-client links. | +| `!account ` | Whether a nick is a registered account. | +| `!uptime` / `!ping` | Bot status. | + +The bot is a Django management command, so `!account` reads the real account database. Join it from +the client: [open #orbit](https://tchatou.fr/app/?channel=%23orbit). diff --git a/wiki/themes.md b/wiki/themes.md new file mode 100644 index 0000000..9b34661 --- /dev/null +++ b/wiki/themes.md @@ -0,0 +1,17 @@ +# Themes + +Switch in **Settings → Appearance**. Four themes ship with Orbit: + +- **Light** — the clean default. +- **Dark** — low-light palette. +- **yomIRC** — a faithful retro mIRC / Windows-95 skin: silver 3D-bevelled chrome, fixed-width log + lines (`[HH:MM] text`), a flat nick list. For the nostalgic. +- **yomIRC dark** — the retro skin in a deep dark palette with a teal accent. + +Deployers can set the **default theme** for new users in +[`config.json`](/docs/config/) → `defaults.theme` (`light` · `dark` · `yomirc` · `yomirc-dark`). + +Other appearance options in Settings: + +- **Compact mode** — denser message rows. +- **Time format** — 12h / 24h timestamps. diff --git a/wiki/troubleshooting.md b/wiki/troubleshooting.md new file mode 100644 index 0000000..dad1b76 --- /dev/null +++ b/wiki/troubleshooting.md @@ -0,0 +1,27 @@ +# Troubleshooting + +## "Connexion fermée" / the socket closes immediately + +The IRC server is rejecting the **Origin**. Add the host Orbit is served from to the server's +WebSocket origin allow-list (e.g. InspIRCd ``). + +## I don't see the latest version after a deploy + +A service worker is serving the cached build. **Bump the cache version** in `public/sw.js` on every +deploy (`const CACHE = 'app-vN'`) — the worker then auto-reloads installed clients. Or hard-refresh. + +## Notifications don't work + +- The browser must grant permission (Settings → Notifications). +- Web Push when the tab is closed needs the server's `draft/webpush` support (VAPID) **and** you to + be logged into an account (subscriptions are stored per account). + +## The keyboard covers the input on mobile + +Orbit tracks the visual viewport to keep the composer above the keyboard. This works best on +Chromium-based browsers; some other mobile browsers report the viewport late. + +## Channels start empty + +Server-side history needs `draft/chathistory` + a storage backend on the server, and the channel +must have history enabled (e.g. InspIRCd `+H`). Without it, channels begin empty.