# Stop Slouching! Build a Real-time AI Posture Guard with MediaPipe and Vue.js

> Source: <https://dev.to/beck_moulton/stop-slouching-build-a-real-time-ai-posture-guard-with-mediapipe-and-vuejs-255n>
> Published: 2026-09-15 00:18:00+00:00

Let's be honest: as engineers, our "focus mode" usually involves leaning into the monitor until our noses almost touch the screen. We start the day sitting like a king and end it looking like a question mark. Back pain isn't just a meme; it's a productivity killer.

In this tutorial, we’re building **Posture Guardian**, a browser-based tool using **real-time computer vision** and **pose estimation** to detect slouching, forward head posture (the "tech neck"), and uneven shoulders. We'll leverage **MediaPipe** and **Vue.js** to create a seamless experience that alerts you the moment your ergonomics fail. If you’ve been looking for a practical application for **machine learning in the browser**, this is it.

How does a browser "know" you're slouching? We need to capture frames from the webcam, process them through a pre-trained model to find skeletal landmarks, and then apply some basic trigonometry to calculate angles.

``` php
graph TD
    A[Webcam Stream] --> B[MediaPipe Pose Model]
    B --> C{Landmark Detection}
    C -->|Coordinates| D[Ergonomics Logic Engine]
    D --> E[Calculate Neck & Shoulder Angles]
    E --> F{Threshold Exceeded?}
    F -->|Yes| G[Browser Notification + Visual Alert]
    F -->|No| H[Status: Healthy]
    G --> A
    H --> A
```

To follow along, you’ll need:

`@mediapipe/pose`)
First, we need to initialize the MediaPipe Pose model. This model identifies 33 landmarks on the human body. For posture, we specifically care about the ears, shoulders, and hips.

``` js
// postureService.js
import { Pose } from "@mediapipe/pose";

export const createPoseEstimator = (onResults) => {
  const pose = new Pose({
    locateFile: (file) => `https://cdn.jsdelivr.net/npm/@mediapipe/pose/${file}`,
  });

  pose.setOptions({
    modelComplexity: 1,
    smoothLandmarks: true,
    minDetectionConfidence: 0.5,
    minTrackingConfidence: 0.5,
  });

  pose.onResults(onResults);
  return pose;
};
```

To detect "Head Forward" posture, we calculate the horizontal distance and angle between the **Ear** and the **Shoulder**. If the ear moves too far forward relative to the shoulder line, you're officially a turtle. 🐢

```
// Logic to detect Forward Head Posture
function analyzePosture(landmarks) {
  const leftEar = landmarks[7];
  const rightEar = landmarks[8];
  const leftShoulder = landmarks[11];
  const rightShoulder = landmarks[12];

  // Calculate the average ear-to-shoulder horizontal offset
  const earMidX = (leftEar.x + rightEar.x) / 2;
  const shoulderMidX = (leftShoulder.x + rightShoulder.x) / 2;

  const diff = Math.abs(earMidX - shoulderMidX);

  // If the head is more than 15% forward relative to the body
  if (diff > 0.15) {
    return { status: 'bad', message: 'Sit up straight! Your neck is straining.' };
  }
  return { status: 'good', message: 'Perfect Posture!' };
}
```

Now, let's wrap this in a Vue component. We'll use the **Webcam API** to feed the video stream into the Pose model.

```
<template>
  <div class="posture-container">
    <video ref="videoElement" class="hidden-video" autoplay></video>
    <canvas ref="canvasElement" class="overlay-canvas"></canvas>

    <div :class="['alert-box', statusClass]">
      <h2>{{ currentStatus }}</h2>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { createPoseEstimator } from './postureService';

const videoElement = ref(null);
const canvasElement = ref(null);
const currentStatus = ref('Initializing...');
const statusClass = ref('neutral');

onMounted(async () => {
  const pose = createPoseEstimator((results) => {
    // Draw landmarks on canvas
    drawUserFeedback(results);

    // Run our logic
    const analysis = analyzePosture(results.poseLandmarks);
    currentStatus.value = analysis.message;
    statusClass.value = analysis.status;

    if (analysis.status === 'bad') {
       triggerNotification();
    }
  });

  const camera = new Camera(videoElement.value, {
    onFrame: async () => {
      await pose.send({ image: videoElement.value });
    },
    width: 640,
    height: 480
  });
  camera.start();
});
</script>
```

Building a simple detection tool is one thing, but making it production-ready involves handling lighting variations, camera calibration, and state management (to avoid spamming notifications every second).

For deeper dives into **advanced AI patterns**, production-grade **Mediapipe configurations**, or how to optimize **TensorFlow.js performance** in large-scale Vue apps, I highly recommend checking out the technical deep-dives over at [WellAlly Blog](https://www.wellally.tech/blog). They cover excellent strategies for integrating wellness tech into the modern developer workflow.

Don't just show a message on the screen—tell the user even if they are in another tab.

```
function triggerNotification() {
  if (Notification.permission === "granted") {
    // Throttle notifications so we don't annoy the user
    if (Date.now() - lastNotificationTime > 60000) {
      new Notification("Posture Alert! 🚨", {
        body: "You're slouching again. Take a deep breath and sit up.",
        icon: "/guardian-logo.png"
      });
      lastNotificationTime = Date.now();
    }
  }
}
```

By combining the power of **MediaPipe** with a reactive framework like **Vue.js**, we’ve built a tool that actually improves your daily life. No expensive hardware, just a few lines of JavaScript and a webcam.

**What's next?**

How do you stay ergonomic at your desk? Let me know in the comments below! And don't forget to fix your posture right now—I know you're leaning forward while reading this. 😉

Happy coding! 🥑
