profile picture

Chi Kin Tsang

Front-end Developer

Learn more about me.

Utrecht, The Netherlands

technology

24
Jul

Infinite Marquee using React and Motion One

I'm sure you have seen them before. A continuous scrolling and looping animation, containing either text or images called a marquee. It's often used to show the logos of partners or as a picture gallery. Let's recreate this animation using React and Motion One!

Initializing the project

First, we will be creating our project and installing some packages.

  • Let's start with creating our app using NextJS by running npx create-next-app@latest in the terminal.
  • Next, for handling the animations we'll install the Motion library by running npm i motion.

Creating the layout

To create the layout, let's start with creating a list of images which we'll be using for the project.

Then we map over the list of images and return an image component to render those images.

  • The width of the images is calculated by dividing the width of the container (in this case the width of the viewport) by the amount of images in the list with logos.length.
  • We use flex-shrink-0 to prevent the images from shrinking and causing it to overlap with each other.

It should look like this:

Loading image...

The static marquee layout

Animating the Infinite Scrolling Marquee

To create the animation, we have to start with importing the motion component from the Motion One library.

Then we change the <div> element containing the images to a <motion.div> component. To make the images move horizontally, we have to animate the x-axis of the motion component. At last, we make it loop continuously at a steady pace by setting the ease to linear and repeat it endlessly with repeat: Infinity.

  • The animation starts off at x = "0" which is the default position and moves left until it reaches -100%, which means it'll move left until its entire width has moved out of the container.

Loading image...

An overview of the layout at the start and end of the animation. Do you spot a problem?

As you can see there is a big empty space left behind from the logos leaving the container when x reaches -100%. To fix this we have to duplicate our list of logos to fill in the empty gap.

This works, because the width is exactly double the size of the original list of logos.

Loading image...

The duplicate images will fill in the empty space

Let's put it all together and create the component.

It will look like this:

We can add a blur to the sides of the marquee for a subtle fade effect.

The end result will look like this:

22
Jun

Scroll Parallax using React and Motion One

Recently, I've been seeing this parallax effect being used quite often on Wordpress websites. Let's recreate this subtle parallax effect using React and Motion One.

Initializing the project

First, we will be creating our project and installing some packages.

  • Let's start with creating our app using NextJS by running npx create-next-app@latest in the terminal.
  • Next, for handling the animations we'll install the Motion library by running npm i motion.
  • We will be using Lenis scroll to enable smooth scroll animations by running npm i lenis.

Creating the layout

We create a list of images which we'll be using for the project.

Next we render the images from the list.

Animating the Parallax Image

First, we create a ref for the container of the image. We'll set it as the target for the useScroll hook from Motion to track its vertical progress within the viewport.

Next, we specify the offset. It describes the points in which the target intersects with the viewport.

  • "start end" means the intersection in which the top ("start") of the target element meets the bottom ("end") of the viewport. It describes the place where the element first enters the screen.
  • "end start" means the intersection in which the bottom ("end") of the target meets the top ("start") of the viewport. It's the place where the target element leaves the screen.
  • The scrollYProgress value ranges from 0 to 1 with "0" being the moment the target element first enters the viewport and "1" the moment right before the element leaves the viewport.

With the useTransform hook from Motion we can transform the scrollYProgress values into other motion values.

  • The value for imageY will be -250 pixels when the value for scrollYProgress is at "0" and 0 pixels when the value of scrollYProgress is at "1". The hook will take care of all the values in between these two numbers. This means the image will be shifted down by -250 pixels when it first enters the viewport and it will move up as the user continues to scroll down.
  • We do the opposite for textY to create a second layer for the parallax effect.

Let's put it all together and create the component.

  • To apply the animation to an element, we have to change it to a motion component. <img> turns into <motion.img> and <h1> turns into <motion.h1>. We can then access the style and customize it with our motion value.

The end result will look like this:

1
Jun

Creating Custom Rich-Text Components using TinaCMS

Tina's rich-text editor comes out of the box with a lot of useful options to spice up the blog posts, like inserting code blocks and adding images to the post. I've been wanting to add MP4 videos to my posts, but it's lacking that feature by default. Luckily, it's easy to extend it with custom rich-text components. Here's how to do it.

Creating the component

Let's start with creating the MP4 video player component using React.

  • To make the videos automatically play, it is required for them to be muted.
  • playsInline is needed to make it play automatically in mobile browsers, because the default behaviour is to have the video be paused until the user plays the video, which opens it fullscreen.
  • Add controls for accessibility to give the user the option to pause the video.

Next, to extend the rich-text editor, you have to add the custom component to the TinaMarkdown component which renders the body.

Finally, add it to Tina's config.ts file as a template.

  • Use type: "image" to make use of Tina's image field for handling the media selection and uploads.

Now you should be able to embed MP4 videos to your blog posts:

Loading image...

1
Mar

My Personal Blog

Hey there! Welcome to my personal blog. It's a place on the internet which I can call "my own". The purpose of building this website was to not only delve deeper into the world of ReactJS, but also to use it as a great learning experience for building something from scratch and watching it come to fruition. The beauty of building a personal website is that it can be whatever I want it to be, while also being the owner of my content.

The Tech Stack

Before even writing a single line of code, I had to decide on what technologies to use for the website. Honestly, it was both a blessing and a curse. On the one hand a blessing, because there are so many awesome open source tools available on the web, but on the other hand a curse for the exact same reason. How do you know what to pick when presented with a near infinite amount of options? I've ultimately decided to use the following.

  • NextJS: As recommended by the official ReactJS development team. I've made use of its Static Site Generation capabilities to make pages load blazingly fast. The routing and deployment was also an ease to setup with the use of their in-depth documentation.
  • TailwindCSS: For styling the website and its components. It removes the need of thinking of class names and hopping between files which makes for a more efficient developing experience.
  • Motion One: To breathe life into the site by animating my components which makes for a more pleasant user experience.

Using this stack not only allowed me to have a smooth developing experience because of my previous experience in working with parts of this stack, but it also let me gain a deeper understanding of using these tools by diving into their official docs.

For managing my content I'm using TinaCMS and Cloudinary. Tina's rich text editor with the ability to view changes live was the main draw for it over its other Content Management System competitors. The drawback was its limited documentation, but they've been expanding their docs at a great speed.

TinaCMS editor

I opted for Cloudinary over Vercel for storing the images, because of its generous free tier while keeping the images responsive.

Final Words

It was quite an interesting experience to build something mostly from reading the documentation and scavenging the web for solutions to my problems. There's still a lot I would like to add the site, but this is a good start!