Translate one tournament alert locally with QVAC, then deliver the bilingual update directly to joined peers through PearRuntime and Hyperswarm—without an application server.
Touchline Relay is a desktop matchday tool for grassroots football tournaments. An organizer writes a short operational update, translates it on-device with QVAC Bergamot (English → Spanish, French, German, or Portuguese), previews both versions, and publishes a structured announcement to a shared room. A second app instance receives it over Hyperswarm and keeps it in local history.
Tournament updates often get lost across WhatsApp, email, and team apps. When a pitch changes or check-in moves, late or fragmented messages cost volunteers and teams real time. Touchline Relay keeps one critical action: compose → translate locally → publish to reachable peers.
| Layer | Technology | Role |
|---|---|---|
| Local AI | QVAC SDK + Bergamot EN→ES/FR/DE/PT | On-device translation on the organizer’s machine |
| Desktop shell | Electron (Forge package) | UI + main-process QVAC lifecycle |
| P2P runtime | PearRuntime / Bare worker | Owns Hyperswarm membership and relay |
| Networking | Hyperswarm | Direct peer delivery of structured announcements |
There is no cloud translation API, application server, account system, wallet, or general chat feed.
- Translation runs locally after the Bergamot model is cached.
- Messages travel directly between reachable peers.
- Peer discovery still requires network reachability (Hyperswarm bootstrap / DHT). This is not claimed as fully offline LAN messaging.
- 3-minute voiceover + shot list:
docs/demo-script.md - Submission paste pack:
docs/submission-draft.md - What we cut:
docs/roadmap.md
- Launch two instances with separate
--storagepaths. - Join the same room name on both.
- Wait until each shows 1 peer.
- On the organizer: set venue + priority, write an English alert, click Translate locally.
- Confirm Spanish preview and Publish to room.
- On the receiver: the bilingual structured announcement appears in Announcements.
- Linux x64 recommended for the verified package path (this repo also carries macOS/Windows packaging config from the Pear Electron starter).
- Node.js 20+ and npm.
- Network access for first-time dependency install and QVAC model download/cache.
- A display (or Xvfb) to run the Electron UI.
git clone https://github.com/ShalyX/touchline-relay.git
cd touchline-relay
npm installIf Electron fails to install:
rm -rf node_modules/electron
npm rebuild electronIf you see:
Error: Cannot find addon '.' ... rocksdb-native
that almost always means a broken/partial npm install (e.g. earlier ENOSPC) or native modules not rebuilt for Electron.
# 1) Free disk first (need ~10GB free)
Get-PSDrive C
# 2) Clean install
cd C:\Users\USER\touchline-relay
git pull
Remove-Item -Recurse -Force node_modules -ErrorAction SilentlyContinue
Remove-Item -Force package-lock.json -ErrorAction SilentlyContinue
npm cache clean --force
npm install
# 3) Rebuild natives for this Electron version
npx --yes @electron/rebuild -f
# 4) Confirm the Windows prebuild exists and is non-empty
Get-Item .\node_modules\rocksdb-native\prebuilds\win32-x64\*.node | Format-Table Name,Length
# 5) Start two peers
npm start -- --storage .\demo-a
# second terminal:
npm start -- --storage .\demo-bIf rebuild fails, install Visual C++ Redistributable x64 and retry npx @electron/rebuild -f.
Development:
npm start -- --storage /tmp/touchline-aSecond peer (required for the demo; custom storage bypasses the single-instance lock):
npm start -- --storage /tmp/touchline-bRoot / hermesbox (this machine runs as root):
# always pass --no-sandbox as root (also baked into npm start)
npm start -- --storage /tmp/touchline-a
# no display / SSH headless:
xvfb-run -a npm start -- --storage /tmp/touchline-aDemo helpers:
npm run start:demo-a
npm run start:demo-bOptional Chromium remote debugging (used by automated QA):
npm start -- --storage /tmp/touchline-a --remote-debugging-port 9222This is a desktop app, not a website. Users install/run it on their machine (organizer laptop, ops desk, second peer device).
git clone https://github.com/ShalyX/touchline-relay.git
cd touchline-relay
npm install
npm start -- --storage ./data-organizerAnother peer (second machine or second terminal):
npm start -- --storage ./data-peerJoin the same room key on both. Translate on the organizer. The peer receives the bilingual alert.
npm run package
# Linux:
# out/Touchline Relay-linux-x64/Touchline RelayZip that folder (or build installers later) and hand it to users. No account, no cloud API key, no app server.
- Not “terminal only forever” — Electron is a normal desktop UI.
- Not “offline guaranteed” — peer discovery still needs network reachability.
- Not multi-tenant SaaS — there is no hosted production URL in this MVP.
Static design preview (populated mock, not live network): open renderer/index.html?demo=1 in a browser.
npm test
npm run lint
npm run qvac:smoke
npm run packageWhat those mean:
npm test— protocol, renderer state, instance policy, QVAC translator unit tests, and a two-peer Hyperswarm structured-announcement integration test.npm run qvac:smoke— real local Bergamot EN→ES translation via@qvac/sdk.npm run package— Electron Forge package plus a postPackage hook that restores the unstripped QVAC native prebuild (Forge otherwise truncates the Vulkan shared library).
Packaged Linux app:
out/Touchline Relay-linux-x64/Touchline Relay
┌──────────────────────────────┐
│ Renderer (vanilla HTML/CSS/JS)│
│ room · compose · preview · UI │
└──────────────┬───────────────┘
│ preload bridge
┌──────────────▼───────────────┐
│ Electron main │
│ QVAC load/translate/unload │
│ PearRuntime.run(worker) │
└──────────────┬───────────────┘
│ framed IPC
┌──────────────▼───────────────┐
│ Bare worker (PearRuntime) │
│ Hyperswarm room join/publish │
│ structured NDJSON wire msgs │
└──────────────────────────────┘
Key source:
electron/main.js— window, QVAC IPC, Pear worker lifecycle, multi-instance policylib/qvac-translator.js— official Bergamot EN→ES pathlib/protocol.js— room key, validation, wire format, duplicate filterworkers/main.js+workers/relay-node.js— Pear/Bare relayrenderer/— editorial desktop UI (“Crossing the line” mark, proof drawer)
Independently verified on Linux x64:
- 16/16 automated tests pass.
- Lint exits 0 (existing
require-awaitwarnings only). - QVAC smoke produces real Spanish output.
- Packaging preserves QVAC native library byte-for-byte vs
node_modules. - Two Electron instances with separate storage:
- join the same room and see 1 peer each
- organizer translates with local QVAC Bergamot
- receiver history shows English + Spanish structured announcement
- publisher records local relay acceptance only (not universal delivery)
Example translated line from live UI QA:
Kickoff se traslada a Pitch 2 a las 14:30. Reúnase en la puerta norte.
Bergamot quality is operational, not human-editor grade. Venue tags stay structured so names remain unambiguous.
- Leave room without restarting the app
- Peer receipt ACKs (connected peers only — not universal delivery)
- Target languages: Spanish, French, German, Portuguese (QVAC Bergamot EN→*)
- Installer notes:
scripts/make-release-notes.mdanddocs/roadmap.md
- English → Spanish only in MVP.
- No leave-room beyond process restart in MVP.
- No end-to-end delivery receipts from every peer—only local relay acceptance + observed peer receive.
- First model download can take time; keep the demo script ready for a cached model.
- Packaging fix is especially important on Linux x64 for
@qvac/translation-nmtcpp.
MIT. Bootstrapped from the official holepunchto/hello-pear-electron starter architecture, then rebuilt for Touchline Relay.
docs/decision.md— concept selectiondocs/design-brief.md— UI specificationdocs/submission-draft.md— DoraHacks paste-ready copy