AI-powered boxing analytics platform — real-time fighter tracking, live scoring overlays, and fight metrics visualization.
Upload a boxing video → Ring Dynamics runs YOLOv8 fighter detection with hardened 2-fighter tracking, draws shivering 3-box overlays (full body, head, core), computes real-time fight metrics, and renders a premium scoring HUD — all viewable in a split-layout web dashboard with live stats synced to video playback.
| Feature | Description |
|---|---|
| 3-Box Fighter Tracking | Full body + head + core sub-boxes with ±2px jitter shimmer for a "live tracking" feel |
| Anti-Audience Filtering | Spatial reasoning + size constraints ensure only the two fighters are tracked |
| Identity Lock | Appearance-based + spatial matching keeps Fighter A / Fighter B consistent across camera cuts |
| Live Scoring Overlay | Activity, Aggression, Ring Control, Pressure — rendered as side panels + top/bottom bars on the video |
| 10-9 Round Scoring | Weighted composite metrics produce estimated round scores |
| Event Feed | Auto-generated fight events ("Fighter B presses forward", "Fighter A controls center") |
| Metrics JSON Export | Per-second timeline data saved alongside annotated videos |
| Split-Layout Dashboard | Video player (70%) + live stats panel (30%) with red/black premium theme |
┌────────────────────┐ ┌───────────────────┐ ┌──────────────────┐
│ Next.js 14 UI │◄──────►│ FastAPI Backend │───────►│ CV Pipeline │
│ (React/TS) │ REST │ (Orchestrator) │ Thread │ (annotate_video)│
│ │ │ │ │ │
│ • Split layout │ │ • Video upload │ │ • YOLOv8 │
│ • Live stats │ │ • Status polling │ │ • ByteTrack │
│ • Event feed │ │ • Metrics API │ │ • FightScorer │
│ • Scorecard │ │ • Video serving │ │ • 3-box drawing │
└────────────────────┘ └───────────────────┘ └──────────────────┘
- Python 3.10+ with
pip - Node.js 18+ with
npm - (Optional) Apple MPS or NVIDIA GPU for faster inference
git clone https://github.com/Zhandolia/ring-dynamics.git
cd ring-dynamics
# Backend dependencies
cd backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Frontend dependencies
cd ../frontend
npm installcd backend
source venv/bin/activate
uvicorn app.main:app --reload --port 8000The API will be available at http://localhost:8000. Visit /docs for the interactive Swagger UI.
cd frontend
npm run devOpen http://localhost:3000 in your browser.
- Click "Upload Video" on the home page
- Select any boxing video (MP4, AVI, MOV — up to 500MB)
- Watch the processing status animate
- Once complete, the split-layout results page appears:
- Left (~70%) — Annotated video with scoring HUD overlay
- Right (~30%) — Live stats panel synced to video playback
You can also run the annotation pipeline directly without the web UI:
# Basic usage
python3 annotate_video.py input.mp4 output.mp4
# With GPU acceleration and custom settings
python3 annotate_video.py fight.mp4 annotated.mp4 \
--device mps \
--scale 0.5 \
--conf 0.30 \
--imgsz 640 \
--fps 30CLI Arguments:
| Argument | Default | Description |
|---|---|---|
input |
— | Path to input video (required) |
output |
auto | Output path (defaults to {input}_annotated.mp4) |
--model |
yolov8n.pt |
YOLOv8 model variant (n, s, m, l, x) |
--device |
cpu |
Inference device (cpu, mps, cuda) |
--scale |
1.0 |
Frame resize scale (0.5 = half size, faster) |
--conf |
0.35 |
Detection confidence threshold |
--imgsz |
1280 |
YOLO input resolution |
--fps |
0 |
Target output FPS (0 = match source) |
--max-frames |
0 |
Limit frames to process (0 = all) |
The CLI also generates a _metrics.json file alongside the output video.
curl -X POST \
-F "file=@fight.mp4;type=video/mp4" \
http://localhost:8000/api/fights/uploadResponse:
{
"id": "8f6b9f0e-...",
"status": "pending",
"metrics_url": null
}curl http://localhost:8000/api/fights/{fight_id}Status transitions: pending → annotating → completed (or failed)
curl http://localhost:8000/api/fights/{fight_id}/video -o annotated.mp4curl http://localhost:8000/api/fights/{fight_id}/metricsReturns per-second timeline data:
{
"duration": 180.0,
"final_scores": [10, 9],
"final_activity": [1.52, 1.81],
"final_aggression": [0.99, 0.43],
"events": [
{"frame": 30, "text": "Fighter B presses forward"},
{"frame": 150, "text": "Fighter A controls center"}
],
"timeline": [
{"time": 1.0, "activity": [35.2, 71.5], "distance": "Outside", ...}
]
}ring-dynamics/
├── annotate_video.py # Main CV pipeline (standalone CLI)
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI application
│ │ ├── api/
│ │ │ └── fights.py # REST endpoints (upload, status, video, metrics)
│ │ ├── core/
│ │ │ └── config.py # Settings & environment config
│ │ ├── models/
│ │ │ └── schemas.py # Pydantic data models
│ │ └── services/
│ │ └── annotation_service.py # Background annotation runner
│ ├── workers/
│ │ └── annotate_video.py # Backend copy of CV pipeline
│ └── requirements.txt
├── frontend/
│ ├── src/app/
│ │ ├── page.tsx # Home page (upload UI)
│ │ ├── fight/[id]/page.tsx # Fight results (split layout)
│ │ ├── globals.css # Red/black theme
│ │ └── layout.tsx # Root layout
│ ├── package.json
│ └── tsconfig.json
└── README.md
- YOLOv8 detects all people in each frame with bounding boxes
- ByteTrack assigns persistent track IDs across frames
- Anti-audience filter selects the two largest, most central detections
- Identity tracker uses spatial proximity + appearance histograms to maintain consistent Fighter A / Fighter B assignment even through camera cuts
Each fighter gets three overlapping boxes drawn with ±2px jitter per frame:
- Full body (outer box) — fighter-colored (red/blue)
- Head zone (top 0-28%) — green accent
- Core zone (28-62%) — fighter-colored
The jitter creates a "shivering" effect that makes the tracking feel alive and millisecond-precise.
The video canvas is expanded to include:
- Top bar — Fighter names, round scores (10-9 system), round number, timer
- Side panels — Per-fighter Activity, Aggression, Ring Control, Pressure bars
- Bottom bar — Distance gauge (Inside/Mid-Range/Outside) + latest event
| Metric | How It's Calculated |
|---|---|
| Activity | Fighter bbox center movement speed (EMA smoothed) |
| Aggression | Forward movement toward the opponent |
| Ring Control | Proximity to ring center (closer = higher) |
| Pressure | Sustained forward movement over time |
| Distance | Gap between fighter bboxes (Inside/Mid/Outside) |
| Round Score | Weighted composite: 40% activity + 35% aggression + 25% ring control |
Environment variables (optional — sane defaults used):
| Variable | Default | Description |
|---|---|---|
DEVICE |
mps |
Inference device (cpu, mps, cuda) |
YOLO_MODEL |
yolov8n.pt |
YOLO model name |
ANNOTATION_SCALE |
0.5 |
Frame resize factor |
ANNOTATION_CONF |
0.30 |
Detection confidence |
ANNOTATION_IMGSZ |
640 |
YOLO input size |
MAX_VIDEO_SIZE_MB |
500 |
Max upload file size |
FRAMES_PER_SECOND |
30 |
Target output FPS |
NEXT_PUBLIC_API_URL |
http://localhost:8000 |
Backend URL for frontend |
- Fine-tune YOLOv8 on boxing-specific dataset (fighters, gloves, referee)
- Train punch detection model (jab, cross, hook, uppercut)
- Implement automatic round detection from video
- Add fighter identification (name/corner assignment)
- WebSocket real-time updates during processing
- Docker Compose for one-command deployment
- PDF/CSV fight report export
- Multi-camera angle support
- Backend: FastAPI, Uvicorn, Pydantic
- Frontend: Next.js 14, React, TypeScript, Tailwind CSS
- CV Pipeline: YOLOv8 (Ultralytics), OpenCV, NumPy
- Tracking: ByteTrack (built-in YOLOv8), custom identity tracker
- Scoring: Custom
FightScorerwith EMA-smoothed metrics
MIT License — see LICENSE for details.
- Ultralytics YOLOv8 — object detection
- FastAPI — backend framework
- Next.js — frontend framework