A puzzle game about real Outside Plant (OSP) fiber-optic engineering, built in Rust with Bevy, for Android (Google Play + F-Droid), with a squad of anime-styled AI companions — one per access technology — who react to every splice you make.
Quick start
cargo run -p light-showSee docs/BUILD.md for Android build instructions
(Google Play .aab and F-Droid-reproducible cargo-apk paths) and
docs/GAME_DESIGN.md for the full design doc,
including the link-budget model and level progression.



Meet the companions
Pick a companion from the menu before you start splicing — each one is tied to a real access technology, has her own dialogue bank, and reacts to your splices, outages, and level results in her own voice.
![]() Séraphine — Fiber mature |
![]() Ondine — Coax mature |
![]() Linka — Wireless mature |
![]() Lattice — Wired mature |
![]() Séraphine — Fiber base |
![]() Ondine — Coax base |
![]() Linka — Wireless base |
![]() Lattice — Wired base |
Full character briefs, palettes, and mood-sheet specs live in
docs/ART_STYLE.md.
Gameplay
Real captures from the desktop build (scripted input driving the actual game under Xvfb — no mockups). MP4 versions alongside each GIF.
World 2 – Unity Gain. The coax cascade is pre-wired except the line
amplifier: pick the gain that lands the carrier inside the [0, 15] dBmV
window. The ledger at the bottom recomputes the live link budget on
every change. This capture runs the full loop — the first pick (20 dB)
runs hot at Rx: 20.05 dBmV, OUT OF WINDOW; swapping in the 5 dB amp
lands Rx: 5.05 dBmV — SERVICE RESTORED. Captured with the mature
288×576 companion set (see docs/ART_STYLE.md); the previous base-set
captures are kept alongside as *_base.gif/*_base.mp4, and the title
screen as title-screen.png / title-screen_base.png.
World 4 – Storm Season. The aerial route goes up first; 20 seconds in, the scripted storm outage cuts it and the repair banner starts its countdown. Dragging from the protection-route splice to the ONT brings the backup path live — SERVICE RESTORED at Loss: 2.22 dB | Rx: −10.22 dBm | Margin: 2.22 dB | IN WINDOW.
One honest caveat: the outage clip was captured with a temporary build that starts at level 2 — level select doesn't exist yet, and level 2 is only reachable through the results screen.
Project layout
crates/osp_sim/ Engine-agnostic fiber-optic link-budget simulation core
game/ Bevy application: states, UI, level loading, companions
game/assets/levels/ Level definitions (JSON)
game/assets/dialogue/ Per-companion dialogue banks (JSON, localizable)
game/assets/sprites/ In-engine sprite sheets, incl. companion mood sheets
game/assets/audio/ Chiptune music loops + win/fail jingles (.ogg)
assets/art/companions/ Source portraits, animated profile GIFs, app icon art
art/aseprite/ Aseprite-ready sprite sources + headless import script
art/unreal/ Content-only Unreal preview project (Paper2D) for the same art
docs/ Design, art direction, asset pipeline, build, and F-Droid docs
fastlane/ Shared Play Store / F-Droid store listing metadata
tools/ Art + music generation scripts (placeholder art, companion art, chiptune)
Status
Feature-complete gameplay loop: core simulation (osp_sim) is fully
implemented and tested; the Bevy front-end has a working state machine
(menu → playing → outage-repair → results), level loading, win/fail
condition checking with a live dB ledger UI, a companion-select menu,
an outage-repair loop (fault injection, live reroute under a countdown,
in-window vs. timed-out resolution), a results screen with win/fail
banners and companion dialogue, all four companions' dialogue/animation
systems (backed by real AI-generated portrait art and 64x64 in-engine
sprite sheets with per-mood accent tinting), on-board component icon
sprites for every placeable part, and a full Megaman-esque chiptune
soundtrack (menu/playing/outage loops, win/fail jingles) wired to every
state. See docs/ASSET_PIPELINE.md for how
all art/audio is generated and how to take it further in Aseprite or
Unreal. Remaining before store submission is entirely account/asset
logistics rather than code: a signing keystore, real device
screenshots, and the Play Console/fdroiddata listing steps — see
docs/BUILD.md and docs/FDROID.md.
License
GPL-3.0-or-later. See LICENSE and
docs/CREDITS.md for asset attribution.
Music
Twelve licensed tracks ship with the game, grouped below by the music-manager
tier that plays them (game/src/audio.rs). Click a group to expand it, then a
track title for its details and listen link.
GitHub strips <audio> tags from rendered markdown, so an in-README
play/pause button is not possible — the ▶ link is the mechanism: it opens
GitHub's file viewer for the track, which renders its own audio player with
play/pause and scrubbing.
Menu (1 track)
🎵 "We're all under the stars" — Eric Skiff
▶ Listen
Music: Eric Skiff - We're all under the stars - Resistor Anthems - Available at http://EricSkiff.com/music · CC BY 4.0 · Plays on: main menu.
Tutorial, levels 0–1 (1 track)
🎵 "Intensive puzzle resolution" — Komiku
▶ Listen
Komiku (Free Music Archive, https://freemusicarchive.org) · CC0 1.0 Universal · Plays on: tutorial levels.
Early, level 2 (2 tracks)
🎵 "Searching" — Eric Skiff
▶ Listen
Music: Eric Skiff - Searching - Resistor Anthems - Available at http://EricSkiff.com/music · CC BY 4.0 · Plays on: early levels.
🎵 "Ascending" — Eric Skiff
▶ Listen
Music: Eric Skiff - Ascending - Resistor Anthems - Available at http://EricSkiff.com/music · CC BY 4.0 · Plays on: early levels.
Mid, level 3 (2 tracks)
🎵 "Chibi Ninja" — Eric Skiff
▶ Listen
Music: Eric Skiff - Chibi Ninja - Resistor Anthems - Available at http://EricSkiff.com/music · CC BY 4.0 · Plays on: mid levels.
🎵 "Underclocked (underunderclocked mix)" — Eric Skiff
▶ Listen
Music: Eric Skiff - Underclocked (underunderclocked mix) - Available at http://EricSkiff.com/music · CC BY 4.0 · Plays on: mid levels.
Hard, level 4+ (2 tracks)
🎵 "Exhilarate" — Kevin MacLeod
▶ Listen
Kevin MacLeod (https://incompetech.com/music/royalty-free/) · CC BY 4.0 · Plays on: hard levels.
🎵 "Action2 - Army Approaching" — Juhani Junkala / SubspaceAudio
▶ Listen
Juhani Junkala / SubspaceAudio, JRPG Pack 5: Action (https://opengameart.org/content/jrpg-pack-5-action) · CC0 · Plays on: hard levels.
Boss (2 tracks)
🎵 "Basic Metal 5" — TeknoAXE
▶ Listen
Basic Metal 5 by TeknoAXE | http://teknoaxe.com — Royalty Free Music by https://www.free-stock-music.com · CC BY 4.0 · Plays on: boss levels.
🎵 "Action3 - Preparing For Battle" — Juhani Junkala / SubspaceAudio
▶ Listen
Juhani Junkala / SubspaceAudio, JRPG Pack 5: Action (https://opengameart.org/content/jrpg-pack-5-action) · CC0 · Plays on: boss levels.
Victory (1 track)
🎵 "We're the Resistors" — Eric Skiff
▶ Listen
Music: Eric Skiff - We're the Resistors - Resistor Anthems - Available at http://EricSkiff.com/music · CC BY 4.0 · Plays on: victory screen.
Mystery (1 track)
🎵 "In a Heartbeat" — Kevin MacLeod
▶ Listen
Kevin MacLeod (https://incompetech.com/music/royalty-free/) · CC BY 3.0 · Plays on: mystery events.
Full attribution lives in game/assets/music/ATTRIBUTION.txt
(also shown in-game on the credits screen) and
game/assets/music/CREDITS.md.
Store compliance
No ads, no in-app purchases, no tracking, no network permission requested —
the same build ships unmodified to both Google Play and F-Droid. See
docs/FDROID.md for the anti-features checklist.










