Formatting
diff --git a/ui/src/frontend/timeline_page/track_tree_view.ts b/ui/src/frontend/timeline_page/track_tree_view.ts
index ce1ed9d..0e1cad7 100644
--- a/ui/src/frontend/timeline_page/track_tree_view.ts
+++ b/ui/src/frontend/timeline_page/track_tree_view.ts
@@ -294,7 +294,13 @@
         overflowY: 'auto',
         overflowX: 'hidden',
         enableWebGL: true,
-        onCanvasRedraw: ({ctx, virtualCanvasSize, canvasRect, webglCanvas, webglCtx}) => {
+        onCanvasRedraw: ({
+          ctx,
+          virtualCanvasSize,
+          canvasRect,
+          webglCanvas,
+          webglCtx,
+        }) => {
           this.drawCanvas(
             ctx,
             virtualCanvasSize,
@@ -521,7 +527,10 @@
 
     // X: clip from timelineRect.left (TRACK_SHELL_WIDTH) to the right edge
     // Adjusted for the canvas offset (virtual canvas position)
-    const scissorX = Math.max(0, Math.round((timelineRect.left + canvasOffset.x) * dpr));
+    const scissorX = Math.max(
+      0,
+      Math.round((timelineRect.left + canvasOffset.x) * dpr),
+    );
     const scissorWidth = canvasWidth - scissorX;
 
     // Y: full canvas height (no vertical clipping needed as tracks are already filtered)
diff --git a/ui/src/plugins/dev.perfetto.ProcessSummary/group_summary_track.ts b/ui/src/plugins/dev.perfetto.ProcessSummary/group_summary_track.ts
index c40d5af..d8a780e 100644
--- a/ui/src/plugins/dev.perfetto.ProcessSummary/group_summary_track.ts
+++ b/ui/src/plugins/dev.perfetto.ProcessSummary/group_summary_track.ts
@@ -100,20 +100,22 @@
 
 // Cached WebGL program state (shared across instances for same GL context)
 // Only program and attribute/uniform locations are shared - buffers are per-instance
-let cachedGlProgram: {
-  gl: WebGL2RenderingContext;
-  program: WebGLProgram;
-  positionLocation: number;
-  baseColorLocation: number;
-  variantColorLocation: number;
-  disabledColorLocation: number;
-  selectorLocation: number;
-  resolutionLocation: WebGLUniformLocation;
-  offsetLocation: WebGLUniformLocation;
-  dprLocation: WebGLUniformLocation;
-  timeScaleLocation: WebGLUniformLocation;
-  timePxOffsetLocation: WebGLUniformLocation;
-} | undefined;
+let cachedGlProgram:
+  | {
+      gl: WebGL2RenderingContext;
+      program: WebGLProgram;
+      positionLocation: number;
+      baseColorLocation: number;
+      variantColorLocation: number;
+      disabledColorLocation: number;
+      selectorLocation: number;
+      resolutionLocation: WebGLUniformLocation;
+      offsetLocation: WebGLUniformLocation;
+      dprLocation: WebGLUniformLocation;
+      timeScaleLocation: WebGLUniformLocation;
+      timePxOffsetLocation: WebGLUniformLocation;
+    }
+  | undefined;
 
 export class GroupSummaryTrack implements TrackRenderer {
   private hover?: GroupSummaryHover;
@@ -486,8 +488,9 @@
     // Check if we need to rebuild the vertex buffer (data changed)
     // Include data.start because positions are stored relative to it
     const dataGeneration = data.starts.length + Number(data.resolution);
-    const needsRebuild = dataGeneration !== this.lastDataGeneration ||
-                         data.start !== this.lastDataStart;
+    const needsRebuild =
+      dataGeneration !== this.lastDataGeneration ||
+      data.start !== this.lastDataStart;
 
     if (needsRebuild) {
       // Reset buffer upload tracking - any rebuild needs GPU upload
@@ -598,11 +601,17 @@
     // Build selector buffer only when hover state changes
     const hoveredUtid = this.trace.timeline.hoveredUtid;
     const hoveredPid = this.trace.timeline.hoveredPid;
-    const hoverChanged = hoveredUtid !== this.lastHoveredUtid ||
-                         hoveredPid !== this.lastHoveredPid ||
-                         needsRebuild;
+    const hoverChanged =
+      hoveredUtid !== this.lastHoveredUtid ||
+      hoveredPid !== this.lastHoveredPid ||
+      needsRebuild;
 
-    if (hoverChanged && this.cachedUtids && this.cachedPids && this.selectorBuffer) {
+    if (
+      hoverChanged &&
+      this.cachedUtids &&
+      this.cachedPids &&
+      this.selectorBuffer
+    ) {
       const isHovering = hoveredUtid !== undefined;
 
       for (let i = 0; i < this.cachedRectCount; i++) {
@@ -613,7 +622,8 @@
 
         if (this.mode === 'sched' && isHovering) {
           const isThreadHovered = hoveredUtid === utid;
-          const isProcessHovered = hoveredPid !== undefined && pid === hoveredPid;
+          const isProcessHovered =
+            hoveredPid !== undefined && pid === hoveredPid;
 
           if (!isThreadHovered) {
             if (isProcessHovered) {
@@ -638,18 +648,21 @@
     }
 
     // Draw using cached buffers with current timescale transformation
-    if (offscreenGl && this.cachedPositions && this.cachedBaseColors &&
-        this.cachedVariantColors && this.cachedDisabledColors &&
-        this.cachedIndices && this.selectorBuffer && this.cachedRectCount > 0) {
+    if (
+      offscreenGl &&
+      this.cachedPositions &&
+      this.cachedBaseColors &&
+      this.cachedVariantColors &&
+      this.cachedDisabledColors &&
+      this.cachedIndices &&
+      this.selectorBuffer &&
+      this.cachedRectCount > 0
+    ) {
       this.drawWebGLRects(offscreenGl, canvasOffset, timescale, data.start);
     }
   }
 
-  render({
-    ctx,
-    size,
-    timescale,
-  }: TrackRenderContext): void {
+  render({ctx, size, timescale}: TrackRenderContext): void {
     const data = this.fetcher.data;
 
     if (data === undefined) return; // Can't possibly draw anything.
@@ -720,14 +733,20 @@
     gl.shaderSource(vertexShader, vsSource);
     gl.compileShader(vertexShader);
     if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
-      console.error('Vertex shader compilation failed:', gl.getShaderInfoLog(vertexShader));
+      console.error(
+        'Vertex shader compilation failed:',
+        gl.getShaderInfoLog(vertexShader),
+      );
     }
 
     const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)!;
     gl.shaderSource(fragmentShader, fsSource);
     gl.compileShader(fragmentShader);
     if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
-      console.error('Fragment shader compilation failed:', gl.getShaderInfoLog(fragmentShader));
+      console.error(
+        'Fragment shader compilation failed:',
+        gl.getShaderInfoLog(fragmentShader),
+      );
     }
 
     // Create program
@@ -736,20 +755,32 @@
     gl.attachShader(program, fragmentShader);
     gl.linkProgram(program);
     if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
-      console.error('Shader program linking failed:', gl.getProgramInfoLog(program));
+      console.error(
+        'Shader program linking failed:',
+        gl.getProgramInfoLog(program),
+      );
     }
 
     // Get locations
     const positionLocation = gl.getAttribLocation(program, 'a_position');
     const baseColorLocation = gl.getAttribLocation(program, 'a_baseColor');
-    const variantColorLocation = gl.getAttribLocation(program, 'a_variantColor');
-    const disabledColorLocation = gl.getAttribLocation(program, 'a_disabledColor');
+    const variantColorLocation = gl.getAttribLocation(
+      program,
+      'a_variantColor',
+    );
+    const disabledColorLocation = gl.getAttribLocation(
+      program,
+      'a_disabledColor',
+    );
     const selectorLocation = gl.getAttribLocation(program, 'a_selector');
     const resolutionLocation = gl.getUniformLocation(program, 'u_resolution')!;
     const offsetLocation = gl.getUniformLocation(program, 'u_offset')!;
     const dprLocation = gl.getUniformLocation(program, 'u_dpr')!;
     const timeScaleLocation = gl.getUniformLocation(program, 'u_time_scale')!;
-    const timePxOffsetLocation = gl.getUniformLocation(program, 'u_time_px_offset')!;
+    const timePxOffsetLocation = gl.getUniformLocation(
+      program,
+      'u_time_px_offset',
+    )!;
 
     // Cache the program (buffers are per-instance, not cached here)
     cachedGlProgram = {
@@ -843,7 +874,9 @@
     //     u_time_px_offset = pxBounds.left + (dataStart - timeSpan.start) / timePerPx
     //                      = timescale.timeToPx(dataStart)
 
-    const timePerPx = timescale.timeSpan.duration / (timescale.pxBounds.right - timescale.pxBounds.left);
+    const timePerPx =
+      timescale.timeSpan.duration /
+      (timescale.pxBounds.right - timescale.pxBounds.left);
     const timeScale = 1 / timePerPx;
     const timePxOffset = timescale.timeToPx(dataStart);
 
@@ -855,7 +888,8 @@
     gl.uniform1f(timePxOffsetLocation, timePxOffset);
 
     // Only upload static buffers when data has changed
-    const needsStaticUpload = this.buffersUploadedForGeneration !== this.lastDataGeneration;
+    const needsStaticUpload =
+      this.buffersUploadedForGeneration !== this.lastDataGeneration;
 
     gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
     if (needsStaticUpload) {
@@ -880,7 +914,11 @@
 
     gl.bindBuffer(gl.ARRAY_BUFFER, disabledColorBuffer);
     if (needsStaticUpload) {
-      gl.bufferData(gl.ARRAY_BUFFER, this.cachedDisabledColors!, gl.STATIC_DRAW);
+      gl.bufferData(
+        gl.ARRAY_BUFFER,
+        this.cachedDisabledColors!,
+        gl.STATIC_DRAW,
+      );
     }
     gl.enableVertexAttribArray(disabledColorLocation);
     gl.vertexAttribPointer(disabledColorLocation, 4, gl.FLOAT, false, 0, 0);
@@ -896,12 +934,21 @@
 
     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
     if (needsStaticUpload) {
-      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.cachedIndices!, gl.STATIC_DRAW);
+      gl.bufferData(
+        gl.ELEMENT_ARRAY_BUFFER,
+        this.cachedIndices!,
+        gl.STATIC_DRAW,
+      );
       this.buffersUploadedForGeneration = this.lastDataGeneration;
     }
 
     // Draw all rectangles using indexed drawing
-    gl.drawElements(gl.TRIANGLES, this.cachedRectCount * 6, gl.UNSIGNED_SHORT, 0);
+    gl.drawElements(
+      gl.TRIANGLES,
+      this.cachedRectCount * 6,
+      gl.UNSIGNED_SHORT,
+      0,
+    );
   }
 
   onMouseMove({x, y, timescale}: TrackMouseEvent) {
diff --git a/ui/src/plugins/dev.perfetto.Sched/cpu_slice_track.ts b/ui/src/plugins/dev.perfetto.Sched/cpu_slice_track.ts
index 5a3553c..6d9bb40 100644
--- a/ui/src/plugins/dev.perfetto.Sched/cpu_slice_track.ts
+++ b/ui/src/plugins/dev.perfetto.Sched/cpu_slice_track.ts
@@ -60,22 +60,24 @@
 
 // Cached WebGL program state (shared across instances for same GL context)
 // Only program and attribute/uniform locations are shared - buffers are per-instance
-let cachedGlProgram: {
-  gl: WebGL2RenderingContext;
-  program: WebGLProgram;
-  positionLocation: number;
-  baseColorLocation: number;
-  variantColorLocation: number;
-  disabledColorLocation: number;
-  selectorLocation: number;
-  flagsLocation: number;
-  localCoordLocation: number;
-  resolutionLocation: WebGLUniformLocation;
-  offsetLocation: WebGLUniformLocation;
-  dprLocation: WebGLUniformLocation;
-  timeScaleLocation: WebGLUniformLocation;
-  timePxOffsetLocation: WebGLUniformLocation;
-} | undefined;
+let cachedGlProgram:
+  | {
+      gl: WebGL2RenderingContext;
+      program: WebGLProgram;
+      positionLocation: number;
+      baseColorLocation: number;
+      variantColorLocation: number;
+      disabledColorLocation: number;
+      selectorLocation: number;
+      flagsLocation: number;
+      localCoordLocation: number;
+      resolutionLocation: WebGLUniformLocation;
+      offsetLocation: WebGLUniformLocation;
+      dprLocation: WebGLUniformLocation;
+      timeScaleLocation: WebGLUniformLocation;
+      timePxOffsetLocation: WebGLUniformLocation;
+    }
+  | undefined;
 
 interface CpuSliceHover {
   utid: number;
@@ -336,8 +338,9 @@
     // Check if we need to rebuild the vertex buffers (data changed)
     // Include data.start because positions are stored relative to it
     const dataGeneration = numRects + data.lastRowId;
-    const needsRebuild = dataGeneration !== this.lastDataGeneration ||
-                         data.start !== this.lastDataStart;
+    const needsRebuild =
+      dataGeneration !== this.lastDataGeneration ||
+      data.start !== this.lastDataStart;
 
     if (needsRebuild && numRects > 0) {
       // Reset buffer upload tracking - any rebuild needs GPU upload
@@ -402,14 +405,14 @@
         // - localY: 0 at top, RECT_HEIGHT at bottom
         // - leftEdgeTime: t1 (same for all 4 vertices, used to compute localX in shader)
         const localBaseIdx = i * 4 * 2;
-        this.cachedLocalCoords[localBaseIdx + 0] = 0;           // TL: localY
-        this.cachedLocalCoords[localBaseIdx + 1] = t1;          // TL: leftEdgeTime
-        this.cachedLocalCoords[localBaseIdx + 2] = 0;           // TR: localY
-        this.cachedLocalCoords[localBaseIdx + 3] = t1;          // TR: leftEdgeTime
+        this.cachedLocalCoords[localBaseIdx + 0] = 0; // TL: localY
+        this.cachedLocalCoords[localBaseIdx + 1] = t1; // TL: leftEdgeTime
+        this.cachedLocalCoords[localBaseIdx + 2] = 0; // TR: localY
+        this.cachedLocalCoords[localBaseIdx + 3] = t1; // TR: leftEdgeTime
         this.cachedLocalCoords[localBaseIdx + 4] = RECT_HEIGHT; // BL: localY
-        this.cachedLocalCoords[localBaseIdx + 5] = t1;          // BL: leftEdgeTime
+        this.cachedLocalCoords[localBaseIdx + 5] = t1; // BL: leftEdgeTime
         this.cachedLocalCoords[localBaseIdx + 6] = RECT_HEIGHT; // BR: localY
-        this.cachedLocalCoords[localBaseIdx + 7] = t1;          // BR: leftEdgeTime
+        this.cachedLocalCoords[localBaseIdx + 7] = t1; // BR: leftEdgeTime
 
         // Write colors and flags for all 4 vertices
         // RGB values are 0-255 from rgba, normalize to 0-1 for WebGL
@@ -445,11 +448,17 @@
     // Build selector buffer only when hover state changes
     const hoveredUtid = this.trace.timeline.hoveredUtid;
     const hoveredPid = this.trace.timeline.hoveredPid;
-    const hoverChanged = hoveredUtid !== this.lastHoveredUtid ||
-                         hoveredPid !== this.lastHoveredPid ||
-                         needsRebuild;
+    const hoverChanged =
+      hoveredUtid !== this.lastHoveredUtid ||
+      hoveredPid !== this.lastHoveredPid ||
+      needsRebuild;
 
-    if (hoverChanged && this.cachedUtids && this.cachedPids && this.selectorBuffer) {
+    if (
+      hoverChanged &&
+      this.cachedUtids &&
+      this.cachedPids &&
+      this.selectorBuffer
+    ) {
       const isHovering = hoveredUtid !== undefined;
 
       for (let i = 0; i < this.cachedRectCount; i++) {
@@ -459,7 +468,8 @@
         let selector = 0; // base
         if (isHovering) {
           const isThreadHovered = hoveredUtid === utid;
-          const isProcessHovered = hoveredPid !== undefined && pid === hoveredPid;
+          const isProcessHovered =
+            hoveredPid !== undefined && pid === hoveredPid;
           if (!isThreadHovered) {
             selector = isProcessHovered ? 1 : 2;
           }
@@ -477,9 +487,16 @@
     }
 
     // Draw rectangles using WebGL
-    if (offscreenGl && this.cachedPositions && this.cachedBaseColors &&
-        this.cachedVariantColors && this.cachedDisabledColors &&
-        this.cachedIndices && this.selectorBuffer && this.cachedRectCount > 0) {
+    if (
+      offscreenGl &&
+      this.cachedPositions &&
+      this.cachedBaseColors &&
+      this.cachedVariantColors &&
+      this.cachedDisabledColors &&
+      this.cachedIndices &&
+      this.selectorBuffer &&
+      this.cachedRectCount > 0
+    ) {
       this.drawWebGLRects(offscreenGl, canvasOffset, timescale, data.start);
     }
   }
@@ -527,7 +544,10 @@
       let tEnd = Time.fromRaw(data.endQs[i]);
       const utid = data.utids[i];
 
-      if (data.ids[i] === data.lastRowId && data.flags[i] & CPU_SLICE_FLAGS_INCOMPLETE) {
+      if (
+        data.ids[i] === data.lastRowId &&
+        data.flags[i] & CPU_SLICE_FLAGS_INCOMPLETE
+      ) {
         tEnd = endTime;
       }
 
@@ -548,7 +568,9 @@
 
       let textColor: Color;
       if (isHovering && !isThreadHovered) {
-        textColor = isProcessHovered ? colorScheme.textVariant : colorScheme.textDisabled;
+        textColor = isProcessHovered
+          ? colorScheme.textVariant
+          : colorScheme.textDisabled;
       } else {
         textColor = colorScheme.textBase;
       }
@@ -679,14 +701,20 @@
     gl.shaderSource(vertexShader, vsSource);
     gl.compileShader(vertexShader);
     if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
-      console.error('Vertex shader compilation failed:', gl.getShaderInfoLog(vertexShader));
+      console.error(
+        'Vertex shader compilation failed:',
+        gl.getShaderInfoLog(vertexShader),
+      );
     }
 
     const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)!;
     gl.shaderSource(fragmentShader, fsSource);
     gl.compileShader(fragmentShader);
     if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
-      console.error('Fragment shader compilation failed:', gl.getShaderInfoLog(fragmentShader));
+      console.error(
+        'Fragment shader compilation failed:',
+        gl.getShaderInfoLog(fragmentShader),
+      );
     }
 
     const program = gl.createProgram()!;
@@ -694,13 +722,22 @@
     gl.attachShader(program, fragmentShader);
     gl.linkProgram(program);
     if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
-      console.error('Shader program linking failed:', gl.getProgramInfoLog(program));
+      console.error(
+        'Shader program linking failed:',
+        gl.getProgramInfoLog(program),
+      );
     }
 
     const positionLocation = gl.getAttribLocation(program, 'a_position');
     const baseColorLocation = gl.getAttribLocation(program, 'a_baseColor');
-    const variantColorLocation = gl.getAttribLocation(program, 'a_variantColor');
-    const disabledColorLocation = gl.getAttribLocation(program, 'a_disabledColor');
+    const variantColorLocation = gl.getAttribLocation(
+      program,
+      'a_variantColor',
+    );
+    const disabledColorLocation = gl.getAttribLocation(
+      program,
+      'a_disabledColor',
+    );
     const selectorLocation = gl.getAttribLocation(program, 'a_selector');
     const flagsLocation = gl.getAttribLocation(program, 'a_flags');
     const localCoordLocation = gl.getAttribLocation(program, 'a_localCoord');
@@ -708,7 +745,10 @@
     const offsetLocation = gl.getUniformLocation(program, 'u_offset')!;
     const dprLocation = gl.getUniformLocation(program, 'u_dpr')!;
     const timeScaleLocation = gl.getUniformLocation(program, 'u_time_scale')!;
-    const timePxOffsetLocation = gl.getUniformLocation(program, 'u_time_px_offset')!;
+    const timePxOffsetLocation = gl.getUniformLocation(
+      program,
+      'u_time_px_offset',
+    )!;
 
     cachedGlProgram = {
       gl,
@@ -730,7 +770,9 @@
     return cachedGlProgram;
   }
 
-  private ensureBuffers(gl: WebGL2RenderingContext): NonNullable<typeof this.glBuffers> {
+  private ensureBuffers(
+    gl: WebGL2RenderingContext,
+  ): NonNullable<typeof this.glBuffers> {
     if (this.glBuffers?.gl === gl) {
       return this.glBuffers;
     }
@@ -790,7 +832,9 @@
     gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
 
     const dpr = window.devicePixelRatio;
-    const timePerPx = timescale.timeSpan.duration / (timescale.pxBounds.right - timescale.pxBounds.left);
+    const timePerPx =
+      timescale.timeSpan.duration /
+      (timescale.pxBounds.right - timescale.pxBounds.left);
     const timeScale = 1 / timePerPx;
     const timePxOffset = timescale.timeToPx(dataStart);
 
@@ -801,7 +845,8 @@
     gl.uniform1f(timePxOffsetLocation, timePxOffset);
 
     // Only upload static buffers when data has changed
-    const needsStaticUpload = this.buffersUploadedForGeneration !== this.lastDataGeneration;
+    const needsStaticUpload =
+      this.buffersUploadedForGeneration !== this.lastDataGeneration;
 
     gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
     if (needsStaticUpload) {
@@ -826,7 +871,11 @@
 
     gl.bindBuffer(gl.ARRAY_BUFFER, disabledColorBuffer);
     if (needsStaticUpload) {
-      gl.bufferData(gl.ARRAY_BUFFER, this.cachedDisabledColors!, gl.STATIC_DRAW);
+      gl.bufferData(
+        gl.ARRAY_BUFFER,
+        this.cachedDisabledColors!,
+        gl.STATIC_DRAW,
+      );
     }
     gl.enableVertexAttribArray(disabledColorLocation);
     gl.vertexAttribPointer(disabledColorLocation, 4, gl.FLOAT, false, 0, 0);
@@ -858,12 +907,21 @@
 
     gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
     if (needsStaticUpload) {
-      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.cachedIndices!, gl.STATIC_DRAW);
+      gl.bufferData(
+        gl.ELEMENT_ARRAY_BUFFER,
+        this.cachedIndices!,
+        gl.STATIC_DRAW,
+      );
       this.buffersUploadedForGeneration = this.lastDataGeneration;
     }
 
     // Indexed drawing: 6 indices per quad, 4 vertices per quad
-    gl.drawElements(gl.TRIANGLES, this.cachedRectCount * 6, gl.UNSIGNED_SHORT, 0);
+    gl.drawElements(
+      gl.TRIANGLES,
+      this.cachedRectCount * 6,
+      gl.UNSIGNED_SHORT,
+      0,
+    );
   }
 
   onMouseMove({x, y, timescale}: TrackMouseEvent) {
@@ -991,7 +1049,9 @@
 // real-time priorities. The pattern is created once as an offscreen canvas and
 // is kept cached inside the Context2D of the main canvas, without making
 // assumptions on the lifetime of the main canvas.
-export function getHatchedPattern(mainCtx: CanvasRenderingContext2D): CanvasPattern {
+export function getHatchedPattern(
+  mainCtx: CanvasRenderingContext2D,
+): CanvasPattern {
   const mctx = mainCtx as CanvasRenderingContext2D & {
     sliceHatchedPattern?: CanvasPattern;
   };