Skip to content

guanxiaol/garmin-analyzer


✨ What is Garmin Analyzer?

Garmin Analyzer is a 100% client-side, open-source tool that turns the raw .fit / .tcx / .gpx files your Garmin (or Wahoo, Coros, Bryton, Suunto, Polar, …) device exports into beautiful, shareable posters and short animated videos — the kind you actually want to put on Instagram Stories, your WeChat Moments, or Strava.

Garmin Connect's charts are functional. Strava's stats stickers are basic. Relive is great but paywalled. Garmin Analyzer is the love child that's free, open source, and never uploads your data anywhere.

Feature overview: parsers, metrics, posters, motion

🎨 Four poster themes, two aspect ratios

Pick the look that matches the ride. Each theme renders at native print resolution and exports as PNG / JPG / WebM-MP4.

Four poster themes: Dark Race, Light Mono, Retro Map, Neon Cyber
Theme Vibe Best for
Dark Race Neon-on-black, racing telemetry Crit / interval session / KOM attempt
Light Mono Editorial, oversized type, b&w "Sunday long ride", clean aesthetic
Retro Map Vintage paper, hand-drawn route Bikepacking, exploration, gravel
Neon Cyber Magenta/cyan gradient, scanlines Indoor trainer PRs, late-night Zwift

Each theme exports at:

  • 1080×1920 — Instagram Stories, WeChat Moments, RED (Xiaohongshu)
  • 1080×1080 — Instagram feed, Twitter/X

Plus an 8-second animated WebM/MP4 with route-draw, count-up numbers, and elevation reveal.

🚀 Quick Start

Use it now (no install)

https://guanxiaol.github.io/garmin-analyzer/

Drag your .fit / .tcx / .gpx onto the page. Done. Your file never leaves your browser.

Run locally

git clone https://github.com/guanxiaol/garmin-analyzer.git
cd garmin-analyzer
pnpm install
pnpm dev           # → http://localhost:5173
pnpm typecheck     # strict TypeScript
pnpm build         # production bundle in dist/
pnpm preview       # preview the production build

Requires Node 18+ and pnpm 9+ (npm/yarn also work).

🧮 What it actually computes

Not just pretty charts — Garmin Analyzer ships proper sports-science math used by coaches:

Metric Formula / Source Notes
NP (Normalized Power) Coggan 30-s rolling, 4th-power average Industry standard
IF (Intensity Factor) NP / FTP Set FTP in Settings
TSS (Training Stress Score) ((duration × NP × IF) / (FTP × 3600)) × 100 Coggan
Power zones (1–7) % of FTP — Coggan tiers Configurable
HR zones (1–5) % of LTHR Configurable
Mean-Maximal Power Curve Per-second resampled sliding window 1s / 5s / 30s / 1min / 5min / 20min / 60min
Work (kJ) Σ power × dt / 1000
Auto climb detection Sustained grade ≥ 3 %, length ≥ 300 m, merged gaps ≤ 120 m Categorized HC / Cat 1-4 by score
Hard-effort intervals 30-s smoothed power ≥ 0.9 × FTP, contiguous ≥ 60 s

All formulas live in src/lib/metrics/ — read the source, file an issue if a number disagrees with your reference tool.

🛠 Tech Stack

Frontend     React 18 · TypeScript (strict) · Vite 5 · TailwindCSS 3
State        Zustand 5 (persist middleware for settings)
Charts       Apache ECharts 5 (time-series, power curve, zone bars)
Route map    Pure SVG with metric-based colouring (zero external dependencies)
Parsers      fit-file-parser 3.x · native DOMParser (TCX / GPX)
Image export html-to-image (DOM → PNG/JPG, no canvas re-render)
Video export Canvas 2D + MediaRecorder (browser-native, no FFmpeg)
Hosting      GitHub Pages via GitHub Actions

Why this stack?

  • 100% in-browser. No server, no backend, no upload. Your Garmin data is yours.
  • Tiny deploy. Static files (~470 KB gzipped). Hosting cost: $0/month forever.
  • No vendor lock-in. Everything is MIT.

🏗 Architecture

flowchart LR
  A[".fit / .tcx / .gpx"] --> B[parsers]
  B -- "unified Activity{}" --> C[metrics]
  B --> D[SVG route view]
  C --> E[poster templates]
  C --> F[charts]
  E --> G["html-to-image → PNG/JPG"]
  E --> H["Canvas 2D + MediaRecorder → WebM/MP4"]
  G --> I["📲 IG / WeChat / X / RED"]
  H --> I

  style A fill:#0c0f14,stroke:#c7ff3a,color:#c7ff3a
  style I fill:#0c0f14,stroke:#ff3ec9,color:#ff3ec9
Loading

Reading order of the source:

  1. src/types.ts — the Activity type model
  2. src/lib/parsers/ — file → Activity
  3. src/lib/metrics/Activity + settings → derived numbers
  4. src/components/posters/Activity → JSX poster
  5. src/lib/export/ — DOM/Canvas → PNG/MP4

📥 Where do I get my Garmin data?

The app has a built-in export guide (click "How to export?" on the home page). Short version:

  1. Easiest — Open https://connect.garmin.com, find the activity, gear ⚙ menu → "Export Original (.fit)". Drag the file back into Garmin Analyzer.
  2. USB direct — Plug your device into your computer, look inside Garmin/Activities/ for the .fit files. (Note: Edge 840/1040 use MTP protocol and need OpenMTP on macOS.)
  3. Bulk historical export — Account Privacy → "Request your data". Garmin emails you a zip of your entire history in 1–3 days.

🗺 Roadmap

v0.2 (next)

  • Multi-file batch import (compare 2–4 rides side-by-side)
  • Static OSM tile backdrop on posters (currently SVG-only)
  • Running-specific template (split pace, cadence overlay)
  • Strava one-click upload of generated posters
  • Auto-detect best 5-min / 20-min effort and call it out on the poster

v0.3

  • PWA — install as a native app, work offline
  • Custom poster editor (drag elements, change colours, custom fonts)
  • Importing from Apple Health / Strava direct API
  • More languages (FR / DE / JA / ES)
  • Team posters — race day group rides

v1.0

  • Yearly review animation (Spotify Wrapped style for cyclists)
  • Power-meter accuracy regression suite — compare against TrainerRoad / WKO5
  • Optional self-hosted backend for users who want long-term storage

Open an issue to suggest a feature or vote with 👍 on existing ones.

🤝 Contributing

Designers, cyclists, data nerds, frontend engineers — all welcome.

See CONTRIBUTING.md for the full guide.

❓ FAQ

Q: Does Garmin Analyzer upload my files anywhere? No. Files are parsed in your browser. No server. Open DevTools → Network and watch.

Q: My Garmin Edge 840/1040 doesn't show up on macOS over USB. Edge 840/1040 use MTP protocol — macOS doesn't support it natively. Install OpenMTP (free), or just export via the Garmin Connect website.

Q: Why isn't my power data showing? Garmin Analyzer reads the standard power field in FIT/TCX. If your bike computer recorded power but you don't see numbers, file an issue with a sample file — most likely a vendor-specific extension we haven't seen yet.

Q: Can I host this myself? Yes — pnpm build outputs static files. Deploy to any static host (Vercel, Cloudflare Pages, Netlify, your own nginx).

Q: Is there a mobile app? Not yet, but the Web app is responsive and works in Safari/Chrome on iOS/Android. PWA support is on the roadmap.

Q: Will you add running / hiking / swimming support? The parser handles them already. UI/templates optimised for those sports are on the roadmap.

💖 Acknowledgments

Standing on the shoulders of giants:

📄 License

MIT © 2026 Garmin Analyzer contributors.

Means you can use it commercially, modify it, distribute it, host it for your team — all free. We'd love a star ⭐ if it helped you.


Built with 🧡 for cyclists who care about how their data looks.

⭐ Star on GitHub · Report a bug · Discussions

About

佳明数据分析器 · Garmin/Wahoo/Coros .fit/.tcx/.gpx 解析与可视化 · 一键生成运动海报和动态视频 · NP/IF/TSS/CP/VAM 教练级指标 · 100% 浏览器本地 · Open-source Garmin / cycling data analyzer · ride poster generator · Relive & Strava alternative

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors