85453da49f
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
Docs / Validate docs (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Sync skills to ClawHub / Publish changed skills (push) Waiting to run
regression / regression-shards (style-16-prod style-9-prod style-17-prod iframe-render-compat variables-prod mp4-h265-sdr, shard-4) (push) Has been cancelled
regression / regression-shards (style-4-prod style-11-prod style-2-prod animejs-adapter typegpu-adapter parallel-capture-regression, shard-5) (push) Has been cancelled
regression / regression-shards (style-7-prod style-8-prod style-10-prod css-spinner-render-compat webm-transparency mp4-h264-sdr webm-vp9, shard-3) (push) Has been cancelled
regression / regression-shards (sub-composition-video style-18-prod raf-ball-render-compat font-variant-numeric sub-comp-t0 sub-comp-id-selector, shard-7) (push) Has been cancelled
Windows render verification / Detect changes (push) Has been cancelled
Windows render verification / Preflight (lint + format) (push) Has been cancelled
Windows render verification / Render on windows-latest (push) Has been cancelled
Windows render verification / Tests on windows-latest (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Fallow audit (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Producer: integration tests (push) Has been cancelled
CI / Producer: unit tests (push) Has been cancelled
CI / File size check (push) Has been cancelled
CI / Test: skills (push) Has been cancelled
CI / Skills: manifest in sync (push) Has been cancelled
CI / CLI: npx shim (macos-latest) (push) Has been cancelled
CI / CLI: npx shim (ubuntu-latest) (push) Has been cancelled
CI / CLI: npx shim (windows-latest) (push) Has been cancelled
CI / SDK: unit + contract + smoke (push) Has been cancelled
CI / Test: runtime contract (push) Has been cancelled
CI / Studio: load smoke (push) Has been cancelled
CI / Smoke: global install (push) Has been cancelled
CI / CLI smoke (required) (push) Has been cancelled
CI / Semantic PR title (push) Has been cancelled
Player perf / Detect changes (push) Has been cancelled
Player perf / Preflight (lint + format) (push) Has been cancelled
Player perf / player-perf (push) Has been cancelled
Player perf / Perf: drift (push) Has been cancelled
Player perf / Perf: fps (push) Has been cancelled
Player perf / Perf: parity (push) Has been cancelled
Player perf / Perf: scrub (push) Has been cancelled
Player perf / Perf: load (push) Has been cancelled
preview-regression / Detect changes (push) Has been cancelled
preview-regression / Preflight (lint + format) (push) Has been cancelled
preview-regression / Preview parity (push) Has been cancelled
preview-regression / preview-regression (push) Has been cancelled
regression / regression (push) Has been cancelled
regression / Detect changes (push) Has been cancelled
regression / Preflight (lint + format) (push) Has been cancelled
regression / regression-shards (hdr-regression style-5-prod style-3-prod mov-prores, shard-1) (push) Has been cancelled
regression / regression-shards (overlay-montage-prod style-12-prod chat missing-host-comp-id png-sequence portrait-edge-bleed, shard-6) (push) Has been cancelled
regression / regression-shards (style-13-prod style-6-prod vignelli-stacking gsap-letters-render-compat audio-mux-parity, shard-8) (push) Has been cancelled
regression / regression-shards (style-15-prod hdr-hlg-regression style-1-prod many-cuts vfr-screen-recording render-symlinked-assets, shard-2) (push) Has been cancelled
140 lines
6.2 KiB
Plaintext
140 lines
6.2 KiB
Plaintext
---
|
||
title: Performance
|
||
description: "How to keep preview playback smooth and diagnose expensive compositions."
|
||
---
|
||
|
||
Preview plays your composition in real time, so any frame that takes longer than 33ms (at 30fps) shows up as stutter. This page covers the patterns that blow that budget and how to spot them.
|
||
|
||
## Preview vs. render
|
||
|
||
Render captures frames one at a time and stitches them into a video. Slow frames make the render take longer, but you never see the pauses — you watch the finished mp4.
|
||
|
||
Preview does the same work in real time. If a frame takes 200ms to paint, you see a 200ms freeze.
|
||
|
||
This is why "render looks fine, preview stutters" is expected for paint-heavy compositions. It doesn't mean preview is broken — it means individual frames are too expensive for real-time playback.
|
||
|
||
## Expensive CSS patterns
|
||
|
||
These are the patterns that most often cause preview to drop below 30fps.
|
||
|
||
### backdrop-filter: blur()
|
||
|
||
Each `backdrop-filter: blur(radius)` sampled over a large area forces the compositor to read pixels from behind the element, run a blur kernel across them, and composite the result. Cost scales with both the blurred area and the radius.
|
||
|
||
Stacked blur layers multiply the cost. Eight layers at progressively larger radii (1, 2, 4, 8, 16, 32, 64, 128px) will happily take 200ms per frame over a 1920x1080 region on mid-tier GPUs.
|
||
|
||
**What to do:**
|
||
- Keep stacked layers to 2-3 maximum, with manually tuned radii
|
||
- Avoid `blur(128px)` or `blur(64px)` over large areas — the biggest radii dominate the cost
|
||
- For a static blur, render it once into a PNG and use a regular `<img>` overlay
|
||
|
||
### filter: blur() and filter: drop-shadow()
|
||
|
||
Same story as `backdrop-filter` but applied to the element itself rather than behind it. Fine on small elements, expensive on large ones.
|
||
|
||
### Shadows on many elements
|
||
|
||
`box-shadow` and `text-shadow` on a few elements are fine. On dozens of elements that also animate, the compositor re-rasterizes each shadowed layer on every frame.
|
||
|
||
### Large gradients with mask-image
|
||
|
||
Combined with `backdrop-filter`, `mask-image` can force additional compositor passes. If you have both on the same element, consider whether you need both.
|
||
|
||
## Image sizing
|
||
|
||
Image source resolution matters more than file size. Chrome decodes JPEGs and PNGs to raw RGBA bitmaps before displaying them — a decoded bitmap is:
|
||
|
||
```
|
||
bitmap_bytes = width × height × 4
|
||
```
|
||
|
||
A 7000×5000 source image is 140MB decoded, regardless of whether the JPEG on disk is 2MB or 5MB.
|
||
|
||
**Rule of thumb:** resize source images to at most 2x the canvas dimensions. For a 1920x1080 canvas, 3840x2160 source images are already overkill. Anything above that is paying for memory and texture-upload cost that never shows on screen.
|
||
|
||
```bash Terminal
|
||
# ImageMagick one-liner to downsize a directory of images
|
||
mogrify -path resized -resize 3840x3840\> *.jpg
|
||
```
|
||
|
||
## Measuring a slow composition
|
||
|
||
Don't guess — measure. Chrome DevTools has everything you need.
|
||
|
||
<Steps>
|
||
<Step title="Run preview">
|
||
Start the preview server and open it in Chrome:
|
||
|
||
```bash Terminal
|
||
npx hyperframes preview
|
||
```
|
||
</Step>
|
||
<Step title="Open DevTools → Performance">
|
||
`Cmd+Option+I` (macOS) or `Ctrl+Shift+I` (Linux/Windows), then switch to the **Performance** tab.
|
||
</Step>
|
||
<Step title="Record during playback">
|
||
Hit the record button, click play in the preview, let it run 3-5 seconds through the jank-prone scene, then stop recording.
|
||
</Step>
|
||
<Step title="Read the main thread track">
|
||
Look for long tasks (red-flagged in the timeline). Expand the tallest bars and check what Chrome labels them:
|
||
|
||
- **Composite Layers / Paint** with a large duration = compositor cost (backdrop-filter, shadows, large textures)
|
||
- **Decode Image** = image decode on first paint (rare in Chrome 131+, images decode off-thread by default)
|
||
- **Layout / Recalculate Style** = layout thrashing from script
|
||
- **Script** = JS work (rare for compositions, check author scripts)
|
||
</Step>
|
||
</Steps>
|
||
|
||
Once you know which category dominates, you know what to change.
|
||
|
||
<Tip>
|
||
A composition that runs at 60fps in isolation but stutters only during specific scenes is usually a composite-cost problem. Check which layers become visible during those scenes.
|
||
</Tip>
|
||
|
||
## When preview is unavoidable slow
|
||
|
||
Some compositions are legitimately too expensive for real-time playback. If you've reduced what you can and preview still stutters, render-to-mp4 and watch the output is a fine workflow — render is still accurate.
|
||
|
||
```bash Terminal
|
||
npx hyperframes render --quality draft --output preview.mp4
|
||
```
|
||
|
||
Draft quality renders fast and is visually close to the final render for everything except encoder-level detail.
|
||
|
||
## WebM encode speed
|
||
|
||
Transparent WebM output uses FFmpeg's `libvpx-vp9` encoder. VP9 is CPU-heavy, so short overlay renders can spend most of their wall time in the encode stage even when frame capture is fast.
|
||
|
||
HyperFrames sets `-cpu-used 4` for VP9 by default. On a devbox check using an 8s 1280×720, 15fps VP9-alpha encode, explicit `-cpu-used 4` cut encode time from 6.3s to 2.6s versus libvpx's default, with SSIM 0.9986 and PSNR 50.5dB against the default encode. Your composition and host CPU will move those numbers, but the direction is consistent: higher values trade some compression efficiency for faster WebM encodes.
|
||
|
||
Tune per deployment with:
|
||
|
||
```bash Terminal
|
||
PRODUCER_VP9_CPU_USED=2 npx hyperframes render --format webm --output overlay.webm
|
||
```
|
||
|
||
For one-off local renders, pass the same value directly:
|
||
|
||
```bash Terminal
|
||
npx hyperframes render --format webm --vp9-cpu-used 2 --output overlay.webm
|
||
```
|
||
|
||
Valid values are integers from `-8` to `8`; HyperFrames clamps out-of-range values before passing them to FFmpeg.
|
||
|
||
## Next Steps
|
||
|
||
<CardGroup cols={2}>
|
||
<Card title="Troubleshooting" icon="wrench" href="/guides/troubleshooting">
|
||
Environment, tooling, and rendering issues
|
||
</Card>
|
||
<Card title="Common Mistakes" icon="triangle-exclamation" href="/guides/common-mistakes">
|
||
Composition pitfalls that break rendering
|
||
</Card>
|
||
<Card title="Rendering" icon="film" href="/guides/rendering">
|
||
Rendering modes, options, and flags
|
||
</Card>
|
||
<Card title="CLI Reference" icon="terminal" href="/packages/cli">
|
||
Full list of CLI commands
|
||
</Card>
|
||
</CardGroup>
|