perf

Installation
SKILL.md

Interface Performance

Fast UI is mostly work you do not do. Do not render nodes nobody can see, do not ask the browser to watch properties that never change, do not animate anything the compositor cannot own, do not fetch at request time what you could build once, and do not move the layout after the user has started reading it. Almost all jank is self-inflicted, and the fix is almost always deleting or deferring work rather than adding cleverness. This skill is entered by a measurement, not by a feeling: if a stopwatch, a profile or a Web Vitals number says it is slow, you are in the right place — if it merely feels wrong, the duration and the easing are motion's to fix and nothing here will help. Never optimise before profiling the actual device.

Adopt the project's existing performance tooling before adding any. If it already has a virtualizer, an image component, a bundle analyzer or a Vitals reporter, use that one — a second virtualization library is worse than an unvirtualized list, because now two things measure the same rows. Check the styling system too: a Tailwind project needs the arbitrary-value transition form, not a hand-written stylesheet beside it. If the framework ships a route-level image or font primitive, it already handles preloading, sizing and format negotiation better than a hand-rolled <img>.

Topic Reference
A number to hold the work to Open references/budgets.md when you need the target to measure against — frame time, Web Vitals thresholds, list sizes, image and bundle weights.
A symptom with no obvious cause Open references/diagnosis.md when something janks and you do not yet know why — it maps each symptom to the panel, the setting, and what the trace looks like when you have found it.

Core Principles

  1. Name the properties that transition; never transition: all. With all, every style change becomes a candidate animation — the browser tracks the whole style object, properties you never meant to tween start tweening, and the engine loses the optimisations a narrow, known list allows. Write transition-property: transform, opacity. Tailwind's bare transition compiles to transition-property: all; use transition-transform or transition-[opacity,filter]. Exception: none — a Tier 0 prohibition; the shorthand's convenience never covers its cost.

  2. Animate only what the compositor owns. transform, opacity, filter and clip-path skip layout and paint. Animating height, width, padding, margin, top or left runs the full pipeline on every frame. Expand panels with transform: scaleY() or a clip, or measure once and animate the transform. Exception: filter: blur() is compositor-owned but genuinely expensive — keep it under 20px and off frequently-animating elements, especially in Safari.

  3. Reserve will-change for a stutter you have observed. The browser creates the compositor layer when motion begins, and that just-in-time promotion occasionally eats the opening frame; will-change: transform requests it up front and fixes exactly that. It does nothing for paint- or layout-bound properties, and each layer holds real GPU memory. Exception: remove it after the animation on any element that exists in quantity — 200 permanently promoted rows cost more than the hitch they prevented.

Installs
3
Repository
agentsorg/benji
GitHub Stars
1
First Seen
Aug 2, 2026
perf — agentsorg/benji