An invisible macOS menu bar app that monitors your posture through your webcam and yells at you when you slouch.
No window. No dock icon. Just silent, constant judgment — and a voice that tells you to sit up straight.
PostureGuard uses MediaPipe Pose and FaceMesh to track your head, face, and shoulders in real time via your webcam. On first launch, you calibrate it by sitting in your best posture. From then on, it measures deviations from your baseline — not generic thresholds — and alerts you when you start slouching.
- Head dropping — chin drifting down (tech neck)
- Slouching — your ear-to-shoulder distance shrinking as you compress
- Leaning left/right — head drifting off-center from your shoulders
- Shoulder tilt — one shoulder higher than the other
- Leaning forward — face getting closer to the camera
- Menu bar icon changes:
PG(good) →PG!(warning) →PG!!(bad) - macOS notification with your current score and the issue
- Voice alert via text-to-speech (Samantha) after 5 seconds of sustained bad posture
- 45-second cooldown between voice alerts so it doesn't drive you insane
- macOS 12+ (Monterey or later)
- Python 3.9+
- A built-in or external webcam
- Camera permissions granted to the terminal/app
git clone https://github.com/schaferjart/PostureGuard.git
cd PostureGuardpip3 install opencv-python mediapipe numpy rumpsIf mediapipe tries to build opencv-contrib-python from source (takes forever), install without dependency resolution and add the missing pieces:
pip3 install opencv-python mediapipe --no-deps
pip3 install absl-py protobuf sounddevice numpy matplotlibNumPy compatibility note: If you get numpy.core.multiarray import errors, your matplotlib may be too old for your numpy version. Fix with:
pip3 install --upgrade matplotlibpython3 postureguard.pyLook for PG in your menu bar. Click it to see the menu.
This gives you a proper app bundle with no dock icon and camera permission prompts:
pip3 install py2app
python3 setup.py py2app -A
open dist/PostureGuard.appThe -A flag creates an alias build (fast, for development). For a standalone redistributable build:
python3 setup.py py2apposascript -e 'tell application "System Events" to make login item at end with properties {path:"/path/to/PostureGuard/dist/PostureGuard.app", hidden:true}'Replace /path/to/PostureGuard with your actual path.
- Click PG in the menu bar
- Click Calibrate Good Posture
- Sit up straight — best posture you've got
- Hold still for ~3 seconds while it captures your baseline
- You'll hear "Calibration complete. I'm watching you."
- Monitoring starts automatically
Your calibration is saved to ~/posture_calibration.json and persists across sessions.
| Menu Item | What It Does |
|---|---|
| Status | Shows if monitoring is active or paused |
| Score | Your current posture score (0-100%) |
| Issues | The most pressing posture issue right now |
| Stop/Start Monitoring | Toggle posture tracking on/off |
| Show Camera | Opens a live camera window with skeleton overlay, face mesh, and score HUD — useful for seeing exactly what the app sees and debugging |
| Calibrate Good Posture | Recapture your baseline (do this when you change chairs, camera angle, etc.) |
| Sensitivity | Low (relaxed) / Medium / High (strict) |
| Quit PostureGuard | Stops monitoring and exits |
Click Show Camera to open a live view showing:
- Green skeleton overlay on your body
- Cyan face mesh contours
- Posture score bar (green/yellow/red)
- Issue labels in red when posture is bad
- Flashing red border when things are really bad
Press q in the camera window or click Hide Camera to close it.
| Level | Description | Best For |
|---|---|---|
| Low | Relaxed thresholds, only flags major slouching | Casual use, couch computing |
| Medium | Balanced detection (default) | Regular desk work |
| High | Strict, catches subtle deviations | When you're serious about posture |
| File | Purpose |
|---|---|
postureguard.py |
Main menu bar app — background monitoring, alerts, calibration |
camera_preview.py |
Standalone camera window with live skeleton/score overlay |
setup.py |
py2app config to build as a macOS .app bundle |
~/posture_calibration.json |
Your calibration data (auto-generated, not in repo) |
postureguard.py (menu bar app, rumps)
├── Background thread: captures frames, runs MediaPipe, computes score
├── Main thread: rumps event loop, menu bar updates
└── Subprocess: camera_preview.py (launched on demand)
camera_preview.py (standalone OpenCV window)
├── Independent camera capture + MediaPipe processing
├── Reads calibration from ~/posture_calibration.json
└── Displays live HUD with skeleton overlay
The menu bar app and camera preview run as separate processes because macOS requires OpenCV windows (cv2.imshow) to run on the main thread, but rumps already owns the main thread for the menu bar event loop.
macOS requires explicit camera access. On first run:
- You may see a "Python wants to access the camera" dialog — click Allow
- If no dialog appears, go to System Preferences → Privacy & Security → Camera and enable access for your terminal app (Terminal, iTerm2, etc.) or PostureGuard.app
"Score: --" and nothing happens
- You need to calibrate first. Click PG → Calibrate Good Posture.
Camera not working
- Check System Preferences → Privacy & Security → Camera
- Make sure your terminal app or PostureGuard.app has camera permission
- If you recently changed permissions, restart the app
Score always 100% / never triggers
- Your calibration might be stale. Recalibrate with your current setup.
- Try High sensitivity from the Sensitivity menu.
- Make sure the camera can see your face AND shoulders.
Too many false alarms
- Switch to Low sensitivity
- Recalibrate in a more natural (but still upright) position — don't sit unnaturally straight during calibration or everything will seem like slouching.
High CPU usage
- The app checks posture every 0.5 seconds (not every frame). Typical usage is ~15-25% of one CPU core. The camera preview uses more when open. Close the camera preview when you don't need it.
All processing happens locally on your Mac. No images, video, or posture data are sent anywhere. The only file created is ~/posture_calibration.json, which contains abstract landmark ratios — not images.
MIT
Built with: