openCycle GitHub
The openCycle ride screen: two ships chase a raider past a black hole, with the route strip across the top and rider cards at the bottom.

Recorded on the built-in simulator

The workout is the flight plan.

openCycle holds your KICKR at the watts the workout asks for, records every ride as a FIT file, and flies a fleet of ships to a new star system while you pedal.

View on GitHub Run it

MIT licensed · macOS and Node 24 · tested with a Wahoo KICKR CORE over Bluetooth FTMS ERG

A trainer controller, a recorder, and a game.

One app covers the indoor season: the trainer, the workout, the file that lands in Garmin, and the flight you watch while you ride it.

A burn leg in progress: the ship fires at a raider inside a lock ring, the route strip reads BURN 1/4 with LOCK 100%, and the rider card shows the target watts, cadence and heart rate.
A burn leg at 115% FTP. Hold the watts and your ship keeps firing; the route strip shows the lock building.
ERG control
Your trainer gets the target over Bluetooth FTMS ERG and holds it there. You pedal, and the resistance follows the workout step by step.
Several riders, one machine
Two or more riders can ride a session on the same computer, each with their own trainer, heart rate strap, targets and FIT file.
A FIT file for every ride
Every session is recorded as a standard FIT file. Download it from History, or let it upload to Garmin Connect.
Workouts and plans
Curated workouts and multi-week plan templates ship with the repo as JSON. Write your own, then check the whole library with one command.
Garmin import and upload
Drop a Garmin account export into the import folder to bring old rides back in. Turn on auto-upload in a profile, save a Garmin login once, and finished rides upload to Garmin Connect.

Every workout is a flight to a new system.

The ride screen is a voyage flown by the workout you are doing. Every system has something enormous to fly toward: a black hole bending the starlight around it, a blue supergiant or a binary pair. The trainer, the targets and the FIT file stay the source of truth: the game only reads them.

  1. Launchlaunch, 450 seconds
  2. Launchlaunch, 450 seconds
  3. Burn 1/4burn 1 of 4, 240 seconds, one survey
  4. Coastcoast, 180 seconds
  5. Burn 2/4burn 2 of 4, 240 seconds, one survey
  6. Coastcoast, 180 seconds
  7. Burn 3/4burn 3 of 4, 240 seconds, one survey
  8. Coastcoast, 180 seconds
  9. Burn 4/4burn 4 of 4, 240 seconds, one survey
  10. Coastcoast, 180 seconds
  11. Approachapproach, 600 seconds

A lit dot marks an objective leg: one survey chance. Cruise, climb and burn legs all count.

VO2max 4x4 in eleven legs: 53 minutes, two launches, four burns, four coasts and an approach. Finish the workout and you arrive.

The mission clock

You arrive by finishing the workout. How hard you push changes what you find there, never whether you get there.

Surveys

Every cruise, climb and burn leg is one survey chance. Hold within 10% of the target for 85% of the leg, after a five-second settle once the leg starts, and the survey locks: a probe flies to the planet, and on arrival it lights a ring, a moon or a station. Going over target never counts.

Pursuits

Every burn is a chase. A raider warps in ahead of the fleet, and while you hold your target your ship fires at it and the lock builds. Finish the burn clean and the raider goes down; miss it and it jumps away. Nobody takes damage, and the lock only shows what the survey already measures.

Your star map

Each rider keeps a voyage: every system they have reached, with the surveys they locked, on a page of its own. The next destination is worked out in advance, so a planned workout already has a name.

Riding together

With two or more riders, everyone flies to the lead rider's destination and chases the same raider. Hold your zones together and a tether links the ships. When one rider's cadence drops away, another can cover: fifteen seconds at 10% over their own target, and a shield goes up around the struggling ship in the helper's color.

Two riders on a burn chasing a raider past a black hole with a glowing accretion disk; both rider cards read ON TARGET.
Two riders on the same burn, chasing one raider past a black hole.
The Voyage page: systems laid out along a winding path, each with its date, workout and survey marks.
The Voyage page: every system a rider has reached, with the surveys they locked.
Arrival at the destination: the ship in orbit beside a ringed planet, lit from behind by a blue supergiant.
Arrival. Each survey you locked lights one feature of the new system; the ones you missed stay as faint outlines.

Hardware

The server runs on the computer next to the bike and talks to the trainer over Bluetooth. There is no account and nothing to sign up for.

Trainer
Tested with the Wahoo KICKR CORE over Bluetooth FTMS ERG control. Other FTMS trainers may work, but they are untested.
Heart rate
Any Bluetooth strap that uses the standard Heart Rate Service.
Computer
macOS and Node 24. The Bluetooth stack is a native addon, so the server runs on Node and not on Bun.
Your data
Rides and profiles live in a folder you choose: ~/.opencycle by default, or OPENCYCLE_DATA_DIR.

Run it

You do not need a trainer to try it. The simulator adds fake trainers and heart rate straps, so a session is one command away.

Shell
git clone https://github.com/rlfleming93/openCycle.git
cd openCycle
pnpm install
OPENCYCLE_SIM=2x2 OPENCYCLE_DATA_DIR=/tmp/opencycle-demo pnpm dev

Open http://localhost:5173, create a profile, then start a session from the session builder. 2x2 means two simulated trainers and two simulated straps, and OPENCYCLE_DATA_DIR keeps the demo database and FIT files out of your real data folder. Requires Node 24 and pnpm 10.26 or later.

With a real trainer, set OPENCYCLE_BLE=1. On macOS, Bluetooth is denied to SSH and headless processes, so the README wraps the server in a small app bundle that gives it a stable identity once you approve it.

A recorded simulator session, 40 seconds: the jump into a new system, a burn pursuit ending with the raider down, two riders chasing past a black hole, and arrival.

There is no login.

Anyone who can reach the server can start sessions, change profiles and read ride data. Run it on a home network you trust, and never expose it to the internet.

The server listens on all interfaces so a TV or tablet on your network can show the ride. OPENCYCLE_HOST=127.0.0.1 keeps it on this machine only.