Repository navigation
EN Bridge Quick Start
Français · Tutorial · Published, reviewed by a person · Applies from: 4.2.5
In about fifteen minutes, on your own machine, you make the sample game signals react to the world outside: first
with the Studio's simulated Bridge, then with a real Bridge on 127.0.0.1, a signal sent through its demonstration
webhook, and the same signal sent twice. Nothing leaves your machine.
Audience, context, and the statuses of what this page rests on
Audience: author, admin · Context: Reality Bridge
The Reality Bridge,
localprofile (SQLite) · contract: stable · verified by CI (support matrix of 4.4.0, 2026-10-23): Node 22.13+ with node:sqlite, on Ubuntu; Chromium and WebKit end to end · automated checks: jobsreality,reality-xcheck; CI planreality; 2 test files · people's passes: none · known limits:bridge-quick-start-local
The sample game games/signals opens with a garden, a closed gate and an old radio on a bench. At the end of this
tutorial:
- a local Bridge serves the game on
http://127.0.0.1:8787/; - the game, played on
http://127.0.0.1:5173/, is linked to it (pause menu, World link); - a signal
mail.answer.correct, sent through the Bridge, opens the gate; sent again, it is answeredduplicateand changes nothing.
- The engine repository, installed (
npm cidone): Install from the repository. Node 22.12 or newer (Requirements). - Two free ports, 8787 (the Bridge) and 5173 (the game), and
curl. - Three terminals, all in the engine repository's folder.
-
Start the Studio on the sample game:
# in the engine repository GAME=signals npm run studioThe Play tab shows a Reality panel, because the game declares
reality: a button per signal, faults to add (a delay, a duplicate, a bad signature, an expiry), the queue reversed, the connection cut and resumed, and what happened to each delivery. Press the button ofmail.answer.correct: the gate opens.It is a simulated Bridge with a development key, running in the page: the signal goes through the same verification, session, save and deduplication as a real one. Stop the Studio (Ctrl-C) before going on.
-
Create the Bridge's keys and configuration for the game:
# in the engine repository GAME=signals npm run bridge -- initYou see
✔ …/.cache/bridge/config.json (keys, webhook secrets and tokens; mode 600), …/root.key (the root key: grant only) and …/admin-token, then the list of demonstration webhooks, one per source of the game's signals:/v1/hooks/badge, /v1/hooks/webhook, /v1/hooks/email, /v1/hooks/mail, /v1/hooks/terminal. The defaults suit this tutorial: the game's originshttp://127.0.0.1:5173andhttp://localhost:5173, the journal as the store.
-
Start it, in a first terminal:
# in the engine repository, terminal 1 GAME=signals npm run bridge -- serveIt prints one JSON line,
{"event":"bridge.listening","url":"http://127.0.0.1:8787/","game":"signals",…}, and keeps running. Every later event (a pairing, a signal) is one more line here.
-
Start the game, in a second terminal, and open
http://127.0.0.1:5173/:# in the engine repository, terminal 2 GAME=signals npm run devThe game's
reality.bridgeis alreadyhttp://127.0.0.1:8787/(games/signals/game.ts).
- Link the game. Open the pause menu, row World link, and choose "Link this game": the game shows an 8-character code (letters and digits, without 0, O, 1, I or L). It waits for a connector to confirm it.
-
Confirm the code as a connector would, in a third terminal. The demonstration webhook of the source
mailhas a token that may confirm pairings; replaceABCD2345with your code:# in the engine repository, terminal 3 TOKEN=$(node -p 'require("./.cache/bridge/config.json").webhooks.mail.token') curl -s -X POST http://127.0.0.1:8787/v1/pairings/ABCD2345/confirm -H "Authorization: Bearer $TOKEN"
The answer is
{"playerId":"p-…"}: 16 hexadecimal digits, a pseudonymous id the Bridge made up. Terminal 1 logs"event":"pairing.confirmed". The game asks the Bridge every two seconds whether its code was confirmed: it collects its link by itself and says it is linked. Note theplayerIdfor the next step.
-
Send the signal through the demonstration webhook. A webhook request is signed with an HMAC-SHA256 of its body under the webhook's secret; this one-liner reads the secret from the configuration and signs. Replace the
p-…:# in the engine repository, terminal 3 node -e ' const { createHmac } = require("node:crypto"); const [playerId] = process.argv.slice(1); const { secret } = require("./.cache/bridge/config.json").webhooks.mail; const body = JSON.stringify({ playerId, event: "answer.correct", id: "try-1" }); const signature = "sha256=" + createHmac("sha256", secret).update(body).digest("hex"); fetch("http://127.0.0.1:8787/v1/hooks/mail", { method: "POST", body, headers: { "Content-Type": "application/json", "X-Web-Scumm-Signature": signature } }) .then(async (r) => console.log(r.status, await r.text())); ' p-0123456789abcdef
It prints
202 {"id":"s-…","sequence":1,"duplicate":false}. In the game, the gate opens. The eventanswer.correctof the webhookmailis the signalmail.answer.correct;idnames this delivery.
- Run the same command again. It prints
200 {"id":"s-…","sequence":1,"duplicate":true}: the same id, the same sequence. The Bridge kept the first one; the game changes nothing.
- Stop the Bridge and the game with Ctrl-C in their terminals. The Bridge says
"event":"bridge.stopping"and exits.
Limit ·
bridge-quick-start-localThis tutorial runs on one machine, over plain HTTP, with demonstration webhooks that may send any signal of their source for any player for 30 days. That is for development only: on the Internet the Bridge runs behind HTTPS, withinit --no-demo-webhooksand one narrowgrantper connector (Install and run the Bridge).
What you just did by hand is what a connector does for a player. On the player's side:
- The pause menu's World link row offers "Link this game", which shows the 8-character code the player gives to the game's connector: answer the email with it, type it at the terminal's prompt, post it with a badge, enter it in a webhook's form. The code waits ten minutes. Once a connector confirms it, the game is linked.
- The link is announced politely, never over a line being said. Signals that arrive while the game is busy (a dialogue, a cutscene, a minigame) wait for it. Offline, the game plays on; back online, what arrived meanwhile is applied.
- The browser keeps the Bridge's URL, the pseudonymous player id and a capability that can only read and acknowledge
this game's signals, under
<game>:reality-linkinlocalStorage. They are never written into a save or a session. A new game on the same device keeps the link. "Unlink" in the same menu revokes the link on the Bridge, not only on the device. - The interface texts are
realityLink,realityStart,realityCode,realityWaiting,realityOpen,realityOffline,realityRevoked,realityNone,realitySimulated,realityUnlink,realityMismatchandrealityRelink, in the game'sui; the English defaults are insrc/engine/dom/reality-ui.ts(Translations). - The player verifies each signal with the Bridge's keys, each within its window, and a signal's expiry, with five
minutes of tolerance for the device's clock (
CLOCK_SKEW_MSinsrc/engine/reality/protocol.ts, the same in the Rust cross-check). When a signal names a key the keyring does not hold (the Bridge rotated while the link was open), the client asks for the keys once before refusing it. - A
WorldSignalV2(ADR 0010) names the tenant, the environment, the origin the player paired from, the link and the key it was signed for, and the player refuses one signed for another context (audience-mismatch), the page's origin checked by default. A Bridge serving several tenants signs V2 only; a single-tenant Bridge signs V1 unless its configuration sayssignalVersion: 2(init --signal-version=2), and the player accepts both (Security).
What the save keeps, and what happens when a save meets another player's link: Guarantees.
games/signals has a chapter, "the mailbox and the terminal", played with the real connectors. Link the game (pause
menu, World link), then:
- write to the gate with "open the door" in the subject or the text, and the shed's door opens (the email connector);
- type
lamp onat the shed's terminal, over Telnet or SSH, and a lamp glows in the garden; - show a badge from the garden guild, and a ribbon lands on the bucket (the Open Badges connector).
None of it is needed to finish the game: the radio on the bench still opens the gate. The Telnet terminal is the quickest to try locally. With the Bridge of step 2 running:
# in the engine repository, terminal 3
GAME=signals npm run bridge -- grant --connector=shed-telnet --source=terminal --signals=terminal.lamp --pair > .cache/bridge/telnet.token
cat > .cache/bridge/telnet.json <<'EOF'
{
"bridge": { "url": "http://127.0.0.1:8787/", "tokenFile": "telnet.token" },
"gameId": "signals",
"health": { "port": 9301 },
"telnet": { "port": 2323 }
}
EOF
npm run connector -- telnet --config .cache/bridge/telnet.jsonThen, from a fourth terminal, nc 127.0.0.1 2323 (or telnet 127.0.0.1 2323): the shed's banner asks for the
pairing code your game shows; type it, then lamp on. The terminal answers "Click. Somewhere in the garden, a lamp
glows." Each connector is described on its own page: Telnet,
SSH, email, Open Badges.
- A signal is a declared identifier, sent by a connector and signed by the Bridge: The Reality Bridge: what it is.
- Pairing links one game on one device to a pseudonymous player; the game keeps a capability that reads its own signals only: Security.
- A signal sent twice is accepted once: Guarantees.
- Declare your own game's signals: Signals and the manifest.
- Run a Bridge for real players: Install and run the Bridge.
- When something goes wrong: Bridge and connector troubleshooting.
Generated publication · publication générée — current documentation · documentation courante: quest'n'click 4.5.3 r1, documentation revision · révision de la documentation b061c4ae6fbeb0be47a11ba8a442ba7e23ecb0a1.
Latest documentation · dernière documentation: https://quest-n-click.cleverapps.io/docs · https://quest-n-click.cleverapps.io/fr/docs; earlier versions · versions précédentes: each release's quest-n-click-docs-<version>.tar.gz · l'archive quest-n-click-docs-<version>.tar.gz de chaque release, https://github.com/Quest-n-Click/quest-n-click/releases
An edit made in this wiki is overwritten at the next publication · une modification faite dans ce wiki est écrasée à la publication suivante.
Edit the source · Modifier la source · Report an error · Signaler une erreur
Index (6)
Start (6)
Play (9)
Install (18)
- Requirements
- Install from the release archive
- Install from npm
- Install from the repository to work on the engine
- doctor: checking your machine
- Image toolchain
- Audio toolchain: ffmpeg, fluidsynth, Furnace, uv
- Upgrade
- Upgrade notes: 4.5
- Upgrade notes: 4.4
- Upgrade notes: 4.3
- Upgrade notes: 4.2
- Upgrade notes: 4.1
- Upgrade notes: v3
- Upgrade notes: v2 to v3
- Coming from web-scumm
- Package reference
- Install troubleshooting
Create a game (55)
- Your first game
- Layout of a created project and of the engine repository
- The working loop
- Content principles and the identity contract
- Rooms
- Geometry: placement, walk zones, masks, layers, camera
- Something is visible but unreachable
- Reactions
- Game commands
- Conditions
- Flags, variables and events: which to use
- Custom code
- Characters
- Items and inventory
- World map
- Dialogues
- Scripts and events
- Moving characters: patrols and walks
- Exits
- Chapters and objectives
- State and saves: persistent or temporary, renaming an id, migrations
- Staging: wide rooms and animations
- The stage: lights, particles, floors
- Skin and fonts
- Title and credits
- Heroes: several characters and hero choice
- Built-in minigames
- A custom minigame
- Translations
- Music in stems
- Sound effects
- Voices: per language and per hero
- Images: prompts, cutting sheets, transparency, scale
- Asset provenance
- The storyboard, source of truth
- Puzzle design
- Classic mechanics
- Review pages
- DSL reference
- Checking your game
- What the solver proves
- Solver options
- Playtests
- Remix
- Speedrun for authors
- The sealed ending
- Production template
- Example games
- Working with an AI
- Build and release a game
- Publish on GitHub Pages
- The static game on Clever Cloud
- Other static hosts
- Sub-path, cache and service worker, incomplete deploys, going back
- Testing on a phone over the LAN
Local Studio (24)
- The local Studio: overview and launch
- Edit a room
- Placement and stage
- Preview, apply, undo
- Storyboard
- Assets and cutting
- Check: validator, solver, critical path, heat, health, coverage
- Before and after captures
- Semantic diff
- Play and replay a session
- Rule explainer
- Language and objectives
- Voices and the heroes × languages matrix
- Map
- Notes
- Remix in the Studio
- Music
- The Assistant: bring your own key
- Demo mode and studio-apply
- Local and LAN security
- Studio API
- Local MCP: setting up each client
- MCP tools
- Studio troubleshooting
Team Studio (21)
- What runs where
- Concepts: revision, transaction, span, lease, preview, build
- Starting as an invited dev
- Working together day to day
- Roles and actions: the full matrix
- Invitations
- Managing members
- Write refused on the hosted Studio: stale base revision (409)
- Write refused on the hosted Studio: span locked (423)
- Recovering after a lost lease, a disconnection or a stale preview
- Comments
- Map and semantic diff
- Publishing builds
- Remote MCP
- The game in Git
- Upgrading the engine of a hosted game
- Hosted assets
- The server's command line
- Health and metrics routes
- Trying it locally with compose.yml
- Known limits
Clever Cloud (23)
- Clever Cloud: overview, cost and prerequisites
- Apps and add-ons
- Domains and TLS
- Keycloak
- Generic OIDC and GitLab
- Configuration
- First deployment
- Backups
- RPO and RTO
- Restore the Studio on a fresh installation
- Redeploys
- Upgrading the server and checking state after a migration
- Limits of going back
- Monitoring
- Security
- Rotating keys
- Recovering admin access
- Changing domain or OIDC provider
- Worker, PostgreSQL or Cellar down
- Exporting the game and leaving the installation
- Retention
- Clever Cloud troubleshooting
- Costs and teardown
Reality Bridge and connectors (16)
- The Reality Bridge: what it is
- Quick start
- Guarantees
- Install and run the Bridge
- Backup and restore
- Several tenants
- Signals and the manifest
- The Bridge's command line
- Connectors overview
- Email connector
- Telnet connector
- SSH connector
- Open Badges connector
- The connector SDK
- Security: Biscuit and signatures
- Bridge and connector troubleshooting
Contribute (25)
- Welcome
- Developer setup
- The dev loop
- Before a pull request
- Conventions
- Writing documentation
- Architecture
- Code tour
- Import boundaries
- Which tests run when
- Mutation testing
- The coverage ratchet
- The quality baseline
- CI explained
- Field passes
- Benchmarks
- Releasing
- npm packages
- Decisions and ADRs
- Governance
- Bot pull requests
- Contributing with AI agents
- Security policy
- Code of conduct
- Licences and credits