PIRX Docs
Dashboard

Sleep Ring

Source: components/home/sleep-ring.tsx


What You See

A card titled 'Sleep Score' with a Moon icon. The main feature is a large circular ring showing your sleep score (0 to 100) in the center with a quality label below it (like 'Good' or 'Excellent'). The ring itself is segmented into colored arcs: yellow for Light sleep, purple for Deep sleep, and violet for REM sleep. The ring fills proportionally to your score. Below the main ring are three smaller rings, one per sleep stage, each showing the percentage of total sleep time spent in that stage and the duration in hours and minutes. The card header also shows total sleep duration. An info popover explains how sleep data works.

How the Numbers Work

The sleep score comes directly from your wearable device on a 0-to-100 scale. The stage breakdown (Light, Deep, REM) is measured by your watch during the night. Each stage is shown as a percentage of total sleep time: for example, if you slept 7 hours and spent 1.5 hours in Deep sleep, Deep shows as 21 percent. The main ring fills to the score percentage and is divided into colored segments matching the stage proportions.

Step by Step

Terra sends sleep webhooks when your wearable syncs. The backend runs normalize_sleep_entry to map provider-specific fields to a standard schema: sleep_score (0-100), and durations in seconds for deep, light, and REM stages. These values are stored in the physiology table. The dashboard fetches the most recent row. The component calculates total sleep = deep + light + REM seconds, then each stage's percentage = (stage_seconds / total) * 100. The main ring circumference is multiplied by score/100 to determine the filled portion, which is then split into colored arcs matching each stage's share of the total. A label maps the score to a word: 80+ is Excellent, 60-79 is Good, below 60 is Needs Work. Each small ring fills to that stage's percentage. Framer Motion animates the arcs in with a staggered 0.1-second delay per segment.

On this page