perf(tooling): add an animation cost profiler and document the harness
Adds `bun run profile:animation`: it serves an isolated fixture and measures each animation variant directly, so comparing techniques takes seconds instead of an application rebuild plus a streamed response. The result is unambiguous and does not vary with element count, measured from 1 to 32: transform, opacity and filter cost zero extra style recalculations, while the individual rotate property, background-position, border-color and box-shadow each recalculate style 60 times a second, and geometry properties add layout on top. Notably `rotate: 360deg` is not a cheap synonym for `transform: rotate(360deg)`, and will-change, wrapper elements, containment and stepped timing do not make a non-composited property cheap. `scripts/perf/DOCUMENTATION.md` documents all four capture commands, how to stand up a production build to measure against, how to read the artifacts, the validity guarantees the scripts enforce, and the methodology rules, so this can be handed to an agent as the entry point for measuring performance. It is linked from the root guide's documentation anchors. The theme skill gains an animation contract carrying the measured table, and the performance skill points at the tooling documentation.
This commit is contained in:
@@ -197,13 +197,19 @@ A cache inside an `O(consumers × entities × candidates)` loop is a mitigation,
|
||||
|
||||
## Repository Tooling
|
||||
|
||||
Three unattended capture commands exist; prefer them over ad-hoc timing code,
|
||||
`scripts/perf/DOCUMENTATION.md` is the entry point: it covers every capture
|
||||
command, how to stand up a production build to measure against, how to read the
|
||||
artifacts, and the validity guarantees these scripts enforce. Read it before
|
||||
measuring.
|
||||
|
||||
Four unattended capture commands exist; prefer them over ad-hoc timing code,
|
||||
and extend them when a scenario is missing rather than measuring by hand.
|
||||
|
||||
| Command | Answers |
|
||||
|---|---|
|
||||
| `bun run profile:idle` | What the app does while nobody interacts with it. Supports `--session`, `--tab`, `--then-tab`, `--panel`, `--expand-projects` to reach a specific mounted state, plus `--baseline` and `--budget-*` for regression gating. |
|
||||
| `bun run profile:session` | What a streaming assistant response costs. Creates a session, dispatches a prompt through the `openchamber session` CLI, and records until the session reports idle. Reports the long-task distribution, a timeline-trace breakdown, running animations, and output-normalised metrics. |
|
||||
| `bun run profile:animation` | What a CSS animation costs, isolated from the app. Animate only `transform` and `opacity`; everything else recalculates style every frame. |
|
||||
| `bun run profile:browser` | A manually driven capture when the interaction cannot be scripted. |
|
||||
|
||||
Both automated commands fail loudly rather than reporting a clean result when
|
||||
|
||||
@@ -71,8 +71,34 @@ import { Icon } from '@/components/icon/Icon';
|
||||
|
||||
Use `IconName` for icon values stored in arrays, objects, state, or config. `Icon` has no `size` prop. Run `bun run icons:generate` when introducing a sprite name, and never edit `sprite.ts` manually. Load `references/icons.md` for the complete workflow.
|
||||
|
||||
## Animation Contract
|
||||
|
||||
Animate only `transform` and `opacity`. The compositor drives those; every other
|
||||
property recalculates style on each frame for as long as the animation runs, and
|
||||
geometry properties add layout on top. Measured on this repository's fixture,
|
||||
identical at any element count from 1 to 32:
|
||||
|
||||
| Animated property | Style recalculations/sec | Layouts/sec |
|
||||
|---|---|---|
|
||||
| `transform`, `opacity`, `filter` | 0 | 0 |
|
||||
| `rotate` (the individual property) | 60 | 0 |
|
||||
| `background-position`, `border-color`, `box-shadow` | 60 | 0 |
|
||||
| `width` and other geometry | 60 | 60 |
|
||||
|
||||
- `rotate: 360deg` is not a cheap synonym for `transform: rotate(360deg)`.
|
||||
Prefer the `transform` form.
|
||||
- Cost applies for the entire time an animation runs, so an indicator tied to a
|
||||
long-running operation pays it continuously. An indicator that is not
|
||||
conveying anything should not be animating.
|
||||
- `will-change`, wrapper elements, `contain`, and `steps()` timing do not make a
|
||||
non-composited property cheap. Only changing the property does.
|
||||
- Verify with `bun run profile:animation` rather than reasoning about it; add a
|
||||
variant to `scripts/perf/animation-fixture.html` for a technique not covered.
|
||||
See `scripts/perf/DOCUMENTATION.md`.
|
||||
|
||||
## Verification
|
||||
|
||||
- Animations are limited to `transform` and `opacity`, or their cost was measured and accepted.
|
||||
- No hardcoded/palette colors were introduced.
|
||||
- Buttons use shared variants and sizes.
|
||||
- Icons use `Icon`/`IconName`, and generated sprite changes are intentional.
|
||||
|
||||
Reference in New Issue
Block a user