Engineering log

Developer Updates

The technical story behind SwingIQ — the architecture, the AI work, and the motion intelligence that make a free, browser-based swing platform actually work.

Looking for the plain-English version? See product updates.

By the numbers

5
Sports, real engines

Golf, tennis, baseball, slow- and fast-pitch softball — each with its own diagnostic rules, not shared labels.

3D
Motion analysis in the browser

Depth-aware pose estimation runs client-side. No app install, no upload of your video to a server.

7
Themes, one token engine

A data-theme palette system retokenizes the entire app — coaching logic and data never change.

0
Required accounts

Local-first by design. You can analyze a swing in seconds with your data kept on your own device.

Engineering milestones

The foundations the rest of the product is built on — oldest to newest.

  1. Five sports, five real diagnostic engines

    Treated each sport as a distinct movement model instead of golf with relabeled tips.

  2. Real AI vision — frames in, coaching out

    The video analyzer now sends real frames to a vision model instead of faking analysis.

  3. Unified lib/pose — one source of truth for movement

    Collapsed scattered pose/motion code into a single shared library every sport draws from.

  4. Fault ontology + retest engine — closing the improvement loop

    A structured fault taxonomy plus an engine that proves whether a fix actually held.

  5. Keyless instant start — local-first by default

    Removed the sign-up wall: full value with data kept on the device, accounts optional forever.

  6. Depth-aware 3D biomechanics — rotation that finally reads the z-axis

    Browser-native 3D swing analysis across all five sports, with no video ever leaving the device.

  7. Implement path, kinetic chain, and temporal intelligence

    The motion engine now reads the implement path, the firing order of the kinetic chain, and how the swing unfolds over time.

All developer updates

Newest first. The technical story behind the changelog.

PlatformFoundationalStrategy

Monetization re-sequenced: free → ads → membership tiers

One canonical monetization order across the whole codebase: grow the free base, monetize via ads for first revenue, then roll out paid tiers.

The project was implicitly subscription-first (the checklist, roadmap, and live Pro/Team tiers all treated paid plans as the next step). We made the order explicit and fixed: Phase 1 grow free users → Phase 2 ads (first revenue from the free audience) → Phase 3 membership tiers, each advancing only when the gate ahead is met. A new north-star doc (docs/MONETIZATION_STRATEGY.md) governs the subordinate docs. In code, ads get a keyless-first capability seam (isAdsConfigured + the /api/capabilities summary) that renders zero ads until an ad-network id is set — mirroring how Stripe stays dormant until keys exist — and the pricing CTA now reads "Coming Soon" (with an optional email notify) instead of a waitlist, since subscriptions are Phase 3.

  • docs/MONETIZATION_STRATEGY.md as the single source of truth (3 phases + the gate between each)
  • Ads wired keyless-first/off by default; non-personalized/contextual for youth-safety
  • Stripe/Pro/Team rails kept pre-built but explicitly deferred to Phase 3
  • Pricing page tiers now show "Coming Soon"
TypeScriptNext.jsCapability seamDocs-as-code
Motion IntelligenceMajorMotion Lab

Implement path, kinetic chain, and temporal intelligence

The motion engine now reads the implement path, the firing order of the kinetic chain, and how the swing unfolds over time.

Three new analysis layers sit on top of the existing pose pipeline. Object tracking estimates the club/bat/racket head path by extrapolating along the grip forearm — no pixel detector, so it is honestly labeled ai_inferred with capped confidence and a provider seam for a future ML detector. The kinetic-chain engine times when each link (lower body → torso → arms → implement) peaks and flags power leaks. Temporal intelligence anchors load/transition/acceleration durations to the detected top-of-backswing and strike, and scores contact-window stability and deceleration. Every output is an optional, backward-compatible field on the session, basis + confidence carried through.

  • Markerless implement path + contact zone (forearm extrapolation, provider seam)
  • Kinetic sequencing with power-leak detection, depth-aware
  • Phase durations, contact-window stability, and cross-session repeatability
  • An AR-style implement-path overlay rendered in the 3D viewer
TypeScriptCanvas 2DPure functionsJest
PlatformNotableMotion Lab

Coach & Team roster + a grounded, LLM-optional coach narrative

A local-first coaching layer: group sessions by athlete, and a conversational coach read that never fabricates.

Coach & Team mode is a local-first roster (its own storage key) with pure aggregation — per-athlete trend, recurring faults, and needs-attention flags, plus team-wide common weaknesses and upload tracking. The AI coach narrative composes the analysis into the SwingIQ 8-part format grounded strictly in real numbers; the existing provider seam can optionally rephrase it with an LLM behind a flag (off by default), so it stays fully functional with no API keys and never invents findings.

  • Local-first roster, pure tested aggregation, no accounts
  • Sessions link to athletes via an optional, backward-compatible field
  • Deterministic 8-part coach read, LLM only warms the wording
TypeScriptReactProvider seamlocalStorage
ArchitectureFoundational

Pose-provider adapter set + an AI-validation debug panel

The pose seam now has cloud + MoveNet adapters, and the analysis exposes its full internals for validation.

Completed the PoseProvider adapter set: a cloud adapter (opt-in via env, validates the untrusted response, stays basis estimated, never throws) and a documented MoveNet placeholder, with a selector that prefers on-device for privacy and falls back honestly. A new AI-validation panel surfaces the raw pipeline output — per-frame pose confidence, dropped frames, phase timestamps, raw metrics, object-tracking and kinetic-chain internals, and device capabilities (WebGPU/WebNN/WASM) — so model output can actually be inspected, not trusted blindly.

  • Cloud + MoveNet adapters behind one interface; on-device stays the default
  • Per-frame confidence, dropped frames, and raw internals in one panel
  • Everything additive — no change to the working pipeline’s shape
TypeScriptMediaPipeuseSyncExternalStore
Motion IntelligenceMajorMotion Lab

Depth-aware 3D biomechanics — rotation that finally reads the z-axis

Browser-native 3D swing analysis across all five sports, with no video ever leaving the device.

Motion Lab estimates body pose from a single phone video and reconstructs the swing in three dimensions — so rotation, tilt, and sequencing are measured through depth instead of guessed from a flat silhouette. The whole pipeline runs client-side, which keeps athletes’ video private and removes server cost from the most expensive part of the product.

  • Single-camera pose → depth-aware 3D reconstruction
  • Custom canvas viewer (not a heavyweight Three.js scene) for low-end phones
  • Same engine generalizes across all 5 sports
TypeScriptMediaPipeCanvas 2DWebWorkers
PlatformNotable

Moat Foundations — readiness, player model, skill transfer & benchmark mirror

A cluster of local-first intelligence modules that compound on a player’s own data.

Shipped readiness scoring, a longitudinal player model, a skill-transfer graph, a performance graph, and a benchmark mirror — all under /labs. Each runs on the data the athlete already has, so insight deepens the more they use SwingIQ without any external dependency.

  • readiness · playerModel · skillTransfer · performanceGraph · benchmarkMirror
  • Honest-first, local-first, no account required
  • Composable modules rather than one monolith
TypeScript
PlatformNotable

Fix Stack + DrillMatch — from diagnosis to the right drill

Turns a ranked fault list into a prioritized stack of fixes and the drills that address them.

DrillMatch maps diagnosed faults to a curated drill library, and Fix Stack orders them so the athlete always sees the single highest-leverage thing first. The framing copy lives in one place (lib/coaching/fixFraming) so the message stays consistent everywhere it appears.

  • Fault → drill matching with a single prioritized stack
  • Centralized framing copy (no duplicated CTA strings)
  • Player Arc progress intelligence alongside it
TypeScript
Motion IntelligenceMajor

Fault ontology + retest engine — closing the improvement loop

A structured fault taxonomy plus an engine that proves whether a fix actually held.

Every diagnosed fault maps into a shared ontology with retest conditions (same camera angle, distance, equipment). The engine reminds you when a finding is due, then produces an honest before/after read once you re-analyze. Comparisons are deliberately labelled as directional video reads, not measured biomechanics.

  • Typed fault taxonomy reused across all sports
  • Condition-matched retests for fair before/after comparison
  • Role-aware explanations (player / parent / coach) off the same finding
TypeScriptRules engine
Design SystemNotable

7-theme token engine — restyle everything, change nothing

A data-theme palette system retokenizes the entire app while coaching and data stay untouched.

A single set of CSS custom properties (driven by a data-theme attribute and palette definitions in globals.css) powers seven hand-built themes. Components reference semantic tokens — bg-card, text-foreground, bg-primary — so a theme swap is purely cosmetic and provably can’t alter logic or stored data.

  • Semantic tokens, not hard-coded colors, across the app
  • Theme choice persisted and included in user backups
  • Cosmetic-only guarantee: no coaching/data ever changes
CSS variablesTailwindNext.js
ArchitectureFoundational

Keyless instant start — local-first by default

Removed the sign-up wall: full value with data kept on the device, accounts optional forever.

The app boots straight into analysis with state persisted locally in the browser. Sign-up, sign-in, and password reset all exist, but they’re strictly opt-in. This reframed the entire data model around local ownership first, sync second.

  • Zero-friction first run, no email required
  • Local-first persistence with optional account sync
  • Privacy posture that respects parents setting up for kids
TypeScriptIndexedDB / localStorage
PerformanceNotable

Offline-resilient at the range

Graceful offline handling with a queue that completes network work when signal returns.

The places people actually train have the worst reception. The app now detects connectivity loss, keeps work safely on-device, surfaces a clear offline banner, and queues anything network-bound to finish automatically on reconnect.

  • Connectivity-aware UI with an offline banner
  • Durable on-device work buffer
  • Auto-flushing action queue on reconnect
TypeScriptService WorkerPWA
AI & VisionNotable

Deterministic agent layer + "Welcome Back"

A deterministic intelligence layer that resumes context and surfaces the single best next step.

On return, the app summarizes a player’s last focus, rates confidence in their top priority, and proposes one low-friction next step — all derived from their own data with no AI account required. It is deterministic by design, so the same inputs always produce the same guidance.

  • Resume-context + next-best-step on every visit
  • Runs with zero external AI dependency
  • Wired into both the marketing and app dashboards
TypeScript
Security & PrivacyNotablev1.2

Backup schema v1.2 — every feature must declare how it exports

A versioned, portable backup format that now covers badges, XP, streaks, and tutorial state.

Backups moved to a versioned schema (v1.2) that captures all user-owned data — sessions, equipment, gamification, community progress, and tutorial history. Restore shows a per-category preview with merge or replace modes. New features are now required to define their export/restore contract so backups stay complete as the platform grows.

  • Versioned, forward-compatible export format
  • Per-category restore preview with merge / replace
  • Export contract enforced for every new feature
TypeScriptJSON schema
Developer ExperienceFoundational

Turbo monorepo with quality gates wired into CI

Type-checking, naming rules, placeholder/trust scans, and security checks all gate every change.

The project is a Turborepo of apps, packages, and a server, with a CI pipeline that runs type-check, a naming linter, a placeholder/trust scanner, and dependency + secret security checks. Automated monthly audits (SEO/AEO/GEO, AI features, engagement, build health) compile into a single master report.

  • Turborepo workspaces: apps / packages / server
  • CI gate: type-check · naming · trust scan · security
  • Scheduled monthly audits compiled into one executive report
TurborepoTypeScriptESLintGitHub Actions
ArchitectureFoundational

Unified lib/pose — one source of truth for movement

Collapsed scattered pose/motion code into a single shared library every sport draws from.

Pose estimation, smoothing, and keypoint math had grown duplicated across features. Consolidating it into lib/pose gave the retest engine, Motion Lab, and the fault ontology a single, tested foundation — so a fix to the math improves every surface at once instead of one.

  • One pose pipeline shared by diagnosis, retest, and Motion Lab
  • Removed duplicated keypoint/smoothing implementations
  • Tested core that downstream features build on
TypeScriptMonorepo
AI & VisionMajor

Real AI vision — frames in, coaching out

The video analyzer now sends real frames to a vision model instead of faking analysis.

The swing-video analyzer extracts representative frames and routes them to a vision provider, then folds the result into the deterministic diagnostic layer. The provider is abstracted behind an interface so the model can be swapped without touching feature code.

  • Frame extraction → vision provider → ranked faults
  • Provider-agnostic interface (swap models without rewrites)
  • Layered on top of the deterministic rules engine, not replacing it
TypeScriptVision LLMNext.js route handlers
ArchitectureFoundational

Five sports, five real diagnostic engines

Treated each sport as a distinct movement model instead of golf with relabeled tips.

A tennis serve, a baseball swing, and a golf swing are fundamentally different motions. Rather than share one engine with swapped vocabulary, each sport got its own diagnostic rules, benchmarks, drill library, and coaching language — switching sports retargets the whole experience.

  • Per-sport rules, benchmarks, and drill libraries
  • Sport switch retargets dashboard, plan, and feedback
  • Foundation the later motion + retest work built on
TypeScriptRules engine

Showing 17 of 17 developer updates

This is the engineering log. For the plain-English, athlete-facing version of what shipped, see the product updates page. Movement findings are directional reads from video, sharpened by every swing you add — not measured lab biomechanics.