Logo

dev-resources.site

for different kinds of informations.

A Tinder-like card game with Framer-Motion

Published at
9/26/2023
Categories
nextjs
framermotion
tailwindcss
Author
lansolo99
Categories
3 categories in total
nextjs
open
framermotion
open
tailwindcss
open
Author
9 person written this
lansolo99
open
A Tinder-like card game with Framer-Motion

Stack used

  • Next.js + Typescript
  • Tailwind
  • Framer Motion

Side note

This post is not a tutorial on building this module from scratch, but a recap of the process and things I wanted to share. I invite you to take a look at the repo if you are interested on examining or pulling the whole code.

Context

In the same vein of my precedent small puzzle game, I adapted the concept of Tinder-like cards swipe using Framer-motion, a powerful React animation library that I still explore on a regular basis.

Initially, I designed an animated prototype and I decided to implement it, in order to customize it for client in the future.

Here are the live demo and the public repo.

Design

The initial concept was to propose a quick game testing someone knowledge on the carbon footprint.

The Tinder-like gesture turned out to be an interesting UI solution, as it brings an appealing, and entertaining UI.

After designing some key screens (Figma) and tested them through an animated After Effects prototype (After Effects), time has come to turn it into some functional code.

Framer-motion

This kind of interactity perfectly fits with what Framer-Motion is capable of. We are talking about gesture event listeners and animation controlled elements.

1. Gesture management with Drag

The first needed piece is the Drag gesture, that will be mapped from the swipe movement.

Framer-Motion has the Drag & Pan helpers.

It's a matter of turning moving elements into a "motion" element using:



<motion.div>


Enter fullscreen mode Exit fullscreen mode

Then apply specific Framer-Motion attributes on them.

For the use-case of a swiping card, I used the following ones :

  • drag (set the element draggable)
  • dragSnapToOrigin (animate the element back to origin at release)
  • dragElastic (set increasing friction as the element walks away from its origin)
  • dragConstraints (maximum distance allowed from element's origin)
  • dragTransition (apply an organic easing when the elements move away or back at release)
  • onDrag (speak for itself)
  • onDragStart (speak for itself)
  • onDragEnd (speak for itself)

All of these events handlers greatly simplify the process to animate a card properly, so it behave with constraints and elastic transitions.

2. Value mapping with UseTransform

The second needed piece is the transform helper to map other elements animation as we swipe left or right (e.g: the bottom action buttons scale).

Framer-Motion has the useTransform hook.

This is the Framer-Motion helper to map any primary movements to control adjacent elements.

The useTransform expose an output value based on a Motion value.
This hook track any motion values derived from a primary element.

Usually, we extract this motion value as variable from an element styled property, and pass it to the useTransform hook to map the desired output.



const x = useMotionValue(0)
const inputX = [-150, 0, 150]
const outputY = [50, 0, 50]

let drivenX = useTransform(x, inputX, outputY)

// ...

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


Enter fullscreen mode Exit fullscreen mode

In this case, x is the Framer-Motion shorthand property for transform: translateX() , and only works for element with motion tags.

3. Animation state tracking with useMotionValueEvent

Lastly, a very useful thing is to trigger some actions based on some animated values.

Framer-Motion has the useMotionValueEvent hook.

It acts like a useEffects, but is specifically designed to work with motion values.



const x = useMotionValue(0)

useMotionValueEvent(x, 'animationStart', () => {
  console.log('animation started on x')
})


Enter fullscreen mode Exit fullscreen mode

In my case, I used it to lift some updated states to a parent component, because animated adjacent components (actions buttons and colored background) are one level up:



useMotionValueEvent(x, 'change', (latest) => {
setCardDrivenProps((state) => ({
...state,
buttonScaleBadAnswer: drivenActionLeftScale,
buttonScaleGoodAnswer: drivenActionRightScale,
mainBgColor: drivenBg,
}))
})

Enter fullscreen mode Exit fullscreen mode




Swipe logic

In my specific case, I wanted to have a more granular control over the swiped card, so I used an additional transparent overlay as draggable element to control the card itself.

Puzzle start

That is pretty much it for the Framer-Motion hooks experimented.

The official doc does a pretty good job at explaining the api. For additional and more human resource, I strongly advise the Sam Selikoff channel, a true expert with a great pedagogy on the subject.

Image-mask

Another thing I struggled with was masking the card image with a custom shape, while leveraging the Next.js Image component.

I wanted to use an SVG mask but failed at a satisfaying result in term of concice syntax.

I ended up using a png image using the CSS mask-image property. It works BUT, we have to put in the webkit vendor prefix to make it work.



style={{
maskImage: url('/images/gamecard-image-mask.png'),
WebkitMaskImage: url(/images/gamecard-image-mask.png),
maskSize: "contain",
WebkitMaskSize: "contain",
maskRepeat: "no-repeat",
WebkitMaskRepeat: "no-repeat",
}}

Enter fullscreen mode Exit fullscreen mode




Contexts and RSCs

Next.js has adopted the new React server component paradigm.

This module is mostly state driven animated, so pretty much all the components are client.

I could have put the text as server component with boundaries, but I didn't see the burden being worth, for this prototype.

The Root Layout is the only server component and pass some initial datas to some React contexts.

These contexts take care of the current game and user score.

I don't want to advertise, but I learned a lot from the free Jack Herrington course to refactor the way I wrote contexts and how to deal with this new paradigm, regarding management state.

Wrapping up

Framer-Motion is a huge and pretty complex library that I still explore and use on a regular basis.

There is still a pile of hooks I haven't play with yet.

Also don't hesitate to drop feebacks, as there is always a lot to learn from each others!

framermotion Article's
30 articles in total
Favicon
Building a food simulation game with Next.js and generative design
Favicon
How to Create a Flipping Card Animation Using Framer Motion
Favicon
State-of-the-Art Web Design with Remix, Tailwind, and Framer Motion
Favicon
How I Created a Stunning Portfolio with Next.js, Tailwind CSS, and Framer Motion
Favicon
Creating the iMessage Card Stack Animation: The Interactive Layer
Favicon
Creating the iMessage Card Stack Animation: The Timelineย Design
Favicon
How to build awesome website with stunning animation?
Favicon
Adding motion to 3D models with Framer Motion and Three.js
Favicon
Creating a Smooth Animated Menu with React and Framer Motion
Favicon
My-Portfolio
Favicon
Watch Out For Broken Links, 404 Page With Framer Motion, TailwindCSS and NextJs
Favicon
Could not find a declaration file for module framer-motion Error in Next.js 14
Favicon
How to add Animations and Transitions in React
Favicon
Creating a text writing animation in React using Framer-Motion
Favicon
Unveiling My Portfolio Website: A Fusion of Tech and Creativity ๐Ÿš€
Favicon
React developer portfolio template use framer motion to animate components
Favicon
Building a mini casual game with Next.js
Favicon
Creating a Multi-Level Sidebar Animation with Tailwind and Framer Motion in React
Favicon
Easy Animated Tabs in ReactJS with Framer Motion
Favicon
A Tinder-like card game with Framer-Motion
Favicon
Elevating Web Design with Framer Motion: Bringing Your Website to Life
Favicon
Animating the Web: Route Transitions in Next.js with Framer Motion
Favicon
Enhancing Form Usability with Framer Motion: A Guide to Animated, Chunked Form Transitions
Favicon
How to Build a fully accessible Accordion with HeadlessUI, Framer Motion, and TailwindCSS
Favicon
Build Portfolio Theme in Tailwind CSS & Next.js
Favicon
How to create Scroll-Linked Animations with React and Framer Motion ๐Ÿ’ƒ๐Ÿป๐Ÿ•บ๐Ÿป
Favicon
How to build 3 simple animation with framer motion
Favicon
How to create an awesome navigation menu using chakra-UI and framer-motion.
Favicon
Make a slide open envelope
Favicon
Animate everything with Framer Motion

Featured ones: