00 · Introduction
What problem does this solve?
A coach shooting match footage wants to find every forehand, backhand, and serve in a 10-minute video, extract them as clips, and annotate what the player did right (or wrong) at the moment of contact. Doing this by hand takes hours. Doing it by hand again every time you tweak parameters takes even longer.
Swing-Analysis automates the finding and clipping step. You give it a video and (optionally) some tuning knobs; it gives you back a list of swing cycles with phase boundaries (ready / windup / contact / follow_through) and pre-cut clip MP4s.
What it deliberately does NOT do
- No shot-quality scoring. This is segmentation, not analysis. Whether the forehand was technically correct is a separate, downstream problem (see
backend/core/analyze_swing.py— it draws the 33-point skeleton and clips but does not score shots). - No cloud service. Everything runs locally on your machine. The FastAPI service binds to
127.0.0.1by default. Opening it up to a LAN isPhase Cwork. - No automatic model updates. The MediaPipe Pose model is pinned (
pose_landmarker_lite.task, 5.5 MB) and committed to the repo. Upgrade deliberately.
Who is it for?
- Coaches / players who already have a video workflow and want to skip the manual clipping tedium.
- Engineers integrating the algorithm into a bigger system (e.g. an analysis dashboard) — they use the REST API and don't touch Electron.
- Researchers experimenting with the algorithm's parameters — they use the CLI to iterate quickly.
Why the layered design?
Two principles:
The algorithm library is sacred. All three scripts in
backend/core/are vendored byte-for-byte —segment_swing.py,analyze_swing.py,gen_skeleton_anim.py. Any change must come from the underlying source first, then be re-copied. This guarantees that any "fix" you make here is reproducible from a singlecp.UIs are replaceable. A CLI is a UI. A desktop app is a UI. A browser tab is a UI. They all want to do the same thing — submit a job, watch progress, retrieve results. The right shape is one algorithm function (
run_pipeline()) callable from any of them.
This shape is what makes the GUI just a thin shell on top of the CLI. No algorithm code in the renderer. No "I have to maintain two implementations" debt.
Brand
Swing-Analysis is one app under the AceCrush brand series — a parent line for sports-AI tools. Concrete shapes:
- The Electron window title and
<title>showSwing-Analysis— that's the app you're in. - The macOS top-bar app menu and the Dock icon carry
AceCrush— that's the brand. - Installers (NSIS / DMG / AppImage / deb) and the macOS
.appare namedAceCrush Swing-Analysisso users see the brand + app together. - Internal identifiers (
package.jsonname, GitHub repo name, GitHub Pages URL, git-clone path) stay lowercase as stable IDs — see 05 · Electron GUI for the full split.
When NOT to use this
- You need real-time pose tracking (this is offline batch — Pass 1 + 1.5 takes ~1s per frame on M-series Mac).
- You want a polished standalone skeleton animation video with smart-zoom cropping (no swing detection, just the overlay). Run
backend/.venv/bin/python3 backend/core/gen_skeleton_anim.py --helpdirectly — it's the same algorithm, but packaged for animation-only use. - You want a hosted web app. This is local-first by design; Phase C sketches a self-hosted option but it's not built.
What does "swing" mean here?
A complete cycle is ready → windup → contact → follow_through. The algorithm uses the player's right wrist position (MediaPipe landmark 16) over time as its primary signal: starts when wrist speed exceeds a threshold, ends when it stops. Adjacent active intervals within 1.5s (inferred rest) or 1.5s (inferred lost-detection) merge into one cycle; otherwise they split.
See 06 · Algorithm for the full pipeline.