Skip to content

fix: replace GSAP tweens with WAAPI for mobile perf#15

Closed
fedgaltc-code wants to merge 1 commit intoFedG-code:masterfrom
fedgaltc-code:fix/waapi-scatter-reform
Closed

fix: replace GSAP tweens with WAAPI for mobile perf#15
fedgaltc-code wants to merge 1 commit intoFedG-code:masterfrom
fedgaltc-code:fix/waapi-scatter-reform

Conversation

@fedgaltc-code
Copy link
Copy Markdown

Summary

Improves on PR #14 by finding and fixing the actual mobile performance bottleneck instead of downgrading the visual effect.

Root cause: Physics2DPlugin runs per-char physics calculations every frame on the JS main thread, and GSAP stagger creates N individual child tweens per reform batch. With 6 concurrent batches of ~15 chars each, GSAP's ticker updates ~360 tweens per frame — this is the core mobile lag.

Fix: Replace all per-element GSAP animations with Web Animations API (WAAPI), which runs entirely on the browser's compositor thread — zero per-frame JS cost.

  • Scatter: Pre-compute parabolic trajectories from the same physics equations Physics2DPlugin solves per-frame, sampled into 4 WAAPI keyframes per char
  • Color flash: el.animate() instead of gsap.fromTo()
  • Reform: WAAPI with fill:'backwards' (applies first keyframe during stagger delay, self-expires after finishing — no getAnimations() cancel needed)
  • will-change: transform, opacity promotes chars to GPU compositor layers
  • MAX_ACTIVE_BATCHES raised from 6→20 (WAAPI is cheap, so fewer impacts are dropped)

Results (iPhone 14 emulated, 4x CPU throttle)

Scenario Metric PR #14 threshold This PR
scatter_spike ScriptDurationMs 57ms
dense_burst ScriptDurationMs 1200ms 23ms (98% ↓)
sustained_annihilation ScriptDurationMs 2200ms 119ms (95% ↓)
sustained_annihilation overlap maxFrameMs 100ms 44ms (56% ↓)

0 perf test flags (vs PR #14 needing to raise thresholds to pass).

Test plan

  • node tests/perf-test-destruction.js — 0 flags, all thresholds pass
  • Manual test on a real mobile device: enable plane mode, fire at text, verify scatter arcs look natural and reform is smooth
  • Theme switch during active destruction — verify clean reset
  • Rapid sustained firing — verify pressure monitor still drops impacts gracefully at extreme load

🤖 Generated with Claude Code

Root cause: Physics2DPlugin ran per-char physics calculations every frame
on the JS main thread, and GSAP stagger created N individual child tweens
per reform batch. With 6 concurrent batches of ~15 chars each, that's
~360 tweens ticking every frame — the actual mobile bottleneck.

Changes:
- Scatter: pre-compute parabolic trajectories from same physics equations
  Physics2DPlugin uses, sample into 4 WAAPI keyframes per char
- Color flash: WAAPI animate() instead of gsap.fromTo()
- Reform: WAAPI with fill:'backwards' (self-expiring, no cancel needed)
- will-change:transform,opacity promotes chars to compositor layers
- MAX_ACTIVE_BATCHES raised from 6 to 20 (WAAPI is compositor-driven)

Result: ScriptDurationMs reduced 95-97% in heavy scenarios. All perf
test thresholds pass (0 flags).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@FedG-code
Copy link
Copy Markdown
Owner

@claude what do you think about this? Isn't this a bit too far removed by getting rid of GSAP completely?

@claude
Copy link
Copy Markdown

claude bot commented Apr 3, 2026

Claude Code is working…

I'll analyze this and get back to you.

View job run

@FedG-code FedG-code closed this Apr 7, 2026
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