Skip to content
Back to skills

Spa Performance

ASecurity

Use when an SPA is slow because of the main thread, frame time, or memory: Web Workers, OffscreenCanvas, scheduler.yield, virtualized or windowed rendering, canvas and DOM editors, image swaps, flicker, blank frames, live updates, or a performance harness. Not React re-renders, bundles, or Server Components (see react-performance).

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 11, 2026
developmentreacttestingperformance

Security analysis

A100/100

Pro scans all 11 files and shows the line behind each finding

Scanned November 11, 2026

npx -y skills add LeahyCC/claude-skills --skill spa-performance --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Spa Performance?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Spa Performance
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/leahycc-spa-performance/badge)](https://www.skillsdirectory.com/skills/leahycc-spa-performance)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: spa-performance
description: >
  Use when an SPA is slow because of the main thread, frame time, or memory:
  Web Workers, OffscreenCanvas, scheduler.yield, virtualized or windowed
  rendering, canvas and DOM editors, image swaps, flicker, blank frames,
  live updates, or a performance harness.
  Not React re-renders, bundles, or Server Components (see react-performance).
---

# SPA performance

Browser performance for a single-page app: what runs on the main thread, what is worth drawing, and how to prove a change helped. Framework rendering, bundle size, and Server Components belong to the `react-performance` skill.

**Measure the moment the user feels, then change one thing.** A faster load that stalls the gesture is a loss. Measure that change alone and again with the rest of the system. Thresholds, the harness, and the worked example live in [measure.md](./resources/measure.md).

Source checks and what is still open: [SOURCES.md](SOURCES.md).

## Procedure

1. Name the moment: first paint of a thing, a gesture (pan, scroll, drag), a keystroke, or a tick of live data.
2. Read the one resource for that moment before choosing a technique. If its first line says `Status: open` or `Status: partial`, apply the written rules and do not invent the items under its Fill in list.
3. Record a baseline with the harness in [measure.md](./resources/measure.md). DevTools finds the cause. The quoted number comes from a rerun with DevTools closed.
4. Classify the cost and change the smallest thing that attacks it.

```
name the moment
        |
        v
too much work? ----yes----> draw less (window, rough pass, release, cancel)
        |
        no
        v
long task on the main thread?
        |
        +-- touches DOM or layout --------> yield
        +-- CPU only, no DOM -------------> worker, transfer the bytes
        +-- the draw itself is the freeze -> OffscreenCanvas in that worker
        +-- deadline is not a frame ------> audio and video
        |
        v
you already own a GPU renderer, and submission or compute is the wall
        |
        v
WebGPU, with a WebGL2 fallback
```

5. Measure the change alone, then with the other changes. Publish cold and warm separately.

A hosted editor (tldraw, and the same class of canvas) shares the main thread with the app. Read [hosted-editor.md](./resources/hosted-editor.md) before optimizing around it. A worker can take your pixels. It cannot take the host's hit testing.

## Where to read

| Moment | Resource | Status |
| --- | --- | --- |
| Prove a before and after | [measure.md](./resources/measure.md) | written |
| Lists, pages, maps, charts: draw less | [draw-less.md](./resources/draw-less.md) | written |
| Yield, worker, OffscreenCanvas, WebGPU | [off-thread.md](./resources/off-thread.md) | written |
| tldraw and other hosted editors | [hosted-editor.md](./resources/hosted-editor.md) | written |
| Code, docs, chat: the keystroke | [typing.md](./resources/typing.md) | written |
| Sheets and grids: rows and columns | [grids.md](./resources/grids.md) | written |
| Logs, prices, live dashboards | [streams.md](./resources/streams.md) | written |
| Audio and video deadlines | [audio-video.md](./resources/audio-video.md) | written |

Maps, large images, and chart series are [draw-less.md](./resources/draw-less.md): tiles, and one sample per screen pixel. An `<img>` swap that blanks the old picture is in that file too.

## Review checklist

- [ ] The moment is named, and the number is from a scripted rerun, not a single hand gesture
- [ ] Cold and warm are separate, and the previous run cannot write the next run's result
- [ ] Frame numbers are headed, with window size and device pixel ratio written down
- [ ] The gesture was run at 1x and at 2x, and the note says which bottleneck each showed ([measure.md](./resources/measure.md))
- [ ] A long frame has a trace, self time by event name, before any fix ([measure.md](./resources/measure.md))
- [ ] Memory is the store that actually holds the bytes, not only the JS heap
- [ ] A switch that wins on load was also timed on the gesture
- [ ] Hit testing and geometry follow the host's record, not live zoom read during render
- [ ] The character just typed is painted before any worker or full-buffer analysis returns
- [ ] In-flight work is cancelled when it leaves the window
- [ ] The quoted build is production, and the measuring UI was closed or its cost stated

Files in this skill

  • README.md2.5 KB
  • SKILL.md4.3 KB
  • SOURCES.md8.3 KB
  • resources/audio-video.md15.3 KB
  • resources/draw-less.md8.8 KB
  • resources/grids.md15.6 KB
  • resources/hosted-editor.md4.4 KB
  • resources/measure.md14.7 KB
  • resources/off-thread.md5.5 KB
  • resources/streams.md15.6 KB
  • resources/typing.md11.9 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

View all in development →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.