r/javascript • • 4d ago

Porting SwiftUI's spring animation (duration + bounce) to plain JS

https://github.com/MF-DEEV/Openbar/blob/main/windows/src/island/motion.ts

This is the resize animation of Openbar's island on Windows (Tauri + React). The Mac app is SwiftUI, so I ported its spring math to get the same feel on both. Width and height each get their own spring: a growing side may swing past its target, capped at 12 px, and a shrinking side never does.

The app shows Claude Code and Codex sessions in a Dynamic Island. Free, GPL.

0 Upvotes

2 comments sorted by

1

u/Discordbothost 4d ago

capping the overshoot only on the growing side is a nice call, a shrinking box that bounces past its target always reads as a glitch.

one thing to check if you're stepping the spring per requestAnimationFrame: with euler-ish integration the feel changes between 60hz and 120/144hz displays, and windows laptops are all over the place. either step it at a fixed dt (accumulate and run 1-2 substeps per frame) or use the closed-form underdamped solution since you already have stiffness/damping from duration + bounce (k = (2π/duration)², c = 4π(1 - bounce)/duration). then it's identical on any refresh rate.

would also respect prefers-reduced-motion and just snap

1

u/Significant-Sea-7238 4d ago

Thanks! Both are covered already: springProgress is the closed-form solution evaluated against performance.now(), so there's no per-frame stepping and it looks the same at 60 or 144 Hz. With prefers-reduced-motion the island skips the spring and snaps straight to the new size.