Infinity Framing with Next.js

Eugene Musebe

Introduction

This article demonstrates Nextjs framework can be used to generate a rich css and HTML infinite frame.

Codesandbox

Check the sandbox demo on Codesandbox.

Find github repo here.

Prerequisites

Entry-level javascript and React/Nextjs knowledge.

Setting Up the Sample Project

In your frame, create a new nextjs app: npx create-next-app infinite frame. Head to your root directory cd infinite frame`

We will begin by setting up Cloudinary in the backend.

Create or log into your cloudinary account through this link. Cloudinary will provide you with a dashboard containing environment variables to integrate into your project.

Start by including cloudinary in your project dependencies npm install cloudinary.

Create a file named .env.local in your root directory and paste the following code.

1CLOUDINARY_CLOUD_NAME =
2
3CLOUDINARY_API_KEY =
4
5CLOUDINARY_API_SECRET =

Fill your environment variables from the Cloudinary dashboard and restart your project: npm run dev.

In the pages/api folder, create a new file named upload.js and configure the cloudinary environment keys and libraries from .env.local directory.

1var cloudinary = require("cloudinary").v2;
2
3cloudinary.config({
4 cloud_name: process.env.CLOUDINARY_NAME,
5 api_key: process.env.CLOUDINARY_API_KEY,
6 api_secret: process.env.CLOUDINARY_API_SECRET,
7});

Below the code above, add a handler function to execute the POST request. The function will receive media file data and post it to the Cloudinary website. It then captures the media file's Cloudinary link and sends it back as a response.

1"pages/api/upload.js"
2
3
4export default async function handler(req, res) {
5 if (req.method === "POST") {
6 let url = ""
7 try {
8 let fileStr = req.body.data;
9 const uploadedResponse = await cloudinary.uploader.upload_large(
10 fileStr,
11 {
12 resource_type: "video",
13 chunk_size: 6000000,
14 }
15 );
16 url = uploadedResponse.url
17 } catch (error) {
18 res.status(500).json({ error: "Something wrong" });
19 }
20
21 res.status(200).json({data: url});
22 }
23}

We can now create our frame.

Head to your home component in the pages/index directory and add the following to your return statement

1"pages/index"
2
3
4<div class="container">
5 <div class="frame"></div>
6</div>

Add the following to your styles/global.css

1"styles/global.css"
2
3
4.container {
5 width:100%;
6 height: 100%;
7 position: relative;
8 display: flex;
9 align-items: center;
10 justify-content: center;
11}
12.frame {
13 width: 900px;
14 height: 900px;
15 position: absolute;
16 border-radius: 50px;
17 border: 5px #087be6 solid;
18}

We have created a frame width and height of 900px. Set the position to absolute and a border-radius of 50px.

Change the container background and add the following code to the frame:

1"styles/global.css"
2
3
4.container {
5 ...
6 background: linear-gradient(90deg, rgba(0,41,69,1) 6%, rgb(53, 0, 56) 29%, rgba(7,33,71,1) 84%);
7}
8
9.frame {
10...
11 box-shadow:
12 0px 0px 20px #00ccff,
13 inset 0px 0px 20px #00ccff,
14 0px 0px 60px #ff00c8,
15 inset 0px 0px 60px #ff00c8;
16}

Add more frames to the container, as many as you like.

1"pages/index"
2
3
4 <div className="container">
5 <div className="frame"></div>
6 <div className="frame"></div>
7 <div className="frame"></div>
8 <div className="frame"></div>
9 <div className="frame"></div>
10 <div className="frame"></div>
11 <div className="frame"></div>
12 <div className="frame"></div>
13 <div className="frame"></div>
14 <div className="frame"></div>
15 <div className="frame"></div>
16 <div className="frame"></div>
17 <div className="frame"></div>
18 </div>

Now add the following to your styles/global.css directory

1.frame:nth-child(1) {
2 transform: rotate(40deg) translateY(0px) translateZ(0px);
3 opacity: 1.00;
4 animation-delay: 0.1s;
5}
6
7.frame:nth-child(2) {
8 transform: rotate(40deg) translateY(50px) translateZ(-10px);
9 opacity: 0.9;
10 animation-delay: 0.3s;
11}
12
13.frame:nth-child(3) {
14 transform: rotate(40deg) translateY(100px) translateZ(-20px);
15 opacity: 0.85;
16 animation-delay: 0.5s;
17}
18
19.frame:nth-child(4) {
20 transform: rotate(40deg) translateY(150px) translateZ(-30px);
21 opacity: 0.70;
22 animation-delay: 0.7s;
23}
24
25.frame:nth-child(5) {
26 transform: rotate(40deg) translateY(200px) translateZ(-40px);
27 opacity: 0.65;
28 animation-delay: 0.9s;
29}
30
31.frame:nth-child(6) {
32 transform: rotate(40deg) translateY(250px) translateZ(-50px);
33 opacity: 0.50;
34 animation-delay: 1.1s;
35}
36
37.frame:nth-child(7) {
38 transform: rotate(40deg) translateY(300px) translateZ(-60px);
39 opacity: 0.40;
40 animation-delay: 1.3s;
41}
42
43.frame:nth-child(8) {
44 transform: rotate(40deg) translateY(350px) translateZ(-70px);
45 opacity: 0.35;
46 animation-delay: 1.5s;
47}
48
49.frame:nth-child(9) {
50 transform: rotate(40deg) translateY(400px) translateZ(-80px);
51 opacity: 0.30;
52 animation-delay: 1.7s;
53}
54
55.frame:nth-child(10) {
56 transform: rotate(40deg) translateY(450px) translateZ(-90px);
57 opacity: 0.25;
58 animation-delay: 1.9s;
59}
60
61.frame:nth-child(11) {
62 transform: rotate(40deg) translateY(500px) translateZ(-100px);
63 opacity: 0.20;
64 animation-delay: 2.1s;
65}
66
67.frame:nth-child(12) {
68 transform: rotate(40deg) translateY(550px) translateZ(-110px);
69 opacity: 0.15;
70 animation-delay: 2.3s;
71}
72
73.frame:nth-child(13) {
74 transform: rotate(40deg) translateY(600px) translateZ(-120px);
75 opacity: 0.1;
76 animation-delay: 2.5s;
77}
78
79.frame:nth-child(14) {
80 transform: rotate(40deg) translateY(650px) translateZ(-130px);
81 opacity: 0.5;
82 animation-delay: 2.7s;
83}
84
85.frame:nth-child(15) {
86 transform: rotate(40deg) translateY(700px) translateZ(-140px);
87 opacity: 0.1;
88 animation-delay: 2.9s;
89}

Here is the result:

Let's make it look better. Set the perspective to be rendered as 2D of 50px and also increase the brightness and contrast of the shadow for aesthetic.

1.container {
2...
3 perspective: 50px;
4}
5.frame {
6...
7 filter:brightness(1.5) contrast(3);
8}

The result:

Finally, add a glowing and zooming animation. Use key frames toanimate the frames' briightness and perspective and container perspective.

1@keyframes breathing {
2 0% {filter: brightness(1.5) contrast(3);}
3 50% {filter: brightness(1.1) contrast(2);}
4 100% {filter: brightness(1.5) contrast(3);}
5}
6@keyframes zooming {
7 0% {perspective: 45px;}
8 50% {perspective: 50px;}
9 100% {perspective: 45px;}
10}

Ease the trick by gradualy increasing animation delay in each of them like below:

1"styles/global.css"
2
3
4.frame:nth-child(1) {
5 transform: rotate(40deg) translateY(0px) translateZ(0px);
6 opacity: 1.00;
7 animation-delay: 0.1s;
8}
9
10.frame:nth-child(2) {
11 transform: rotate(40deg) translateY(50px) translateZ(-10px);
12 opacity: 0.9;
13 animation-delay: 0.3s;
14}
15
16.frame:nth-child(3) {
17 transform: rotate(40deg) translateY(100px) translateZ(-20px);
18 opacity: 0.85;
19 animation-delay: 0.5s;
20}
21
22.frame:nth-child(4) {
23 transform: rotate(40deg) translateY(150px) translateZ(-30px);
24 opacity: 0.70;
25 animation-delay: 0.7s;
26}

With the animation complete, we can now capture the frame at any point and upload the caption to Cloudinary. Ensure to go through the article to enjoy the experience.

Eugene Musebe

Software Developer

I’m a full-stack software developer, content creator, and tech community builder based in Nairobi, Kenya. I am addicted to learning new technologies and loves working with like-minded people.