Deconstructing Framer X landing page animation.

Angel Davchev
Oct 2 · 5 min read

And getting away with it like cool dudes who don’t look at explosions

Always interactive, lightning fast design.

Is what their Unique Selling Point says when you first land on And they’re right. Framer is a well known design tool in the UX/UI world. For those of you who don’t know jack all about Framer, it’s probably one of the best, if not the best interaction design tool on the market. You can design, build prototypes, add sexy micro interactions and export everything in React code, so those pesky developers won’t have to bother you about how much padding does the media object have on the vertical and horizontal axis. How cool is that? It’s cooler than cool. As Andre 3000 said “Iceeee-coooold”.

This is backed up by plethora of top notch companies that use Framer as their go to design and prototype tool: Facebook, PayPal, MailChimp, Netflix, Tinder and many more.

The landing page

Now, selling a product as cool as Framer X is, your landing page has to be on par with it, right? Damn right, I say. Framer’s landing page is a clean, informative and aesthetically pleasing amalgamation of HTML, CSS, JavaScript, SVG and a few .mp4 videos that showcase the product at it’s best and how to use it. The page has ample of animations: As you scroll your way down, images, text blocks and videos magically appear on your screen to keep you engaged and informed the best way possible.

These animations are triggered as soon as you scroll past some element on the screen, and frankly my dear are nothing new in the landing page design and development business.

What really got my attention was their Store block and the way the store cards animated in an infinite loop forever and ever, upwards and upwards. I just had to find out how they did it and I just had to write an article about it.

Cool, isn’t it?

Let’s talk some CTRL+SHIFT+I stuff

If you press those three keys together, the browser will magically switch to the inspect mode, and you can view the element structure of the page. If you scroll down to the Store block of the page, you’ll see that the content is divided in 2 sections with CSS Grid. The code is:

display: grid;
grid-template-columns: 580px 440px;
grid-gap: 100px;
align-items: center;

This puts the store cards on the left, the text content on the right, aligned to the center with a gap of 100px between them. Pretty straightforward.

The block structure

The store cards are contained in 2 divs: The first containing div .store-cards has a fixed height of 840px . This acts as some kind of a viewport and it sets the height for the whole section. The section container #feature-store has an overflow: hidden property attached to it, so the cards are animating in a vertical space of 840px and anything that goes beyond that won’t show on the screen. Now the second containing div for the store cards that has an intriguing name of just “div” has the following properties attached to it:

display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: auto;
grid-auto-flow: row;
grid-gap: 20px;
width: 560px;
position: relative;
top: 0;
animation: scrollUp 40s linear infinite;

This just means that the cards are set in three columns, spaced out by a 20px gutter on both the vertical and horizontal axis and if by any chance there’s a new card added, it will be auto flown to a new row. What a mouthful.

The “div” is our main guy. El Divo! [Mexican mariachi music playing, cut of by a whiplash sound].

The animation

Okay, now that we’re familiar with the block structure, let’s dive into the animation.

That must’ve hurt

It appears that Framer aren’t using any JavaScript library to animate the cards. Instead, they rely on good ol’ CSS and keyframes. Before I’ve even decided to write this article, I’ve self confidently wrote the animation myself.

@keyframes scrollUp {
from {
transform: translateY(0px);
to {
transform: translateY(-100%);

But then I’ve watched the cards magically disappear into the void, then start again from ground zero, then disappear into the void again and so on and so forth. I’ve noticed that the animation isn’t right.

I went to inspect mode again and switched to the “Sources” tab to find out what’s going on.

What’s this magic number?

Turns out they are animating the translateY property to -1125px . Who gave them this number? Why? I’ve started doing math to find out how they got this four digits devil.

My face during the process

The discovery

Now obviously, there isn’t an infinite set of cards. That would just pollute the DOM to the level of Earth’s pollution, and the CSS Greta will make a speech for it.

Turns out Framer have 15 store-cards, but the trick is, they are rendering them twice in order to achieve the effect.


So, if the cards are divided into three columns and there’s a set of 15 cards, that would mean there are five rows of cards. The cards have fixed height of 205px and 20px gutter between them.

If you take the magic number of 1125 and divide it by 5 and then remove 20 from it, you’ll get 205 which is the card height number in pixels. Eureka!

As I’ve mentioned above they render the cards twice, so you wouldn’t notice the gap between when the animation starts all over.

So the formula to get the magic number to translate your cards on the Y axis is the following:

(cardHeight + gutterWidth) * numberOfRows

And there you have it folks. I hope that this article was exciting and I sincerely hope that you’ve learned something new along the way. Happy hacking!


Laika is a free platform where Tech professionals can find a job they love in the Balkans.

Angel Davchev

Written by

UI/UX designer


Laika is a free platform where Tech professionals can find a job they love in the Balkans.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade