ClaudeAI posts animated clips of their mascot on social media. Quick loops of their pixel mascot strolling round and looking out, waving a flag, understanding, stomping with confetti. The timing has character. The movement has weight. I simply wished to take them aside.
I slowed the clips to 0.3x, captured screenshots of each body, illustrated the mascot, and rebuilt 4 animations from scratch in about 4 days. No video recordsdata, no GIFs. Simply SVG, GSAP, and React. The objective was a precise reproduction, each timing, each easing, and each body matching the unique.
This can be a breakdown of how I approached each, the challenges I bumped into, and the way I pulled it off. You possibly can take a look on the working examples right here.
Instruments
The mascot is constructed totally from <rect> parts, no paths, no curves. Simply rectangles organized into a personality. GSAP powers every part: gsap.to() for steady tweened movement, gsap.set() for fast body swaps, and gsap.timeline() to orchestrate sequences. Some animations are pure tweening. Others are frame-by-frame sprite sheets the place every body has its personal maintain time and sure sections of the sequence replay earlier than persevering with. One is a hybrid of each. React handles the part construction and refs.
Strolling Claude
Strolling Claude is essentially the most advanced of the 4. The mascot seems to be round, jumps, walks throughout the display, seems to be down, crouches, and leaps to the opposite facet. It’s the one animation pushed totally by steady GSAP tweens.
The Clip Masks
The primary drawback I bumped into was the legs. When Claude leans to go searching, the legs tilt and stretch utilizing rotation and scaleY. That’s what offers the lean its weight. The legs are bending into the bottom like they’re truly supporting the physique. However stretching a rectangle doesn’t care about the place the ground is. And not using a boundary, the legs push proper by way of.
The repair is a <clipPath> wrapping the legs and reducing off something that extends previous the bottom. Easy, nevertheless it’s the sort of element that makes the distinction between an animation that feels proper and one which feels off.
<defs>
<clipPath id="ground-clip">
<rect x="-20" y="-50" width="160" peak="136" />
</clipPath>
</defs>
<g clipPath="url(#ground-clip)">
<rect id="leg4" x="85" y="60" width="11" peak="26" fill="#DD775B" />
<rect id="leg3" x="64" y="60" width="11" peak="26" fill="#DD775B" />
<rect id="leg2" x="32" y="60" width="11" peak="26" fill="#DD775B" />
<rect id="leg1" x="11" y="60" width="11" peak="26" fill="#DD775B" />
</g>
The lean. Getting the lean proper was largely about timing. GSAP’s "<" operator can sync a number of tweens to fireside on the similar time, so the eyes, physique, and legs all transfer collectively in a single beat. The physique tilts, the eyes shift, and the legs stretch all of sudden, all with the identical easing. That’s what makes it really feel like one movement as a substitute of three issues occurring individually.
tl.to(eyesRef.present, { x: -3, length: 0.4, ease: "power2.out" })
.to(bodyRef.present, { rotation: -3, x: -3, y: -5,
svgOrigin: "53 65", length: 0.4, ease: "power2.out" }, "<")
.to(legs, {
rotation: (i) => [-7, -8, -8, -9][i],
scaleY: (i) => [1.35, 1.3, 1.2, 1.15][i],
length: 0.4, ease: "power2.out"
}, "<")
Every leg will get its personal rotation and stretch worth; those nearer to the lean route bend extra. When it got here to the stroll, the legs wanted to pivot from the hip as a substitute of the ft. A .name() mid-timeline switches the svgOrigin earlier than the stroll begins, then switches again after. Similar legs, totally different anchor level, utterly totally different movement.
The Bounce
The soar was the half the place I went again to my screenshots. Claude crouches, launches throughout the display in an arc, and bounces on touchdown. Getting the physique, palms, and legs to all do the suitable factor on the proper time meant finding out the unique body by body.
The crouch is fast, the physique dips down and the palms drop with it, all in 0.1 seconds. That snap is what offers the “gathering momentum” really feel earlier than takeoff.
.to(bodyRef.present, { y: 8, length: 0.1, ease: "power3.in" })
.to([leftHandRef.current, rightHandRef.current],
{ y: 10, length: 0.1, ease: "power3.in" }, "<")
Then the soar itself. The group strikes horizontally whereas the vertical movement follows a parabolic arc — sine.out going up, power3.in coming down. The easing distinction between up and down is what offers it pure gravity.
.to(groupRef.present, { x: "+=" + jumpDist, length: 0.85,
ease: "power1.inOut" }, "soar")
.to(groupRef.present, { y: -90, length: 0.42,
ease: "sine.out" }, "soar")
.to(groupRef.present, { y: 0, length: 0.2,
ease: "power3.in" }, "soar+=0.6")
The touchdown has a small bounce on the palms; they overshoot downwards for 0.05 seconds after which settle again up. With out it the touchdown feels stiff.
The Flag Waver
Flag Waver is a hybrid: sprite frames for the flag and GSAP transforms for every part else. The flag can’t be tweened. The physique sway, the hand motion, and the refined shifts – these are all GSAP.
The Flag
I illustrated twelve variations of the flag, exhibiting each place it takes mid-wave. Every body is a unique association of 5×5 pixel rectangles, and there’s no shortcut. You possibly can’t tween between pixel artwork shapes. You simply draw all of them. The primary three frames are the flag rising, going from limp to completely catching the air. As soon as it’s up, the wave begins. So on the primary play, the animation runs all twelve frames. After that, the loop picks up from body 4. The flag is already within the air. It doesn’t must rise once more.
Attaching the flag to the hand
I wrapped the suitable hand and all twelve flag sprites inside a single <g> aspect in order that they share the identical rework. Wherever the hand goes, the flag follows. The hand additionally needed to transfer in the other way of the flag wave; because the flag swings out, the hand pulls again to satisfy it, holding the flag connected to the wrist as a substitute of drifting away.
const handExtraX = [0, -6, -12, -14, -8, -2, 0, 0, -4, -10, -16, -18];
tl.set(handGroup, { x: handExtraX[frame] }, time);
<g ref={handGroupRef}>
<rect id="right-hand" x="92" y="46" width="21.6589" peak="22.6434" fill="#DD775B" />
<g ref={el => (frameRefs.present[0] = el)}>{/* flag body 0 */}</g>
<g ref={el => (frameRefs.present[1] = el)}>{/* flag body 1 */}</g>
{/* ...all 12 */}
</g>
The Physique
The physique needed to transfer reverse to the flag. When the flag swings proper, the mascot shifts left. When it comes again, he shifts proper. The ft keep planted the entire time; solely the higher physique sways. I mapped every body to a sway worth:
const swayX = [0, 0, -5, -5, 0, 4, 4, 4, 0, 0, -5, -5];
The left hand follows the identical thought. When the physique shifts left, the left hand drops a number of pixels with it. Simply 4 pixels on sure frames:
const leftHandY = [0, 0, 4, 4, 0, 0, 0, 0, 0, 0, 4, 4];
Confetti Claude
Confetti Claude is three animations operating on the similar time. The character is stomping, and two confetti bursts are firing independently.
The Character
Eight frames of Claude stomping: tilting left, reaching up, tilting proper, reaching up once more. Once more, every body is a very totally different illustration. The physique form adjustments, the hand positions change, and the leg heights change. GSAP steps by way of the eight frames on a 125ms loop.
The Confetti
Eight sprites, utterly separate from the character. Every body is a unique scatter of coloured pixels; they unfold out large at first, then skinny out because the burst fades till there’s nothing left. The entire burst additionally strikes by way of the air, shoots up, peaks, and falls again down. Eight Y values doing the work:
const particleYOffsets = [-65, -72, -76, -70, -58, -42, -22, 0];
The Timing
The confetti doesn’t simply play by itself. It waits for the mascot’s hand to succeed in the highest of the stomp earlier than it fires. The primary burst begins with a one-frame delay, so it strains up with leg body 1, the precise second the hand is raised. The second burst fires on the final leg body, the alternative stomp:
const pTl = gsap.timeline({ repeat: -1, delay: FRAME_DURATION });
const p2Tl = gsap.timeline({ repeat: -1, delay: 6 * FRAME_DURATION });
Three timelines are operating independently, however they keep in sync as a result of the delays line up with the stomp cycle. The result’s that it seems to be like Claude is definitely throwing the confetti; the hand goes up, and the burst follows. The second burst makes use of the identical sprites mirrored with scale(-1, 1), launching from the left facet as a substitute of the suitable.
Fitness center Claude
Fitness center Claude seems to be like the best animation, nevertheless it was truly the toughest. There’s no tweening, no transforms, no computed values. Simply 36 illustrated frames each place of Claude choosing up the dumbbell, curling it overhead, and placing it again down. Every body is a very totally different SVG illustration. 36 frames are drawn, however the playback sequence runs by way of 48 beats as a result of frames 13 by way of 24 play twice. Claude does a second rep.
The work wasn’t primarily within the code. It was in drawing each single body and getting the timing proper between them. Not each body performs on the similar velocity. Some want to carry longer; the dumbbell pauses on the prime of the curl, and the mascot holds place earlier than the subsequent rep. A flat price makes it really feel like a slideshow. Dynamic delays give it rhythm. GSAP builds the entire sequence as a single timeline. It loops by way of the body array, units every body’s visibility, and locations it on the timeline on the proper second utilizing the delay values:
perform getDelay(seqIdx, body)
const tl = gsap.timeline({ repeat: -1 });
let time = 0;
for (let i = 0; i < frameSequence.size; i++) {
const body = frameSequence[i];
frames.forEach((el, j) => {
if (el) tl.set(el, { show: j === body ? "inline" : "none" }, time);
});
time += getDelay(i, body);
}
Frames 6 and seven maintain for 270 ms, that’s the trouble on the prime of the carry. Frames 15 and 21 maintain for 400ms; the pause between reps. The final body sits for a full 1.5 seconds earlier than the entire thing loops. Small variations, however they’re what make it really feel like Claude is definitely understanding and never simply biking by way of SVGs.
Reflections
The entire challenge took about 4 days. What saved me going was having a transparent image of the end in my head, the objective was a precise reproduction of the unique animations. Not “impressed by,” not “much like.” The identical factor. That meant each timing, each easing, each body needed to match. It was a particular sort of problem, reverse-engineering another person’s inventive choices with code.
Shout out to GSAP for making this sort of work potential, and for the merch bundle I received after posting this challenge. And to ClaudeAI for the unique animations that began the entire thing.
Thanks for studying!! In case you made it this far, I hope one thing right here sparked an thought. Go construct one thing, your nook of the net must be enjoyable.


