Documentation

Contributing

How the repository is laid out and how to send a change.

Repository layout

src/
  app/                     routes
    (marketing)/           public site and docs
    (app)/                 signed-in surfaces
    prompter/[roomId]/     the display
    remote/[roomId]/       the remote
  components/
    brand/  ui/  marketing/  docs/  app/  pwa/
    prompter/              engine, canvas, session hooks
  lib/
    markdown/blocks.ts     deterministic script splitter
    prompter/state.ts      state shape, limits, themes
    realtime/              protocol, link, WebRTC mesh
  server/
    api/routers/           tRPC: script, room
    auth/                  Auth.js config and guards
    db/                    Drizzle schema and client
scripts/
  generate-brand-assets.mjs   renders the app icons

Getting set up

Follow Running your own; a contributor setup and a self-hosted setup are the same thing. You need your own Supabase project and at least one OAuth client of your own; there is no shared development backend.

Conventions

  • TypeScript is strict, including noUncheckedIndexedAccess. npm run typecheck has to pass.
  • Prettier decides formatting. npm run format before you commit.
  • Anything off the network is validated with Zod before it is used, on both the tRPC boundary and the realtime one.
  • The frame loop does not touch React. If you are adding something that runs per frame, it belongs in the engine, not in state.
  • Comments explain decisions, not mechanics. Say why the anchor is not a scroll offset; do not narrate what the next line does.
  • No emoji in the interface, and no placeholder copy. Every string is real.

Testing a change by hand

There is no substitute for two real devices. The sync path in particular cannot be exercised in one browser window, because the WebRTC tie-break and the presence ordering both depend on there being two device keys.

  1. Run npm run dev and open the display on your computer.
  2. Reach the dev server from your phone on the same network, or use a tunnel. Remember that WebRTC and the wake lock need a secure context, so a tunnel with HTTPS is more representative than a LAN IP.
  3. Check the badge on both devices. If it says Direct, the peer path is live; if it says Relay, you are exercising the fallback.
  4. Test a reload mid-session. Persistence is easy to break and easy to miss.

Worth knowing

Force the relay path by disabling WebRTC in the browser, or by putting one device on a network that blocks UDP. Both paths need to work, and the relay one is the one users on venue Wi-Fi will actually get.

Wanted

  • TURN support. An optional, configurable TURN server so direct routes are possible on hostile networks.
  • Import. Google Docs, plain text, and a paste handler that converts formatting to Markdown.
  • Timed segments. A per-section target duration with a countdown on the remote.
  • Foot pedals. Gamepad API mapping, so a pedal can drive play and step.
  • Accessibility. Screen-reader behaviour on the prompter surface deserves a proper look.

Sending a change

  1. Open an issue first for anything that changes the sync protocol or the data model.
  2. Branch, make the change, run typecheck and format.
  3. Describe what you tested and on which devices. “Two devices, same Wi-Fi, direct” is useful; “works for me” is not.
  4. Open a pull request against the repository.

Teleprompt is MIT licensed and maintained by Biios. Contributions are accepted under the same licence: a merged patch carries your name in the history and nothing else changes hands.