Skip to content

chrisjwalk/zwift-log-parser

Repository files navigation

Zwift Log Parser

A TypeScript command-line tool for parsing and analyzing Zwift activity log files. Built with Bun and React Ink.

Features

  • 📊 FPS Analysis — Visualize frame rate performance with ASCII graphs and statistics
  • 🗺️ Route Tracking — Identify routes/activities with duration, distance, and elevation data
  • 🌍 World Sessions — Track world changes and activity segments
  • 💻 System Information — Extract GPU, CPU, RAM, resolution, and graphics settings
  • 🎮 Session Metadata — View game version, launcher version, device info, and timestamps
  • 📤 JSON Export — Output data as JSON for further processing
  • 🔧 Flexible Options — Enable/disable specific analysis sections as needed
  • 📁 Interactive File Picker — Browse and select log files if no path is provided

Installation

From npm

npm install -g zwift-log-parser
zwift-log-parser /path/to/your/Log.txt

Local Development

git clone https://github.com/chrisjwalk/zwift-log-parser.git
cd zwift-log-parser
bun install
bun run build
npm link          # makes the zwift-log-parser command available globally
zwift-log-parser /path/to/your/Log.txt

Usage

Basic Usage

zwift-log-parser /path/to/Log.txt

If no file path is provided, an interactive file picker will launch:

zwift-log-parser

Command-Line Options

zwift-log-parser [logfile] [options]

Arguments:
  logfile            Path to Zwift log file to parse

Options:
  -V, --version      Output the version number
  --no-fps           Skip FPS analysis and graphs
  --no-routes        Skip route/activity information
  --no-metadata      Skip session and system metadata
  --json             Output results as JSON instead of formatted display
  -h, --help         Display help information

Examples

# Analyze everything (default)
zwift-log-parser ~/Documents/Zwift/Logs/Log.txt

# Routes and metadata only, no FPS graph
zwift-log-parser ~/Documents/Zwift/Logs/Log.txt --no-fps

# Export to JSON for further processing
zwift-log-parser ~/Documents/Zwift/Logs/Log.txt --json > output.json

# FPS analysis only
zwift-log-parser ~/Documents/Zwift/Logs/Log.txt --no-routes --no-metadata

Sample Output

🚴 Zwift Log Parser v0.0.1

Session Information
  Log Date/Time:  21:09:07 2026-01-08
  Game Version:   1.104.4(157262) rc/1.104.4
  Device:         PC

System Information
  GPU:            NVIDIA GeForce RTX 5060/PCIe/SSE2
  Driver:         4.6.0 NVIDIA 591.74
  CPU:            12th Gen Intel(R) Core(TM) i5-12600KF
  RAM:            64GB
  Resolution:     1920x1080
  Graphics:       ultra

Worlds
  Watopia
  • Triple Flat Loops
  • The Big Ring

FPS Analysis

  📍 Watopia

     126.00 ┤
     121.33 ┤  ╭───╮                     ╭──────╮
     116.67 ┼──╯   │        ╭╮           │      ╰╮
     ...

  Time: 1h 48m 52s | Average: 99.76 | Min: 61.73 | Max: 120.97

Development

Project Structure

This is a Bun workspace monorepo with two packages:

core/                       # Parser library (@zwift-log-parser/core)
├── src/
│   ├── index.ts            # Library entry point
│   └── lib/
│       ├── parser.ts       # ZwiftLogParser class
│       ├── file-picker.ts  # Interactive file picker
│       └── __fixtures__/   # Test data (real log files)
└── package.json

cli/                        # CLI application
├── src/
│   ├── main.tsx            # Entry point — argument parsing
│   ├── App.tsx             # Root React Ink component
│   └── components/         # Individual UI panel components
│       ├── Banner.tsx
│       ├── MetadataPanel.tsx
│       ├── WorldsPanel.tsx
│       ├── FpsPanel.tsx
│       └── Section.tsx
└── package.json

scripts/
└── build.ts                # Bun build script (bundles CLI via esbuild)

bin/
└── zwift-log-parser.js     # npm bin wrapper

Available Commands

bun install              # Install dependencies
bun run build            # Build CLI bundle to dist/
bun run dev              # Run CLI directly with Bun (no build needed)
bun start                # Run the built CLI from dist/
bun test                 # Run all tests
bun lint                 # Lint all source files with ESLint
bun run clean            # Remove build artifacts
bun run pack             # Create npm tarball in dist/

Development Workflow

# 1. Install dependencies
bun install

# 2. Run directly without building (fastest iteration)
bun run dev /path/to/Log.txt

# 3. Build for production
bun run build

# 4. Test the built bundle
bun start /path/to/Log.txt

# 5. Run tests
bun test

# 6. Lint
bun lint

Publishing to npm

# Bump version, build, and publish
npm version patch
bun run build
npm publish --access public

To test the package locally before publishing:

bun run pack
npm install -g dist/zwift-log-parser-<version>.tgz

Technology Stack

  • Runtime: Bun
  • Language: TypeScript 6.0
  • UI: React Ink 7 (terminal UI, React 19)
  • Bundler: esbuild (via Bun build API)
  • CLI Arg Parsing: Commander.js
  • FPS Graphs: asciichart
  • File Picker: @inquirer/prompts
  • Testing: Vitest
  • Linting: ESLint 10 + typescript-eslint

Architecture

Core Library (@zwift-log-parser/core)

Provides the ZwiftLogParser class and pickFile() utility:

  • parseMetadata(content) — session and system info
  • parseRouteSessions(content) — routes and world sessions with timing
  • parseFPSLines(content) — raw FPS sample array
  • parseFpsPerWorld(content) — FPS data grouped by world, with timestamps
  • calculateFpsStats(fps) — average, min, max statistics
  • downsampleData(data, width) — reduce data points for graph rendering

CLI Application

Built with React Ink — the terminal output is a rendered React component tree. Commander.js handles argument and option parsing before React renders.

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

License

MIT

About

Parse and visualize your Zwift ride logs — FPS graphs, route tracking, and system info in your terminal. Built with Bun + React Ink.

Topics

Resources

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors