Skip to main content

performance-profiling

Run the headless app, catalog-load, and ZIP profilers and interpret the JSON the way a human would from window.profiler.report(), profile:load, and the ZIP console table. Use when editing sources/canvas/, load-image, renderer, zip export, zip-helpers, performance-profiler, install-item-metadata, loadAllMetadata, or when the user mentions performance, profiling, slow render, FPS, catalog load, or ZIP export timing.

Quellinformationen

Repository
LiberatedPixelCup/Universal-LPC-Spritesheet-Character-Generator
Letzte Quellaktivität
29. August 2026 um 11:48
Erkannte Sprache von SKILL.md
Englisch
Sterne
1.862
Forks
596

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
performance-profiling
description
Run the headless app, catalog-load, and ZIP profilers and interpret the JSON the way a human would from window.profiler.report(), profile:load, and the ZIP console table. Use when editing sources/canvas/, load-image, renderer, zip export, zip-helpers, performance-profiler, install-item-metadata, loadAllMetadata, or when the user mentions performance, profiling, slow render, FPS, catalog load, or ZIP export timing.
# Performance profiling Do not ask the user to open DevTools. Run the matching script, then read the JSON or the diff. Phase names and console commands: [PERFORMANCE_PROFILING.md](../../../PERFORMANCE_PROFILING.md). ## Which command | What changed | Command | Notes | | --- | --- | --- | | `loadImage()`, `renderCharacter()`, hash hydration, preview, palette recolor | `npm run profile:app` | Live app, `?debug=true`. Default `--recolor both` (WebGL + `?recolor=cpu`). Headless Playwright Chromium is SwiftShader; real GPU: `--headed --channel chrome`. | | `loadAllMetadata`, metadata chunks, catalog bootstrap | `npm run profile:load` | Production `vite preview`, not Vite serve. Median of 5 navigations. Port `4178` (`APP_LOAD_PROFILE_PORT`). | | Generated metadata payload bytes | `npm run metadata:size` / `metadata:size:check` | Generator output, not Vite chunks. CI gates 500 KiB item / 600 KiB pair. | | Drawing, slicing, or PNG encode | `npm run profile:zip:quick` | Fake JSZip. Ignore `generateZip`. | | Real zip packaging (`generateAsync`, `zip-helpers`) | `npm run profile:zip` | Real JSZip. Slower. | These are not interchangeable. Match the command to the change. The ZIP pair is not a substitute for `profile:app`, and `profile:load` is not a substitute for either (Vite serve pretty-prints metadata; `window.profiler` starts after catalog import). Layout shift during load is [cls](../cls/SKILL.md), not a row on this table. **Before any of them:** `npx playwright install` once. ZIP scripts need `dist/*-metadata.js` (`npm run dev` or `npm run build` once) and use `npx serve`. `profile:app` starts Vite serve on `127.0.0.1:5178` (override `APP_PROFILE_PORT`) unless you pass `--url http://127.0.0.1:5173`. `profile:load` runs `vite build` then `vite preview` on `127.0.0.1:4178` unless you pass `--url`. A full ZIP run can take several minutes (up to 10). App profile with both recolor modes is usually 2–4 minutes. `profile:load` is a production build plus five homepage navigations. Request full permissions; Playwright needs a real browser. If `PLAYWRIGHT_BROWSERS_PATH` points at a Cursor sandbox cache, the script unsets it. ## Workflow If the change is **not yet made**, take a baseline first. Use the matching pair (`:quick` with `:quick`, `profile:app` with `profile:app`). ```bash npm run profile:app:baseline # …make the change… npm run profile:app npm run diff:app-profile -- tmp/baseline-app-profile.json tmp/app-profile.json ``` Catalog bootstrap / metadata payload: ```bash npm run profile:load:baseline # …make the change… npm run profile:load npm run diff:app-load-profile -- tmp/baseline-app-load-profile.json tmp/app-load-profile.json ``` A few milliseconds on `indexReadyMs` / `liteReadyMs` is noise; 50 ms+ median is worth a second look (first-paint gates). A 50 ms+ move on `catalogReadyMs` alone can be the credits/palette tail. `diff:app-load-profile` always exits 0. `diff:app-profile` prints **two** sections when both files contain both modes: `======== webgl ========` and `======== cpu ========`. Compare like-with-like. One mode only: `--recolor webgl` or `--recolor cpu`. ```bash npm run profile:zip:baseline:quick npm run profile:zip:quick npm run diff:zip-profile -- tmp/baseline-zip-export-profile-quick.json tmp/zip-export-profile-quick.json ``` If the change is **already made** and `tmp/baseline-*.json` exists from this machine, diff against it. If there is no baseline, report the absolute numbers and flag outliers. Do not invent a baseline after the fact. JSON lands under `tmp/` (gitignored) and is also printed on stdout. ## Interpreting A positive Δ means the after run was slower. Compare on the same machine. A few milliseconds is noise. `renderCharacter` can swing tens of ms between two runs; repeat once if a single Δ is the only evidence. Confirm `activeMode` and `recolorStats` in each section: CPU must show `activeMode: cpu` and `cpu > 0` if the outfit recolours. WebGL should show `webgl > 0` (or `cpu` if this Chromium has no GL). Confirm `renderer` (`unmaskedRenderer`): SwiftShader / llvmpipe is software GL, not the user's GPU. Hardware looks like `ANGLE (Apple, … Metal …)` or an NVIDIA/AMD name. `--headed --channel chrome` fails the run if the renderer is still software. **App profile** (`profiler.snapshot()`, same buckets as `profiler.report()`): - `renderCharacter` — compositing only (not dynamic-import wait) - `snapshot().renderCharacter.calls[]` — per-step `phasesMs` / `counters` for each completed render (`mithrilRedrawStart`, `buildDrawCalls`, `sizeCanvas`, `loadImages`, `recolor`, `draw`, `customLoad`, `customRecolor`, `customDraw`, `mithrilRedrawEnd`) - `image-load:<path>` — one span per network load - `hash-loadSelectionsFromHash` — URL hash hydration - Category totals: `imageLoads`, `draws`, `previews`, `domUpdates` - Slow-operation threshold is 50ms (`slowThresholdMs`) - `diff:app-profile` prints `── renderCharacter phases ──` (call 0 vs call 0, call 1 vs call 1) **Catalog load profile** (`profile:load`, production `vite preview`): - `indexReadyMs` — navigation time origin to `__LPC_waitCatalogIndexReady()` - `liteReadyMs` — navigation time origin to `__LPC_waitCatalogLiteReady()` (hash / `initCanvas` wait on index+lite) - `catalogReadyMs` — navigation time origin to `__LPC_waitCatalogAllReady()` (credits, palette, layers too) - `catalog-load` / `catalog-chunk:*` — User Timing around each metadata import - metadata `*-metadata*` resources — `transferSize`, `decodedBodySize`, `duration` - A few milliseconds is noise; 50 ms+ on `indexReadyMs` or `liteReadyMs` median is worth a second look **ZIP profile** (`phasesMs` / metadata): - `render_imageLoadDecode_*` / `render_composite_*` - `drawAndSlice`, `pngEncode`, `zipFile`, `staticFiles` - `generateZip` — only meaningful on the real-JSZip run The default character is the full outfit in [`zip-profile-default-hash.ts`](../../../scripts/zip/zip-profile-default-hash.ts), not whatever was last open in a browser. `profile:app` then deselects the layered gear (body + head + expression only). Limit one ZIP export: `npm run profile:zip -- --only splitAnimations` (also `splitItemSheets`, `splitItemAnimations`, `individualFrames`). Custom app hashes: `npm run profile:app -- --hash '…' --hash2 '…'`. Real GPU: `npm run profile:app -- --headed --channel chrome` (and the same flags on `profile:app:baseline`). Compare GPU baselines only to GPU runs. ## Still ask the user WebGL vs CPU **visual** correctness is not this skill: [canvas-render](../canvas-render/SKILL.md). Timing both recolor paths is.
Auf GitHub ansehen