WebKit requestAnimationFrame and Hz Detection
WebKit’s requestAnimationFrame (rAF) is the heartbeat of browser rendering. This document covers how Monolex detects actual display performance and adapts its timing system accordingly.Architecture Overview
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ WEBKIT RAF IN MONOLEX ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Hardware Display (120Hz/60Hz/30Hz) │
│ │ │
│ ▼ │
│ WebKit RAF Scheduler │
│ │ (measures actual frame timing) │
│ ▼ │
│ DisplayTimingManager (TypeScript) │
│ │ invoke("set_measured_fps", fps) │
│ ▼ │
│ DisplayTiming (Rust) │
│ │ effective_hz.store(fps) │
│ ▼ │
│ GridWorker tick_interval │
│ │ frames(3) = 3 * (1000/fps) ms │
│ ▼ │
│ Adapted timing throughout system │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
RAF Callback Timing
WebKit calls RAF callbacks at the display’s refresh rate, but actual timing varies:| Condition | Typical Rate | Behavior |
|---|---|---|
| Normal operation | 60fps | Callbacks every 16.67ms |
| Background tab | 1fps | Severely throttled |
| System load | 30-45fps | Variable interval |
| Low power mode | 30fps | Power-saving throttle |
Hz Detection Flow
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Hz DETECTION FLOW │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Frontend (RAF) Backend (Rust) │
│ │ │ │
│ │ measureFrame() │ │
│ │ track callback timing │ │
│ │ │ │
│ │ average over 60 samples │ │
│ │ │ │
│ │ invoke("set_measured_fps") │ │
│ │──────────────────────────────────────►│ │
│ │ │ set_measured(fps) │
│ │ │ effective_hz.store() │
│ │ │ │
│ │ │ GridWorker reads │
│ │ │ frames(n) uses new Hz │
│ │ │ │
└─────────────────────────────────────────────────────────────────────────────────┘
FPS Safety Limits
Copy
┌─────────────────────────────────────────────────────────────────┐
│ FPS VALUE SAFETY PROCESSING │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Measured FPS arrives (e.g., 25, 60, 90) │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Apply Safety Limits │ │
│ │ │ │
│ │ Below 20? → Set to 20 (minimum) │ │
│ │ Above 120? → Cap at display max │ │
│ │ In range? → Use as-is │ │
│ │ │ │
│ └─────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ Safe FPS value used for all timing │
│ │
│ Why limits? │
│ ─────────── │
│ • 20fps minimum: Prevents system freeze │
│ • Display max: Never faster than screen can show │
│ │
└─────────────────────────────────────────────────────────────────┘
Frame Duration Calculation
Copy
┌─────────────────────────────────────────────────────────────────┐
│ "WAIT FOR N FRAMES" CALCULATION │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Input: "Wait for 3 frames" │
│ │
│ Calculation: │
│ ───────────── │
│ Frame duration = 1 second ÷ FPS │
│ Wait time = Frame duration × N │
│ │
│ Examples: │
│ ────────── │
│ @ 60fps: 1 frame = 16.7ms → 3 frames = 50ms │
│ @ 30fps: 1 frame = 33.3ms → 3 frames = 100ms │
│ @120fps: 1 frame = 8.3ms → 3 frames = 25ms │
│ │
│ Speed: Nearly instant (billionths of a second) │
│ │
└─────────────────────────────────────────────────────────────────┘
System Load Impact
Copy
┌─────────────────────────────────────────────────────────────────────────────────┐
│ RAF RATE VS SYSTEM LOAD │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ CPU Load Measured FPS Frame Budget Notes │
│ ════════ ════════════ ════════════ ═════ │
│ │
│ 10-30% 60 fps 16.67ms Normal operation │
│ 50-70% 45-55 fps 18-22ms Slight pressure │
│ 80-90% 30-40 fps 25-33ms Heavy load │
│ 95%+ 20-30 fps 33-50ms Severe throttling │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Adaptive Response
When system load increases:- WebKit naturally throttles RAF rate
- DisplayTimingManager detects lower fps
- Backend adjusts all frame-based timeouts
- Fewer IPC calls, larger batches
- System maintains stability under load
ProMotion Display Support
Copy
┌─────────────────────────────────────────────────────────────────┐
│ PROMOTION DISPLAY HANDLING │
├─────────────────────────────────────────────────────────────────┤
│ │
│ MacBook Pro with ProMotion can run at: │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 120Hz ████████████████████████ Smooth animation │ │
│ │ │ │
│ │ 60Hz ████████████ Normal operation │ │
│ │ │ │
│ │ 24Hz ████ Static content │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ Monolex Detection: │
│ ─────────────────── │
│ 1. Check display capabilities on startup │
│ 2. Set maximum allowed rate │
│ 3. Fallback to 60Hz if detection fails │
│ │
│ Benefit: Automatically uses your display's best rate │
│ │
└─────────────────────────────────────────────────────────────────┘
Summary
RAF as Heartbeat
WebKit RAF timing reflects actual display performance.
60-Sample Average
Smooth FPS measurement over 60 frames (~1 second).
20-120Hz Range
Minimum 20fps floor, maximum hardware Hz cap.
~4-8ns Cost
Lock-free atomic operations for minimal overhead.
Related
- Overview - Adaptive timing system overview
- Tokio Tick - How Rust timer uses Hz
- Control Layers - Hz (Outer) vs ACK (Inner)