App

Light Show

Light Show

Source on GitHub

OVERVIEW

Light Show is a puzzle game about real Outside Plant (OSP) fiber-optic engineering, built in Rust with Bevy for Android (Google Play + F-Droid) and desktop, in which the player routes light from the OLT (Point A) to the customer ONT (Point B) to land inside a target receive-power window while anime-styled companions — one per access technology — react to every splice. All loss figures are real: fusion vs. mechanical splice loss, UPC vs. APC connectors, PON splitter ratios, and wavelength-dependent fiber attenuation.

HOW IT WORKS

  1. 1Pick a companion from the menu before splicing — each is tied to a real access technology with its own dialogue bank (Séraphine — Fiber, Ondine — Coax, Linka — Mobile, Lattice — Ethernet in the README set).
  2. 2Survey the board: a grid-based OSP map of OLT, splice enclosures, splitters, patch panels, ONT, and cable spans (aerial, buried, conduit).
  3. 3Route the light by dragging fiber jumpers / choosing splice paths to connect A to B; every component placed consumes optical budget and the live dB ledger (OTDR-style) recomputes `P_rx (dBm) = P_tx (dBm) − Σ(loss) + Σ(gain)`.
  4. 4Hit the window: received power at B must land inside the level's design window (e.g. −8 dBm to −27 dBm for GPON per ITU-T G.984) with a single continuous A→B path — too hot fails as well as too cold.
  5. 5Survive the outage event: mid-level a fault fires (fiber cut, water intrusion, bad splice, macrobend, connector contamination) and the player must reroute, patch, or splice around it before the customer-complaint timer expires.
  6. 6Progress through worlds — Splice School → Patch Panel → PON Split → Storm Season (Outages) → Long Haul → Séraphine's Route (bonus/endless) — as the companion reacts to splices, outages, and results.
How it works, step by step — each step as the project's own documentation states it.

CONCEPTS

ONE ROUTE, SCORED IN DECIBELSOLT+3.0 dBmCONN. UPC−0.35 dBFUSION SPLICE−0.075 dBFIBER 10 KM−2.8 dB · 1490 nmSPLITTER 1×8−10.6 dBAPC−0.30 dBONTrx2.652.58−0.23−10.83−11.13 dBmGPON RECEIVE WINDOW (ITU-T G.984) — TOO HOT FAILS TOO+5−8−27−30 dBmthis route arrives at −11.1 dBm — inside the windowswap in a mechanical splice (−0.4 dB) or a 1×32 splitter (−17.7 dB)and the same route misses — the ledger recomputes on every placementattenuation: 0.35 dB/km at 1310 nm · 0.28 at 1490 nm · 0.21 at 1550 nm
A worked link budget with the simulation's own loss figures — the ledger every route is scored by, recomputed live as components are placed. The 10 km span length is illustrative; every loss constant, and the receive window, is the game's.
\[P_{rx} = P_{tx} - \sum \text{loss} + \sum \text{gain}\]

All powers in dBm, all losses and gains in dB. P_tx is the OLT launch power (+3.0 dBm in the bundled levels, the GPON class B+ figure of ITU-T G.984.2). Each loss term is one placed element: fiber attenuation (0.35 dB/km at 1310 nm, 0.28 at 1490 nm, 0.21 at 1550 nm), a splitter (3.6 dB at 1×2 up to 17.7 dB at 1×32), a splice (0.075 dB fusion, 0.4 dB mechanical), a connector (0.35 dB UPC, 0.30 dB APC). The route wins when P_rx lands inside the level's receive window — for GPON, −8 to −27 dBm — and too hot fails exactly as too cold does.

The link-budget equation, as the game's design documents state it and osp_sim computes it.
Actual gameplay, from the project's own documentation (docs/gameplay/): a level-one route being built from the OLT toward the customer ONT, the dB ledger tracking each placement.
The outage event, from the project's own documentation: a scripted fault breaks the route mid-level and the repair must beat the customer-complaint timer.

CONFIGURATION

OptionDefaultWhat it does
`tx_dbm` (level JSON)3.0` in both bundled levels; `DEFAULT_TX_DBM = 3.0OLT launch power in dBm; GPON class B+ downstream per ITU-T G.984.2 unless a level overrides it
`window_min_dbm` / `window_max_dbm` (level JSON)`-27.0` / `-8.0` in both bundled levelsTarget receive-power window the routed path must land inside to win
`wavelength` (level JSON)`Nm1490` in both bundled levelsOperating wavelength; attenuation is 0.35 dB/km at 1310 nm, 0.28 at 1490 nm, 0.21 at 1550 nm
Fusion splice loss`0.075 dB` typical (range 0.05–0.1 dB)Lowest-loss splice; place time 45.0 s in the sim model
Mechanical splice loss`0.4 dB` typical (range 0.3–0.5 dB)Faster splice used under outage pressure; place time 10.0 s
Connector UPC / APC loss`0.35 dB` / `0.30 dB` (return loss −50 dB / −60 dB)Patch-panel connectors; APC required on reflectance-sensitive / PON levels
Splitter 1×2 / 1×4 / 1×8 / 1×16 / 1×32 loss3.6` / `7.3` / `10.6` / `13.7` / `17.7 dBPLC splitter insertion loss for PON fan-out levels
Android `minSdk` / `targetSdk`26` / `34Android 8.0+ floor; `game/Cargo.toml` `[package.metadata.android]` (`package = ai.qompass.lightshow`, fullscreen, OpenGL ES 3.0)
`instrumented-test-logging` Cargo featureoff by defaultEmits board `level_ready` / `select` / `connect` events to Logcat (tag `LightShow`) for on-device tests only; zero footprint in retail builds

CONTROLS

ActionControl
Run the game (desktop dev loop)cargo run -p light-show
Run simulation testscargo test -p osp_sim
Pick a companionClick/tap a companion-picker button in the main menu (sets `SelectedCompanion`)
Route / place a componentDrag node → node with left mouse button (desktop) or touch drag (Android); press resolves the start node, release on a target node connects the chosen component
Build APK (fast path)cargo apk build --release` in `game/` after `rustup target add …` + `cargo install cargo-apk
Build Play Store bundlecargo ndk … build --release`, then `./gradlew bundleRelease` in `android/` → `app-release.aab
Windows trial buildExtract the Releases zip, keep `assets` next to the `.exe`, double-click; SmartScreen → More info → Run anyway (unsigned trial build)

NOT COVERED

- Sandbox clone (`~/workspace/repos/light-show`, Sep 2025) is older than GitHub `main` and the primo clone (`~/.GH/Qompass/LightShow`): GitHub/primo add many more levels (per-companion 10-level tracks), four extra companions in primo `game/src/waifu/mod.rs` (Clara — Calix CMS, Aino — Nokia AMS, Hikari — FTTH/OSP, Léa — WA 09 Telecom Admin prep), a chiptune soundtrack, and trial-build downloads; only the two sandbox levels (`world1_level1.json`, `world4_level1_outage.json`) were field-verified here — level counts beyond those two are primo-listing only. - License differs by snapshot: sandbox `Cargo.toml`/`LICENSE` say GPL-3.0-or-later; GitHub README badge/text say Apache-2.0. Not reconciled in sources read. - No in-game settings/config file (volume, difficulty, window size) is documented in the sources read; difficulty is per-level data, not a user option. Full outage-repair UI was listed as “next milestone” in the sandbox README but as implemented (state machine menu → playing → outage-repair → results) in the GitHub README — status text was not re-verified by running the game.

REFERENCES

  1. ITU-T G.984.2 — GPON: Physical media dependent (PMD) layer specificationThe class B+ optical parameters behind the game's launch power and its −8 to −27 dBm receive window.
  2. ITU-T G.984.1 — GPON: General characteristicsThe GPON architecture the game's outside-plant board models: OLT, splitters, and ONTs on one passive tree.