GSAP timelines: animation as data
GoByte Skills #19: a GSAP timeline is a seekable program. Every value is a function of the playhead, so you can scrub, reverse and test any frame in plain Node. Plus the three ways it quietly stops being pure.
Arthur is one of GoByte's characters. This post was drafted by AI agents in Arthur's voice, then fact checked, run and edited by the GoByte team.
A timeline is a seekable program, so you can scrub, reverse and render any frame, which is what makes animation testable.
Transcript
A playhead scrubs a two tween timeline forward and back while the box it drives always lands at the value the code predicts, because every frame is a function of time.
const { gsap } = require("gsap");
gsap.defaults({ ease: "none", duration: 1 });
const box = { x: 0 };
const tl = gsap.timeline({ paused: true });
tl.to(box, { x: 100 }).to(box, { x: 0 });
console.log(tl.duration()); // 2
tl.seek(0.5);
console.log(box.x); // 50
tl.progress(0.75);
console.log(box.x); // 50
tl.seek(1.9).seek(0.25);
console.log(box.x); // 25
No DOM, no clock, no waiting for frames. GSAP tweens any numeric property of any object, so this runs in plain Node.
Why it works#
A timeline is a tree of tweens, each with a start time and a duration. Put the playhead at t and every child gets a local time, t - start, clamped to its duration. Each tween then writes from + (to - from) * ease(local / duration) (repeat and yoyo only fold the local time first). Every value is a function of the playhead, not of the frames that came before. Jump from 1.9 back to 0.25 and you get exactly what straight playback shows at 0.25. Playing is just a ticker calling that same render with the wall clock.
What that buys you#
A unit test that asserts a value at a time. Scrubbing with a slider or the scroll position. A renderer that seeks frame by frame and screenshots each one, which is how the clip on this post was made, identically on every run.
Where it breaks#
- Start values are recorded lazily, on a tween's first render. Set
box.x = 500before the first seek andseek(0.5)gives 300: the tween starts from whatever it finds. - Callbacks: in GSAP 3,
seek()suppresses them by default, whiletime()andprogress()fire the ones they pass over. Same playhead, different side effects. - Anything outside the timeline is not seekable. One
setTimeoutorMath.random()in anonUpdate, and the frame at 3.2 s depends on how you got there.
Rule of thumb#
Hang every moving thing off one timeline and the animation becomes a pure function of time, testable like any other. Skip it and your test plan is "watch it a few times and squint".
Your product here? Partner with us
Back to topDiscussion
No comments yet. Signed in GoByte members with a verified e-mail can join. Community guidelines
Reading is open to everyone. Commenting and voting need a GoByte account with a verified e-mail.