v145 · Performance · JavaScript · demo
Frame Timeline
A visual waterfall of each paint entry's four timing phases: startTime, renderTime, paintTime, and presentationTime. Load images to trigger LCP and element-timing entries and see how each phase contributes to total display latency — the new Chrome 145 fields (paintTime and presentationTime) show the compositor handoff cost that was previously invisible.
Chrome 145+ —
entry.paintTime and entry.presentationTime on LCP, element-timing, and paint entries. In older browsers only startTime and renderTime are available; the chart shows those phases in grey.
Click "Load image" to trigger a new LCP candidate · repeat to add more entries · each bar shows the 4-phase timeline
LCP / element-timing target
No image yet
Each click loads a new SVG image, triggering an element-timing and LCP entry. The observer captures all four timing phases.
Paint phase waterfall
startTime (layout/render start)
renderTime (element visible)
paintTime (CPU rasterise done)
presentationTime (frame on screen)
Load an image to see paint phases here…
Raw timing data (ms from navigation start)
type
startTime
renderTime
paintTime
presentationTime
No entries yet
// presentationTime and paintTime — Chrome 145
// These fields show the compositor pipeline, previously invisible.
const observer = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
console.log({
type: entry.entryType,
startTime: entry.startTime, // layout/render start
renderTime: entry.renderTime, // element became visible (LCP/element-timing)
paintTime: entry.paintTime, // ← NEW Chrome 145: CPU rasterise complete
presentationTime: entry.presentationTime, // ← NEW Chrome 145: frame on screen
});
// Gap analysis:
const cpuCost = entry.paintTime - entry.renderTime; // CPU paint time
const compositorCost = entry.presentationTime - entry.paintTime; // compositor handoff
console.log('CPU paint:', cpuCost.toFixed(1), 'ms');
console.log('Compositor:', compositorCost.toFixed(1), 'ms');
}
});
observer.observe({ type: 'largest-contentful-paint', buffered: true });
observer.observe({ type: 'element', buffered: true });
observer.observe({ type: 'paint', buffered: true });