CV-powered soccer juggling coach β upload, analyze, improve.
Built for Hacklytics 2026. Users upload a short juggling video; the system detects the ball, tracks pose, identifies touches, and returns metrics plus coaching tips. The frontend shows results with charts and exports session JSON for Figma Make dashboards.
- Upload video (MP4, MOV, AVI, MKV, WebM) and run analysis
- Ball + pose pipeline: YOLO detection, Kalman smoothing, MediaPipe legs/feet
- Touch detection: left/right foot, rhythm intervals, peak height, lateral drift
- Knee stiffness proxy and coaching tips from the API
- Dashboard: skill score, L/R foot donut, rhythm graph, score breakdown, touch timeline
- Download session JSON for Figma Make or other tools
- Anime.js entrance animations and subtle UI graphics
Watch the system in action:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β USER β
β (Mobile / Web Browser) β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
β 1. Upload Video
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FRONTEND β
β β
β React / Flutter / Vue β
β β
β Pages: β
β βββ Upload Page β send video to API β
β βββ Loading Page β show progress spinner β
β βββ Dashboard Page β show all charts + results β
β βββ Replay Page β show annotated video β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
β 2. POST /analyze (video file)
β 3. GET /download/{job_id} (video)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FASTAPI SERVER β
β (main.py on Kaggle GPU) β
β β
β Exposed via ngrok β
β https://xxxx.ngrok-free.app β
β β
β Endpoints: β
β βββ GET /health β
β βββ POST /analyze β runs VideoProcessor β
β βββ GET /download/{id}β returns annotated video β
β βββ DELETE /cleanup/{id} β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββ
β
β 4. process_video()
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β VIDEO PROCESSOR β
β (video_processor.py) β
β β
β Frame by Frame Pipeline: β
β β
β βββββββββββ βββββββββββ βββββββββββββββββββ β
β β YOLO βββββΆβ Kalman βββββΆβ Ball History β β
β β detect β β filter β β + Trail β β
β βββββββββββ βββββββββββ ββββββββββ¬βββββββββ β
β β β
β βββββββββββββββββββ β β
β β MediaPipe βββββΆ Pose Landmarks β β
β β Pose Estimator β β β
β βββββββββββββββββββ β β
β βΌ β
β βββββββββββββββββββββ β
β β Touch Detection β β
β β F1: Foot Label β β
β β F2: Proximity β β
β β F3: Peak+Drift β β
β β F4: Knee Angle β β
β βββββββββββ¬ββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββ β
β β get_results() β β
β β returns JSON β β
β βββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β 5. Returns JSON + annotated video
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FRONTEND DASHBOARD β
β β
β JSON data mapped to: β
β βββ Skill Score Ring β skill_score β
β βββ L vs R Donut Chart β left_pct / right_pct β
β βββ Rhythm Line Graph β intervals[] β
β βββ Foot Timeline β touches[].foot + t β
β βββ Height Heatmap β touches[].x/y + peak β
β βββ Drift Channel β avg_drift_px β
β βββ Knee Feedback Card β knee_feedback{} β
β βββ Coaching Tips List β coaching_tips[] β
β βββ Annotated Video β /download/{job_id} β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- User picks a video on phone or browser.
- Frontend sends
POST /analyzewith the video file. - FastAPI receives it and saves to
/kaggle/working/videos/. - video_processor.py runs frame by frame:
- YOLO detects the ball every frame
- Kalman filter smooths and fills gaps
- MediaPipe detects leg skeleton
- Touch detection runs on detected frames
- Overlays are drawn on each frame
- get_results() builds the final JSON.
- FastAPI returns the JSON to the frontend.
- Frontend renders the dashboard from the JSON.
- User can click βWatch Replayβ (or open annotated video link).
- Frontend calls
GET /download/{job_id}. - Annotated video streams back to the browser.
| Layer | What | Why |
|---|---|---|
| CV Engine | YOLO + MediaPipe + Kalman | Ball + pose detection |
| GPU Server | Kaggle T4 | Free GPU |
| API Layer | FastAPI | Fast, async, auto docs |
| Tunnel | ngrok | Expose Kaggle publicly |
| Frontend | React + Vite | SPA, fast dev experience |
| Charts | Recharts | Rhythm, foot donut, radar |
| Animation | Anime.js | Entrance and UI motion |
| Video | HTML5 <video> |
Replay annotated video |
- [ Choose Video ] button (or βChoose video fileβ label)
- On select β
POST /analyze - Loading spinner while the API processes
| Block | Data source |
|---|---|
| Skill: 55.4 | skill_score |
| L:80% R:20% | left_pct / right_pct |
| Rhythm Graph | intervals[] |
| Foot Timeline | touches[].foot + t |
| Height / Drift | touches[].x/y, avg_drift_px |
| Knee: 175Β° Stiff | knee_feedback |
| Coaching Tips | coaching_tips[] |
| Watch Replay | GET /download/{job_id} |
Layout sketch:
ββββββββββββββββ¬βββββββββββββββ
β Skill: 55.4 β L:80% R:20% β
ββββββββββββββββ΄βββββββββββββββ€
β Rhythm Graph β
βββββββββββββββββββββββββββββββ€
β Foot Timeline LβRβLβLβL β
ββββββββββββββββ¬βββββββββββββββ€
β Height Map β Drift: 26px β
ββββββββββββββββ΄βββββββββββββββ€
β Knee: 175Β° Very Stiff β
βββββββββββββββββββββββββββββββ€
β Tips: β Chain more touches β
βββββββββββββββββββββββββββββββ€
β [ βΆ Watch Replay ] β
βββββββββββββββββββββββββββββββ
| Layer | Technologies |
|---|---|
| Backend | Python 3.10+, FastAPI, OpenCV, Ultralytics YOLO, MediaPipe, NumPy |
| Frontend | React 19, Vite 7, Recharts, Anime.js |
| Hosting | Kaggle (backend), ngrok (public URL), static frontend (e.g. Vercel/Netlify) |
- Run the FastAPI app (
cv/main.py) in a Kaggle notebook or environment wherevideo_processor.pyand models (YOLO, MediaPipe pose landmarker) are available. - Expose the server with ngrok and set the frontend API base URL to that ngrok URL.
cd frontend
npm install
npm run dev- Set
VITE_API_BASEin.envif your API is not at the default ngrok URL. - Production build:
npm run buildβ deploy thedist/folder.
- Configure in
frontend/src/config.jsor viaVITE_API_BASE(e.g.https://your-ngrok-subdomain.ngrok-free.dev).
JuggleIQ/
βββ cv/
β βββ main.py # FastAPI app: /health, /analyze, /download, /cleanup
β βββ video_processor.py # YOLO, MediaPipe, Kalman, touch detection, get_results()
βββ frontend/
β βββ src/
β β βββ App.jsx # Upload, results, charts, Figma Make block
β β βββ config.js # API_BASE
β β βββ App.css
β βββ public/samples/ # Sample drill videos
βββ drills/ # Source drill videos
βββ docs/
β βββ PRD.md
β βββ tech_stack.md
β βββ DEVPOST_OVERVIEW.md
βββ requirements.txt # Python backend deps
βββ README.md # This file
| Method | Path | Description |
|---|---|---|
| GET | /health |
Health check |
| POST | /analyze |
Upload video β analysis JSON |
| GET | /download/{id} |
Annotated video (inline) |
| DELETE | /cleanup/{id} |
Remove annotated video file |
Session JSON from Download session JSON is under 5MB and can be imported as a Figma Make dataset. Use it to build animated dashboards (skill gauge, foot donut, touch timeline, knee badge, coaching tips). See docs/DEVPOST_OVERVIEW.md for animation ideas and workflow.
- JuggleIQ β Hacklytics 2026
- CV: YOLO (Ultralytics), MediaPipe
- Frontend: React, Vite, Recharts, Anime.js
Gabriel Dos Santos β MediaPipe integration Gavin Calleja β FigmaMake Dashboard Analytics
