Edit Page

#Handoff from Framer

How to convert interactive Framer prototypes into production.

Motion is the library driving Framer's animation and gesture capabilities, so converting prototypes into production-level code is usually straightforward.

In this guide we'll cover the main differences between the libraries.

#Striking a balance

Every API has to strike a balance between simplicity, flexibility, performance, file-size, and more.

That ideal balance is different depending on whether our code is being used in a prototype, or being deployed in a production environment. Whether it's being consumed by a designer, or a developer. This is why Motion presents a different API than Framer Library.

#Frame vs Motion components

The single biggest difference between the two APIs is that in Framer Library the fundamental building block is a Frame, while Motion uses motion components.

A Frame always renders a div, and it offers a number of top-level convenience style props like x and shadow. It also makes big assumptions about the div's default styles, like position: "absolute" and width: 100.

<Frame x={100} />

For a semantic web, there's a motion component for every valid HTML and SVG element. They offer the same animation and gesture API as a Frame as well as individual transform shortcuts like x and scale, but they're otherwise identical to their underlying element.

<motion.div style={{ x: 100 }} />

#MotionValues

MotionValues are bound to a Frame where you'd statically set a visual value, which for a Frame is usually the top-level props like x.

const x = useMotionValue(0)

return <Frame x={x} />

The same is true for motion components. MotionValues are set where you'd usually static set a value. So for HTML components, this is via the style property.

const x = useMotionValue(0)

<motion.div style={{ x }} />

For SVG, via the top-level prop for attributes, or the style property for transforms.

const cx = useMotionValue(0)
const scale = useMotionValue(1)
const originX = useMotionValue(0.5)

<motion.circle cx={cx} style={{ scale, originX }} />

#Color support

Framer Library offers the Color primitive. This allows animation between named colors, and/or different types of color (ie RGBA to HSLA).

<Frame
  initial={{ backgroundColor: Color("red") }}
  animate={{ backgroundColor: Color("#fff") }}
/>

The code that interpolates between different color spaces is quite large. It's useful in a prototype environment but in production style guides and design systems usually define colors in a single color space.

For this reason Motion only supports animating colors between RGBA/Hex, or HSLA. It also doesn't support the animation of named colors.

<motion.div
  initial={{ backgroundColor: "#f00" }}
  animate={{ backgroundColor: "#fff" }}
/>

#Scroll

In Framer, scrollable areas are created with the Scroll component. On the web, the entire viewport is scrollable. So instead Motion offers the useViewportScroll hook which returns four read-only MotionValues that can be used to power scroll-driven animations.

There isn't currently an equivalent for scrollable elements (via overflow: scroll), but it is possible to set up an equivalent system with useMotionValue and onScroll.

const scrollX = useMotionValue(0)
const handleScroll = e => {
  scrollX.set(e.nativeEvent.target.scrollLeft)
}

return <div onScroll={handleScroll} />