Skill: Measure JS FPS
Monitor and measure JavaScript frame rate to quantify app smoothness and identify performance regressions.
Quick Command
# Method 1: Built-in Perf Monitor
# Shake device → Dev Menu → "Perf Monitor"
# Method 2: Flashlight (Android, detailed reports)
curl https://get.flashlight.dev | bash
flashlight measureWhen to Use
- Animations feel choppy or janky
- Scrolling is not smooth
- Need baseline FPS metrics before/after optimization
- Want to compare performance across builds
Prerequisites
- React Native app running on device/simulator
- For Flashlight: Android device (iOS not supported)
Note: This skill involves interpreting visual output (FPS graphs, performance overlays). AI agents cannot yet process screenshots autonomously. Use this as a guide while reviewing metrics manually, or await MCP-based visual feedback integration (see roadmap).
Step-by-Step Instructions
Method 1: React Perf Monitor (Quick Check)
Open Dev Menu:
- iOS Simulator:
Ctrl + Cmd + Zor Device > Shake - Android Emulator:
Cmd + M(Mac) /Ctrl + M(Windows)
- iOS Simulator:
Select "Perf Monitor"
Observe the overlay showing:
- UI (Main) thread FPS - Native rendering
- JS thread FPS - JavaScript execution
- RAM usage
Hide with "Hide Perf Monitor" from Dev Menu
Interpretation:
- 60 FPS = Smooth (16.6ms per frame)
- < 60 FPS = Dropping frames
- 120 FPS target for high refresh rate devices (8.3ms per frame)
Method 2: Flashlight (Automated Benchmarking)
Android only. Provides detailed reports and JSON export.
Flashlight FlatList vs FlashList Comparison
Flashlight shows comparative performance data:
- Score (0-100): Overall performance rating (higher is better)
- Average FPS: Target 60 FPS for smooth scrolling
- FPS Graph: Real-time frame rate over test duration
- CPU/RAM metrics: Resource consumption
The image shows FlatList (score: 3) vs FlashList (score: 67) - a dramatic difference visible in both the score and FPS graph.
Installation:
# Install Flashlight CLI
curl https://get.flashlight.dev | bashUsage:
# Start measuring (app must be running on Android)
flashlight measureFeatures:
- Real-time FPS graph
- Average FPS calculation
- CPU and RAM metrics
- Overall performance score
- JSON export for CI comparison
Important: Disable Dev Mode
Always disable development mode for accurate measurements:
Android:
- Open Dev Menu
- Settings > JS Dev Mode → OFF
iOS (React Native CLI):
# Run Metro in production mode
npx react-native start --reset-cache
# Then build release variantExpo:
# Start Metro without dev mode
npx expo start --no-dev --minify
# For accurate measurements, use EAS Build for release testingCode Examples
Identify FPS Drop Source
If UI FPS drops but JS FPS is fine:
- Native rendering issue
- Too many views/complex layouts
- Heavy native animations
If JS FPS drops but UI FPS is fine:
- JavaScript computation blocking
- Expensive React re-renders
- Look for
longRunningFunctionpatterns
If Both drop:
- Mixed issue, start with JS profiling
Target Frame Budgets
// 60 FPS = 16.6ms per frame
const FRAME_BUDGET_60 = 16.6;
// 120 FPS = 8.3ms per frame
const FRAME_BUDGET_120 = 8.3;
// If your function takes longer, it will drop frames
const longRunningFunction = () => {
let i = 0;
while (i < 1000000000) { // This blocks for seconds!
i++;
}
};Interpreting Results
| FPS Range | User Perception | Action |
|---|---|---|
| 55-60 | Smooth | Acceptable |
| 45-55 | Slight stutter | Investigate |
| 30-45 | Noticeable jank | Optimize required |
| < 30 | Very choppy | Critical fix needed |
Flashlight CI Integration
# Export measurements to JSON
flashlight measure --output results.json
# Compare builds
flashlight compare baseline.json current.jsonCommon Pitfalls
- Measuring in dev mode: Results will be artificially slow
- Not using real device: Simulators don't reflect real performance
- Ignoring UI thread: React Native has two threads - JS issues don't always show on UI thread
- Single measurement: Run multiple times, FPS varies
Related Skills
- js-profile-react.md - Find what's causing FPS drops
- js-animations-reanimated.md - Fix animation-related drops
- js-lists-flatlist-flashlist.md - Fix scroll-related drops