Sprintlab
Free, open-source sprint kinematic analysis — upload a video, get research-level biomechanics metrics. Built to bridge the resource gap for athletes in under-resourced parts of the world.
Install / Use
/learn @mvch1ne/SprintlabREADME

SprintLab is a desktop application I made to help sprinters perform kinematic analysis on their training videos so they can gain insights and improve their performance. It's built with Electron and a React/TypeScript frontend, and coupled with a Python backend built with FastAPI and RTMLib for highly accurate, research-level pose estimation and tracking of body landmarks. The desktop app bundles everything into a single installer — no Python, no server setup, just download and run.
The app lets users upload videos, calibrate real-world distances and compute performance metrics like ground contact times, stride length, joint angles, linear and angular velocities, acceleration, and more — all from just a video.
This project is very personal to me. As an athlete and engineer from Ghana, West Africa, where biomechanics labs are pretty much non-existent, I looked around for a tool to help level the playing field and realized I had to build it myself. SprintLab is open to everyone worldwide, but my major motivation is to help bridge the resource gap in underdeveloped parts of the world, like Africa. I'm excited to see how it helps athletes everywhere.
FULL DOCUMENTATION WEBSITE→
DEMO VIDEO →
Table of Contents
- Download
- Features
- Architecture
- Tech Stack
- Project Structure
- Getting Started
- Building from Source
- How It Works
- Metrics Reference
- Testing
Download
A pre-built Windows installer is available on the Releases page.
| Platform | File | Notes |
| -------- | -------------------------------------------- | ----------------------------- |
| Windows | SprintLab Setup x.x.x.exe (NSIS installer) | Available on Releases page |
| macOS | SprintLab-x.x.x.dmg | Build from source (see below) |
| Linux | SprintLab-x.x.x.AppImage | Build from source (see below) |
Windows users: Right-click the installer and choose Run as administrator. Windows SmartScreen may also show a warning because the binary is not code-signed — click More info → Run anyway to proceed.
Note: On first launch, SprintLab downloads the ONNX pose-estimation model weights (~70 MB) and caches them locally. An internet connection is required for this one-time download.
Features
- AI Pose Estimation — 133-keypoint whole-body pose tracking via RTMLib (MMPose Wholebody3d), streamed from the backend as Server-Sent Events so you see real-time progress as each frame is processed
- Ground Contact Detection — Automatic detection of foot touchdown and liftoff events, with contact time, flight time, and step frequency computed per stride. Contacts are editable and can also be placed manually
- Joint Angle Tracking — Per-frame interior angles for hip, knee, ankle, shoulder, elbow, and wrist on both sides, plus segment inclinations for torso, thigh, and shin — all smoothed and differentiated to give angular velocity and acceleration
- Center of Mass Trajectory — Hip-midpoint displacement, horizontal speed, acceleration, and cumulative distance travelled, all in real-world metres once calibrated
- Calibration — Draw a reference line on the video, enter its real-world length, and every pixel measurement is converted to metres
- Distance and Angle Measurement — Freehand measurement overlay for any distance or angle visible in the frame
- Video Trim and Crop — Cut the video to the exact sprint window and crop to remove irrelevant parts, all in the browser via FFmpeg.js (no upload required)
- Sprint Timing — Static (block/standing start) and flying-start timing modes, with reaction time, zone entry/exit markers, and frame-accurate sprint start confirmation
- Telemetry Panel — Interactive sparklines for every metric with a playhead that tracks the current video frame, plus a tabbed layout across Steps, Lower body, Upper body, and CoM
Architecture
┌──────────────────────────────────────────────────────────────┐
│ Browser (React SPA) │
│ │
│ ┌──────────────────────────────────────┐ ┌─────────────┐ │
│ │ Viewport (orchestrator) │ │ VideoCtx │ │
│ │ ┌─────────────────────────────────┐ │ │ (shared │ │
│ │ │ useVideoPlayback · useZoomPan │ │ │ state) │ │
│ │ │ useCalibration · useMeasurements│ │ └──────┬──────┘ │
│ │ │ useSprintMarkers · useCoM │ │ │ │
│ │ │ useTrimCrop │ │ │ │
│ │ └─────────────────────────────────┘ │ │ │
│ └──────────────┬───────────────────────┘ │ │
│ │ │ │
│ ┌──────────────┴───────┐ │ │
│ │ Telemetry (shell) │─────────────────────────┘ │
│ │ ContactsTab · CoMTab│ │
│ │ JointRow · Sparkline│ │
│ └──────────────────────┘ │
│ │ │
│ useSprintMetrics (hook) │
│ sprintMath.ts (pure) │
│ │ │
│ POST /infer/video ←→ SSE stream │
└─────────────────┼────────────────────────────────────────────┘
│
┌─────────────────▼────────────────────────────────────────────┐
│ Backend (FastAPI) │
│ │
│ GET /health — readiness probe │
│ POST /infer/video — SSE: progress + keypoint data │
│ │
│ OpenCV → frame extraction │
│ RTMLib Wholebody3d → 133 keypoints × N frames │
│ ONNX Runtime → CPU inference │
└──────────────────────────────────────────────────────────────┘
The frontend never blocks waiting for inference to finish. The backend streams a progress SSE event after every frame (frame index, %, FPS, ETA) and a single result event at the end containing all frame data. The frontend stores keypoints in a Map<frameIdx, Keypoint[]> and computes all metrics in a single useMemo pass once the result arrives.
Video trimming, cropping, and export are handled entirely in the browser using FFmpeg.js (WASM) — no video data leaves the device for those operations.
Tech Stack
Desktop
| Concern | Library / Tool | | --------- | ---------------------------------------- | | Shell | Electron 36 | | Packaging | electron-builder (NSIS / DMG / AppImage) |
Frontend
| Concern | Library / Tool | | ---------------- | ----------------------------------------- | | Framework | React 19 + TypeScript 5.9 | | Build | Vite 7 | | Styling | TailwindCSS 4 + Figtree variable font | | UI Components | Radix UI + Shadcn/ui | | Icons | Lucide React · Tabler Icons · Huge Icons | | Video processing | FFmpeg.js (WASM) | | Testing | Vitest 3 · jsdom · @testing-library/react |
Backend
| Concern | Library / Tool | | ----------------- | -------------------------------------- | | Framework | FastAPI (async) | | Pose estimation | RTMLib — MMPose Wholebody3d (133 kpts) | | Video I/O | OpenCV | | Inference runtime | ONNX Runtime (CPU) | | Testing | pytest · pytest-asyncio · httpx |
Project Structure
sprintlab/
├── electron/
│ ├── main.js # Electron main process (window, backend spawn, static server, menu)
│ └── preload.js # Context bridge (fullscreen IPC, resource file reader)
│
├── frontend/
│ ├── src/
│ │ ├── hooks/ # Custom hooks extracted from Viewport
│ │ │ ├── useVideoPlayback.ts # Video loading, playback state, frame tracking
│ │ │ ├── useZoomPan.ts # Viewport zoom/pan transforms
│ │ │ ├── useCalibration.ts # 2-point scale reference calibration
│ │ │ ├── useMeasurements.ts # Distance & angle measurement tools
│ │ │ ├── useSprintMarkers.ts # Sprint markers, manual contacts, merged contacts
│ │ │ ├── useCoM.ts # Centre of Mass display & events
│ │ │ └── useTrimCrop.ts # Trim & crop panel state
│ │ ├── components/
│ │ │ ├── dashboard/
│ │ │ │ ├── viewport/
│ │ │ │ │ ├── PoseEngine/ # Pose detection + skeleton overlay
│ │ │ │ │ ├── CalibrationAndMeasurements/ # Calibration + measurement tools
│ │ │ │ │ ├── TrimAndCrop/ # FFmpeg.js trim/crop UI
│ │ │ │ │ ├── StatusBar/ # Inference progress indicator
│ │ │ │ │ ├── videoUtilities/ # Export + frame helpers
│ │ │ │ │ ├── controls/
