Skip to content
View LuckyMonkey's full-sized avatar
  • Almost-There.org
  • Boston

Block or report LuckyMonkey

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Content in all repositories owned by your account will be closed.
Maximum 250 characters. Please donโ€™t include any personal information such as legal names or email addresses. This note will only be visible to you.
Report abuse

Contact GitHub support about this userโ€™s behavior. Learn more about reporting abuse.

Report abuse
luckymonkey/README.md

๐Ÿต Lucky Monkey: On-Call in the Jungle

A browser game about keeping a make-believe jungle network alive through one on-call shift. Routers are temples, firewalls are vine gates, the database lives in a lake, and the outages are real ones in costume.

Play in your browser Training shift

Rust Bevy WebAssembly Data driven Tests Faults Nodes

The archipelago: floating islands, one river from void to void, rope links between islands

It is 09:00. You are on call. A stampede of bison is about to hit the Banana Cache, a worm is reaching across the vines, and the certificate on the Auth Gate expires in fifty seconds. The Watchtower can see some of it coming. Not all of it.


๐Ÿ“š Contents


๐ŸŽฎ How to play

An incident: the big red Time to Loss timer, red rope links to the troubled node, the crew and the shared network log

You run a small crew through an 8-minute shift (09:00 โ†’ 17:00 on the game clock). Things break. You read the symptoms, send someone, pick the response, and race the โณ Time to Loss.

1. Learn the network first. Nothing breaks until you start.

Key Mode
T ๐Ÿ—บ๏ธ Tour Island by island through all 28 nodes: what each one is, its lore, what it links to, and how many services lose their path if it goes down
P ๐Ÿงช Practice One problem at a time, timers ร—3, nothing spreads, no game over
B ๐Ÿ“– Field guide Every concept you've met, with the example where you met it

Tour mode

2. Delegate to your crew

Faster at Can't
๐Ÿต Mango the monkey good at everything
๐Ÿฆœ Pip the parrot diagnosis heavy work
๐Ÿฆฅ Moss the sloth maintenance: certs, patches, canaries
๐Ÿธ Fern the tree frog hardware: cables, vents, power
๐Ÿ˜ Tusk the elephant heavy work: rollbacks, hotfixes, replicas

Pick a response and a crew member runs it straight away, in about 2.5 s. They still travel to the node on the map, but nothing waits for them. Each runs one thing at a time, so the whole crew can work five problems at once.

3. Find the origin, not the symptoms

DNS left alone: two neighbours already failing because of it, each pointing back to the origin

Every problem starts somewhere for a reason ("A botnet of a million bison found the Banana Cache on the open internet") and, left alone, spreads along its links as its timer runs down.

  • ๐ŸŸก Warning: nothing is broken yet. Prevent it (renew the cert, canary the deploy) for bonus points.
  • ๐Ÿ”ด Incident: the origin. It's degraded and counting down; at 0 it goes down.
  • ๐Ÿ“‰ Symptom: a neighbour suffering from it. Nothing to fix there: O jumps to the origin, and fixing the origin clears every symptom at once.
  • ๐Ÿ› Worms are contagious: they infect neighbours for real.
  • ๐Ÿฉถ Unreachable: fine, but cut off because the only path runs through a down node.

4. Run the command, read the verdict

Four responses to the same DDoS: two wrong, one that buys time, one that fixes it

Pick one of four responses. The terminal types the real command, streams its output, runs a health check, and then says โœ… CORRECT, ๐Ÿฉน PARTLY (it bought time) or โŒ NOT THE FIX, with the reason. Not sure? ๐ŸŒ H spends a banana on a hint, or ๐Ÿ” I diagnoses every option.

Diagnosed: every option labelled with what it would do

5. Keep the SLA

Network health is the network right now. Shift SLA is its average over the shift, and you need 95% to pass and unlock the next level. At the end you get your score, โœ… what went right, โš ๏ธ what went wrong (with specifics such as "ใƒกใ‚คใƒณใƒซใƒผใ‚ฟใƒผ Router went down when its Time to Loss ran out, cutting off 27 other service(s)"), and your shift history.

End of shift

โŒจ๏ธ Keys

Enter start ยท Space most urgent ยท Tab cycle problems ยท 1-4 respond ยท I diagnose ยท H ๐ŸŒ hint ยท O go to the origin ยท Z X C V N pick a crew member ยท G send ยท arrows hop nodes ยท Q/E islands ยท WASD/drag pan ยท wheel/pinch zoom ยท F follow

๐Ÿ“ฑ On a phone: drag, pinch, tap a node, tap a response. Off-screen nodes become pins on the screen edge. Tap one to fly there.

โ–ถ Jump straight into a situation: DDoS on the Banana Cache ยท a deploy that migrated the database ยท a certificate about to expire ยท DNS down

Full rules: docs/gameplay.md


๐Ÿง  What it teaches

Under the jungle paint, every fault is a real production failure and every right answer is the first move an experienced operator would make. All 18 fault types โ†’

In the jungle In real life
๐Ÿ’ฅ Service crashed โ†’ ๐Ÿ”„ restart a process can die while the machine still answers ping
๐Ÿ“› Names don't resolve, IPs work โ†’ fix DNS the classic "it's always DNS"
๐Ÿท๏ธ New devices get no address โ†’ expand the DHCP pool address exhaustion
๐Ÿฆฌ Stampede on one endpoint โ†’ block with an ACL (rate-limit only buys time) DDoS: mitigation vs remediation
๐Ÿ“‰ Neighbours failing because of one broken node โ†’ fix the origin, not the symptoms root cause and blast radius
๐Ÿ› Worm โ†’ patch (quarantine only buys time) containment vs eradication
๐Ÿ“ฆ Bad deploy โ†’ roll back; with a schema migration โ†’ fall forward when rollback is and isn't safe
โš–๏ธ Replicas disagree โ†’ resync from the primary replication lag and split brain
๐Ÿ” Routing loop, ๐Ÿ“ข broadcast storm (โ†’ Spanning Tree), ๐Ÿ๏ธ wrong VLAN layer 2 and 3 failure modes
๐Ÿ” Expiring certificate โ†’ renew it. "Disable TLS" is refused, with the reason security isn't optional under pressure
๐Ÿฉถ Router down โ†’ 27 services unreachable root cause vs dependency impact, blast radius
๐Ÿ“… ๐Ÿงฌ ๐Ÿ’พ warnings proactive vs reactive work: prevention is cheaper
โณ Time to Loss prioritising by consequence, not by noise

It also teaches the shape of on-call: triage, delegating to people with different strengths, not burning out your crew, and reading the symptom before grabbing a tool. "Time to Loss" is the game's own term, and the field guide is explicit that it is not IP TTL or DNS TTL.


โš™๏ธ How the game code works

 game/data/*.json โ”€โ”€โ–ถ data.rs โ”€โ”€โ–ถ sim.rs (the rules: no Bevy, fully testable)
   tuning ยท islands ยท              โ–ฒ   โ”‚ health, faults, crew, director, log
   nodes ยท world ยท npcs            โ”‚   โ–ผ
                    keys/clicks โ”€ ops.rs (HUD, Time to Loss, overlays, pins, input โ†’ orders)
                                   โ”‚
           world.rs ยท water.rs ยท clouds.rs ยท npc.rs ยท view.rs ยท ui.rs   (Bevy ECS: drawing)
  • Bevy 0.20, Rust โ†’ WebAssembly โ†’ WebGL2. One isometric projection function, one terrain mesh per diagonal row so depth sorting is exact, a texture atlas for the tiles. โ†’ docs/engine.md, docs/world.md
  • sim.rs is the whole game model, with no engine. Each frame the screen calls Sim::step(dt) and draws the result. A separate native crate, game/simtest/, compiles the same file and runs 14 rule tests plus a balancing harness with bot players (Idle / Novice / Beginner / Expert ร— 4 levels ร— 20 seeds). โ†’ docs/simulation.md
  • Health is a graph walk. After every change a breadth-first search from the core router marks what's reachable. Anything cut off is Unreachable, so root causes and impacts never get mixed up.
  • An incident director deals new trouble only after a grace period, under a per-level budget, and never while the network is already on its knees.
  • Workers route over the links with Dijkstra (flyers go straight). The game picks whoever would finish first unless you choose.
  • One event log groups related events ("27 services unreachable" is one line, not 27).
  • The map is data. tools/gen-world.py turns islands.json + nodes.json into the archipelago: one river from void to void, canyons where islands rise above it, vine bridges, free-floating islands, hanging pixel vines.

Router down: everything behind it unreachable

File What
game/src/sim.rs rules: faults, responses, director, crew, routing, health, SLA, scoring, event log
game/src/ops.rs the game screen: HUD, Time to Loss, roster, alerts, log, rope links, edge pins, tour, summary, input
game/src/ui.rs welcome gate, node panel
game/src/world.rs terrain meshes, vines, decorations, node cards
game/src/water.rs ยท clouds.rs ยท npc.rs waterfall, bubbles, data frames ยท clouds, rain, lightning ยท wandering critters
game/src/view.rs ยท link.rs camera, touch, picking ยท deep links (#node=โ€ฆ&incident=โ€ฆ)
game/src/data.rs loads live JSON, merges over built-in copies, never crashes on a bad file
game/simtest/ native tests + balancing bots
tools/ world generator, doc generator, texture packer, font subsetter, build scripts

๐Ÿ› ๏ธ Build and run it yourself

rustup target add wasm32-unknown-unknown
cargo install wasm-bindgen-cli --version 0.2.129 --locked   # must match game/Cargo.lock
tools/build-web.sh                     # builds into web/game
python3 -m http.server -d web 8080     # open http://localhost:8080

Run the rules tests and the balancing table (native, no browser needed):

cd game/simtest
cargo test --release
cargo run --release --bin balance

A release build needs a few GB of disk and takes a while the first time (Bevy is big). The live site also runs inside a small Next.js host page (app/page.tsx). tools/deploy.sh is the author's own deploy to their server.


โœ๏ธ Change the game without recompiling

Everything worth tuning is JSON in game/data/, fetched when the page loads:

File Holds
tuning.json every fault, response, action, crew member, level, the training script, concepts, numbers
islands.json the archipelago: islands, heights, hills, river, bridges
nodes.json the 33 nodes: names, emoji, connections, lore
world.json generated from the two above by tools/gen-world.py

Edit, run python3 tools/gen-world.py (if you touched the map), copy into web/game/data/, and reload. A broken file falls back to the built-in copy, so a typo can't take the game down. Add a fault in JSON and it's in the game, in the docs (tools/gen-docs.py), and in the deep links.


๐Ÿ“– Documentation

๐ŸŽฎ How to play rules, crew, levels, keys
๐Ÿ’ฅ Failure types all 18 faults: symptom, fix, mitigation, why (generated from the data)
๐Ÿ๏ธ Nodes and lore the legend, every island and node, its role and story (generated)
๐Ÿงฎ The simulation the model, director, workers, tests and balancing numbers
๐ŸŽฏ On-call design why the loop works the way it does
๐Ÿ–ฅ๏ธ Interface layout, phone layout, camera, deep links, Bevy UI traps
๐ŸŒ‹ The world isometric maths, terrain, the archipelago, water, clouds
๐Ÿฆ€ The engine Bevy and ECS, explained for this project
๐Ÿ”ง Build, deploy and test ยท Extending
๐Ÿ–ผ๏ธ A tour in pictures ยท Overview and history ยท Decisions ยท Glossary
๐Ÿ“ฆ Outside assets and licences ยท Isometric engine extraction report

๐Ÿ™ Credits and licences

Made by LuckyMonkey ๐Ÿ’๐ŸŒ

Pinned Loading

  1. photosort photosort Public

    exif pipelines for no-cloud local image organization with quality of life features

    C 3 2

  2. Csharp Csharp Public

    HEIC/HEIF โ†’ JPEG decoder written in C. Named to annoy Microsoft and Apple in one go. The HEIC dependency for photosort.

    C

  3. aspartame-linux aspartame-linux Public

    Arch-derived Linux with a modernized Sugar desktop and Python as a first-class citizen. Paused.

    Python

  4. snakepit snakepit Public

    Python sandboxing subsystem for Aspartame Linux โ€” 'put the Python in the box'

  5. eightpaint eightpaint Public

    eightpaint

    HTML

  6. xfcePlasma xfcePlasma Public

    animated plasma wallpaper with icon solution

    Shell