Skip to content

perf(rendering): precompute cursor spring for preview/thumbnail - #3225

Merged
richiemcilroy merged 1 commit into
CapSoftware:mainfrom
kyzer1023:perf/cursor-spring-precompute
Oct 25, 2026
Merged

richiemcilroy merged 1 commit into
CapSoftware:mainfrom
kyzer1023:perf/cursor-spring-precompute

Conversation

@kyzer1023

@kyzer1023 kyzer1023 commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

What

Export preview (crates/export/src/preview.rs) and the editor thumbnail (crates/editor/src/thumbnail.rs) now build a PrecomputedCursorTimeline once and pass it to ProjectUniforms::new_with_precomputed_cursor. Playback and main export already did this. Preview and thumbnail were still calling ProjectUniforms::new, which rebuilds the cursor spring on every sample.

PrecomputedCursorTimeline::from_project uses the base cursor spring (tension, mass, friction, click spring). Per-frame style overrides still go through the existing cached_variant path inside new_with_precomputed_cursor. A transition reuses that timeline when both sides are the same recording clip, and builds a second timeline when the outgoing clip is different.

The one-time spring build also interns cursor ids. Each 60 Hz simulation step stores a u32 instead of cloning a String. Interpolation still returns the same cursor id string.

Why

interpolate_cursor_with_click_spring filters, decimates, and runs build_smoothed_timeline on every call. ProjectUniforms::new invokes that closure at least three times per frame (current position, previous position, and tilt) plus click ripples. Preview and thumbnail paid that cost on every frame even though the spring does not depend on the frame.

Bench

From bc-50d9e482 scan #4, three uncached rebuilds versus one indexed build:

Recording Moves 3× uncached rebuild One indexed build
60s 3601 1.11 ms 0.04 ms
10 min — 9.76 ms 0.36 ms
60 min — 58.5 ms 2.38 ms

A local debug check of the same shape (unoptimized; the precomputed side includes the one build plus three lookups) was 4.984 ms → 1.534 ms for 60s/3601 moves, 46.665 ms → 14.694 ms for 10 min, and 274.348 ms → 87.413 ms for 60 min. That run interned the cycling cursor ids down to 3 strings. These debug times are slower than the scan because they include the build and run unoptimized; they confirm the 3× rebuild versus one build ratio.

Overlap

Does not overlap #3144, #3145, #3146, #2980, #2981, #2979, #2809, or #3112. #3112 caches ProjectConfiguration snapshots and is complementary: this change only stops the cursor spring rebuild on the export-preview and thumbnail paths.

Test plan

  • cargo fmt --all
  • cargo clippy -p cap-rendering -p cap-editor -p cap-export --all-features --locked --no-deps -- -D warnings
  • cargo test -p cap-rendering --lib cursor_interpolation::tests — 20 passed, 2 ignored
  • cargo test -p cap-editor --lib thumbnail:: — 4 passed, 1 ignored
  • Export preview of a smoothed cursor, including a cross-clip transition, matches the previous frame
  • Editor thumbnail still writes screenshots/preview.jpg for a project whose cursor smoothing is on

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge; no actionable issues were found.

Summary

Preview and thumbnail rendering now build one cursor spring timeline per rendered frame and reuse it across cursor samples.

  • Preview frames and thumbnails reuse a prepared cursor spring timeline.

Reviews (1) · Last reviewed commit: "perf(rendering): precompute cursor sprin..." · Reviewed by Greptile

Export preview and the editor thumbnail were still calling ProjectUniforms::new, which rebuilt the cursor spring on every sample. Build PrecomputedCursorTimeline once and pass it through, and intern cursor ids during that build.
@vercel

vercel Bot commented Oct 25, 2026

Copy link
Copy Markdown
Contributor

@kyzer1023 is attempting to deploy a commit to the Cap Software Inc Team on Vercel.

A member of the Team first needs to authorize it.

@kyzer1023

Copy link
Copy Markdown
Contributor Author

@greptileai review

@richiemcilroy
richiemcilroy merged commit 2bb5963 into CapSoftware:main Oct 25, 2026
48 of 50 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants