Surfaced by the #4539 desktop main-thread attribution baseline (docs/perf/desktop-mainthread-baseline-2026-07-02.md). Part of #4539 / #4487 (desktop render axis).
Signal
#4539 set out to characterize the 52% / ~11 s "Other" bucket on desktop /dashboard. The new harness (scripts/measure-desktop-mainthread.mjs) decomposed it, and the single largest previously-uncharacterized component is Layerize:
| "Other" component |
unthrottled (cpu 1) |
throttled (cpu 4) |
Layerize |
27.6% (3.06 s) |
15.5% |
ThreadControllerImpl::RunTask (scheduler) |
20.4% |
16.5% |
| rest (IntersectionObserver, GC, mojo, …) |
~7% |
~10% |
Layerize is stably a top-2 "Other" component across both host conditions → a real structural cost, not a host artifact. Lighthouse buckets Layerize into "Other," which is exactly why the 52% was a black box.
What Layerize is
Blink compositor layerization — assigning paint layers to compositing layers and (re)building the compositing layer tree. Its cost scales with the number of composited layers and how often the layer tree is rebuilt. ~3 s of it on desktop /dashboard means the page is creating/updating a large number of compositing layers.
Lever / investigation path
- Count the composited layers on prod
/dashboard via CDP LayerTree.enable → LayerTree.layerTreeDidChange (or DevTools "Layers" panel). Establish how many layers exist and which nodes own them.
- Audit layer-forcing CSS for over-promotion beyond the two unavoidable map canvases (deck.gl
scene-container>canvas + maplibregl-canvas): will-change, transform: translateZ(0) / 3D transforms, position: sticky/fixed, opacity/filter on large subtrees, per-panel promotion, backdrop-filter.
- Reduce unnecessary promotions so the compositor isn't re-layerizing ~3 s worth.
Tension to respect
#4538 (convert non-composited animations to transform/opacity) promotes some elements to their own compositing layer to make paint cheap. Over-promotion is the opposite failure and inflates Layerize. Balance the two: promote what animates, demote what doesn't — don't blanket-will-change.
Acceptance
- A named cause: which elements/CSS over-promote, backed by a composited-layer count.
Layerize self-time share drops, re-measured by scripts/measure-desktop-mainthread.mjs (before/after, both --cpu 1 and --cpu 4).
- Absolute desktop
mainthread-work cross-checked against a clean PSI/Calibre run (the harness gives the relative share, not the headline absolute — KTD1).
Effort: medium (investigation-first). This is the desktop render-axis twin of the INP/map presentation work; distinct from #4536 (forced reflow / styleLayout) and #4538 (non-composited animations).
Surfaced by the #4539 desktop main-thread attribution baseline (
docs/perf/desktop-mainthread-baseline-2026-07-02.md). Part of #4539 / #4487 (desktop render axis).Signal
#4539set out to characterize the 52% / ~11 s "Other" bucket on desktop/dashboard. The new harness (scripts/measure-desktop-mainthread.mjs) decomposed it, and the single largest previously-uncharacterized component isLayerize:LayerizeThreadControllerImpl::RunTask(scheduler)Layerizeis stably a top-2 "Other" component across both host conditions → a real structural cost, not a host artifact. Lighthouse bucketsLayerizeinto "Other," which is exactly why the 52% was a black box.What
LayerizeisBlink compositor layerization — assigning paint layers to compositing layers and (re)building the compositing layer tree. Its cost scales with the number of composited layers and how often the layer tree is rebuilt. ~3 s of it on desktop
/dashboardmeans the page is creating/updating a large number of compositing layers.Lever / investigation path
/dashboardvia CDPLayerTree.enable→LayerTree.layerTreeDidChange(or DevTools "Layers" panel). Establish how many layers exist and which nodes own them.scene-container>canvas+maplibregl-canvas):will-change,transform: translateZ(0)/ 3D transforms,position: sticky/fixed,opacity/filteron large subtrees, per-panel promotion,backdrop-filter.Tension to respect
#4538(convert non-composited animations totransform/opacity) promotes some elements to their own compositing layer to make paint cheap. Over-promotion is the opposite failure and inflatesLayerize. Balance the two: promote what animates, demote what doesn't — don't blanket-will-change.Acceptance
Layerizeself-time share drops, re-measured byscripts/measure-desktop-mainthread.mjs(before/after, both--cpu 1and--cpu 4).mainthread-workcross-checked against a clean PSI/Calibre run (the harness gives the relative share, not the headline absolute — KTD1).Effort: medium (investigation-first). This is the desktop render-axis twin of the INP/map presentation work; distinct from
#4536(forced reflow /styleLayout) and#4538(non-composited animations).