The timeline grid was not matching the volume grid due to overflow situations. This occurred when the cron job (running every 10 minutes) reported screen time increases greater than 10 minutes in a single interval.
Example Scenario
Record at 9:55 AM: 0 minutes
Record at 10:00 AM: 100 minutes
Problem: 100 minutes appeared in a 5-minute gap
Old behavior: Clamp to 10 minutes, lose 90 minutes to "Artifacts"
New behavior: Distribute 100 minutes backwards into empty blocks
Solution: Backfill Algorithm
Algorithm Steps
Iterate through time blocks sequentially (7:00 AM - 11:40 PM, 100 blocks of 10 minutes each)
Calculate raw usage for each block based on cumulative screen time data
Handle overflow:
If usage ≤ 10 minutes: Use actual usage
If usage > 10 minutes:
Fill current block with 10 minutes
Add remainder to backlog
Backfill process:
When backlog exists, work backwards from current block
Fill previous empty blocks until backlog is exhausted
Each block can hold maximum 10 minutes
Volume grid synchronization:
Volume grid now uses timeline's active block count instead of simple totalMinutes/10
This ensures both grids always match in number of filled blocks
Implementation Details
// Three-pass algorithm:// 1. Calculate raw usage for each block// 2. Apply backfill algorithm with backlog management// 3. Generate HTML and calculate statistics// Volume grid now syncs with timeline:const actualActiveBlocks = timelineStats?.visibleBlocksCount || numFilled;
Key Features
Volume Preservation: All screen time minutes are represented in the grid
Timeline Approximation: Usage is distributed backwards from sync points
Visual Clarity: No single "exploded" blocks with impossible usage
Grid Synchronization: Volume and timeline grids always show same number of active blocks
Enhanced Tooltips: Show backfilled vs. direct usage
Statistics Tracking: New "Backfilled" metric in blue
✅ Volume: Total red blocks match total screen time
✅ Timeline: Better approximation of when usage occurred
✅ Synchronization: Both grids show identical number of active blocks
✅ Statistics: Clear breakdown of backfilled vs. direct usage
✅ Tooltips: Enhanced information about block contents
The Mismatch Issue & Fix
Why the Mismatch Occurred
The original volume grid used simple math: Math.ceil(totalMinutes / 10) to determine filled blocks. However, the backfill algorithm can create more active blocks than this simple calculation suggests.
Example:
380 minutes ÷ 10 = 38 blocks (volume grid)
But with overflow backfill: 41 blocks become active (timeline grid)