Back to Components
Timed Cards Opening
Component

Timed Cards Opening

CodewithLord
October 29, 2025

This project is a **visually engaging web page** that displays travel destination cards with animation and interactivity

🧠 Description

This project is a visually engaging web page that displays travel destination cards with animation and interactivity.
It uses HTML, CSS, and GSAP (JavaScript animation library) to create a dynamic card transition effect with a navigation bar, details section, and progress pagination.


💻 HTML Code


1<!DOCTYPE html> 2<html lang="en"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title>CodewithLord - Timed Cards Opening</title> 7 <link rel="stylesheet" href="./style.css"> 8 9 </head> 10 11 <body> 12 <body> 13 <div class="indicator"></div> 14 15 <nav> 16 <div> 17 <div class="svg-container"> 18 <svg 19 xmlns="http://www.w3.org/2000/svg" 20 fill="none" 21 viewBox="0 0 24 24" 22 stroke-width="1.5" 23 stroke="currentColor" 24 > 25 <path 26 stroke-linecap="round" 27 stroke-linejoin="round" 28 d="M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418" 29 /> 30 </svg> 31 </div> 32 <div>CodewithLord</div> 33 </div> 34 <div> 35 <div class="active">Home</div> 36 <div>Holidays</div> 37 <div>Destinations</div> 38 <div>Flights</div> 39 <div>Offers</div> 40 <div>Contact</div> 41 <div class="svg-container"> 42 <svg 43 xmlns="http://www.w3.org/2000/svg" 44 fill="none" 45 viewBox="0 0 24 24" 46 stroke-width="1.5" 47 stroke="currentColor" 48 > 49 <path 50 stroke-linecap="round" 51 stroke-linejoin="round" 52 d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z" 53 /> 54 </svg> 55 </div> 56 <div class="svg-container"> 57 <svg 58 xmlns="http://www.w3.org/2000/svg" 59 viewBox="0 0 24 24" 60 fill="currentColor" 61 > 62 <path 63 fill-rule="evenodd" 64 d="M7.5 6a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM3.751 20.105a8.25 8.25 0 0116.498 0 .75.75 0 01-.437.695A18.683 18.683 0 0112 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 01-.437-.695z" 65 clip-rule="evenodd" 66 /> 67 </svg> 68 </div> 69 </div> 70 </nav> 71 72 <div id="demo"></div> 73 74 <div class="details" id="details-even"> 75 <div class="place-box"> 76 <div class="text">Switzerland Alps</div> 77 </div> 78 <div class="title-box-1"><div class="title-1">SAINT</div></div> 79 <div class="title-box-2"><div class="title-2">ANTONIEN</div></div> 80 <div class="desc"> 81 Tucked away in the Switzerland Alps, Saint Antönien offers an idyllic retreat for those seeking tranquility and adventure alike. It's a hidden gem for backcountry skiing in winter and boasts lush trails for hiking and mountain biking during the warmer months. 82 </div> 83 <div class="cta"> 84 <button class="bookmark"> 85 <svg 86 xmlns="http://www.w3.org/2000/svg" 87 viewBox="0 0 24 24" 88 fill="currentColor" 89 > 90 <path 91 fill-rule="evenodd" 92 d="M6.32 2.577a49.255 49.255 0 0111.36 0c1.497.174 2.57 1.46 2.57 2.93V21a.75.75 0 01-1.085.67L12 18.089l-7.165 3.583A.75.75 0 013.75 21V5.507c0-1.47 1.073-2.756 2.57-2.93z" 93 clip-rule="evenodd" 94 /> 95 </svg> 96 </button> 97 <button class="discover">Discover Location</button> 98 </div> 99 </div> 100 101 <div class="details" id="details-odd"> 102 <div class="place-box"> 103 <div class="text">Switzerland Alps</div> 104 </div> 105 <div class="title-box-1"><div class="title-1">SAINT </div></div> 106 <div class="title-box-2"><div class="title-2">ANTONIEN</div></div> 107 <div class="desc"> 108 Tucked away in the Switzerland Alps, Saint Antönien offers an idyllic retreat for those seeking tranquility and adventure alike. It's a hidden gem for backcountry skiing in winter and boasts lush trails for hiking and mountain biking during the warmer months. 109 </div> 110 <div class="cta"> 111 <button class="bookmark"> 112 <svg 113 xmlns="http://www.w3.org/2000/svg" 114 viewBox="0 0 24 24" 115 fill="currentColor" 116 > 117 <path 118 fill-rule="evenodd" 119 d="M6.32 2.577a49.255 49.255 0 0111.36 0c1.497.174 2.57 1.46 2.57 2.93V21a.75.75 0 01-1.085.67L12 18.089l-7.165 3.583A.75.75 0 013.75 21V5.507c0-1.47 1.073-2.756 2.57-2.93z" 120 clip-rule="evenodd" 121 /> 122 </svg> 123 </button> 124 <button class="discover">Discover Location</button> 125 </div> 126 </div> 127 128 <div class="pagination" id="pagination"> 129 <div class="arrow arrow-left"> 130 <svg 131 xmlns="http://www.w3.org/2000/svg" 132 fill="none" 133 viewBox="0 0 24 24" 134 stroke="currentColor" 135 > 136 <path 137 stroke-linecap="round" 138 stroke-linejoin="round" 139 d="M15.75 19.5L8.25 12l7.5-7.5" 140 /> 141 </svg> 142 </div> 143 <div class="arrow arrow-right"> 144 <svg 145 xmlns="http://www.w3.org/2000/svg" 146 fill="none" 147 viewBox="0 0 24 24" 148 stroke="currentColor" 149 > 150 <path 151 stroke-linecap="round" 152 stroke-linejoin="round" 153 d="M8.25 4.5l7.5 7.5-7.5 7.5" 154 /> 155 </svg> 156 </div> 157 <div class="progress-sub-container" > 158 <div class="progress-sub-background" > 159 <div class="progress-sub-foreground" ></div> 160 </div> 161 </div> 162 <div class="slide-numbers" id="slide-numbers"></div> 163 </div> 164 165 <div class="cover" ></div> 166 167 168 169 </body> 170 <script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js'></script><script src="./script.js"></script> 171 172 </body> 173 174</html> 175

The HTML defines the layout of the page.

It includes:

A navbar with icons and links.

A main “details” section showing the travel card content.

A pagination section for slide transitions.

A cover element used for animated page entry effects.

The GSAP library is loaded for animations.

CSS Code


1@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Oswald:wght@500&display=swap"); 2body { 3 margin: 0; 4 background-color: #1a1a1a; 5 color: #FFFFFFDD; 6 position: relative; 7 overflow: hidden; 8 font-family: "Inter", sans-serif; 9} 10 11.card { 12 position: absolute; 13 left: 0; 14 top: 0; 15 background-position: center; 16 background-size: cover; 17 box-shadow: 6px 6px 10px 2px rgba(0, 0, 0, 0.6); 18} 19 20#btn { 21 position: absolute; 22 top: 690px; 23 left: 16px; 24 z-index: 99; 25} 26 27.card-content { 28 position: absolute; 29 left: 0; 30 top: 0; 31 color: #FFFFFFDD; 32 padding-left: 16px; 33} 34 35.content-place { 36 margin-top: 6px; 37 font-size: 13px; 38 font-weight: 500; 39} 40 41.content-place { 42 font-weight: 500; 43} 44 45.content-title-1, 46.content-title-2 { 47 font-weight: 600; 48 font-size: 20px; 49 font-family: "Oswald", sans-serif; 50} 51 52.content-start { 53 width: 30px; 54 height: 5px; 55 border-radius: 99px; 56 background-color: #FFFFFFDD; 57} 58 59.details { 60 z-index: 22; 61 position: absolute; 62 top: 240px; 63 left: 60px; 64} 65.details .place-box { 66 height: 46px; 67 overflow: hidden; 68} 69.details .place-box .text { 70 padding-top: 16px; 71 font-size: 20px; 72} 73.details .place-box .text:before { 74 top: 0; 75 left: 0; 76 position: absolute; 77 content: ""; 78 width: 30px; 79 height: 4px; 80 border-radius: 99px; 81 background-color: white; 82} 83.details .title-1, 84.details .title-2 { 85 font-weight: 600; 86 font-size: 72px; 87 font-family: "Oswald", sans-serif; 88} 89.details .title-box-1, 90.details .title-box-2 { 91 margin-top: 2px; 92 height: 100px; 93 overflow: hidden; 94} 95.details > .desc { 96 margin-top: 16px; 97 width: 500px; 98} 99.details > .cta { 100 width: 500px; 101 margin-top: 24px; 102 display: flex; 103 align-items: center; 104} 105.details > .cta > .bookmark { 106 border: none; 107 background-color: #ecad29; 108 width: 36px; 109 height: 36px; 110 border-radius: 99px; 111 color: white; 112 display: grid; 113 place-items: center; 114} 115.details > .cta > .bookmark svg { 116 width: 20px; 117 height: 20px; 118} 119.details > .cta > .discover { 120 border: 1px solid #ffffff; 121 background-color: transparent; 122 height: 36px; 123 border-radius: 99px; 124 color: #ffffff; 125 padding: 4px 24px; 126 font-size: 12px; 127 margin-left: 16px; 128 text-transform: uppercase; 129} 130 131nav { 132 position: fixed; 133 left: 0; 134 top: 0; 135 right: 0; 136 z-index: 50; 137 display: flex; 138 align-items: center; 139 justify-content: space-between; 140 padding: 20px 36px; 141 font-weight: 500; 142} 143nav svg { 144 width: 20px; 145 height: 20px; 146} 147nav .svg-container { 148 width: 20px; 149 height: 20px; 150} 151nav > div { 152 display: inline-flex; 153 align-items: center; 154 text-transform: uppercase; 155 font-size: 14px; 156} 157nav > div:first-child { 158 gap: 10px; 159} 160nav > div:last-child { 161 gap: 24px; 162} 163nav > div:last-child > .active { 164 position: relative; 165} 166nav > div:last-child > .active:after { 167 bottom: -8px; 168 left: 0; 169 right: 0; 170 position: absolute; 171 content: ""; 172 height: 3px; 173 border-radius: 99px; 174 background-color: #ecad29; 175} 176 177.indicator { 178 position: fixed; 179 left: 0; 180 right: 0; 181 top: 0; 182 height: 5px; 183 z-index: 60; 184 background-color: #ecad29; 185} 186 187.pagination { 188 position: absolute; 189 left: 0px; 190 top: 0px; 191 display: inline-flex; 192} 193.pagination > .arrow { 194 z-index: 60; 195 width: 50px; 196 height: 50px; 197 border-radius: 999px; 198 border: 2px solid #ffffff55; 199 display: grid; 200 place-items: center; 201} 202.pagination > .arrow:nth-child(2) { 203 margin-left: 20px; 204} 205.pagination > .arrow svg { 206 width: 24px; 207 height: 24px; 208 stroke-width: 2; 209 color: #ffffff99; 210} 211.pagination .progress-sub-container { 212 margin-left: 24px; 213 z-index: 60; 214 width: 500px; 215 height: 50px; 216 display: flex; 217 align-items: center; 218} 219.pagination .progress-sub-container .progress-sub-background { 220 width: 500px; 221 height: 3px; 222 background-color: #ffffff33; 223} 224.pagination .progress-sub-container .progress-sub-background .progress-sub-foreground { 225 height: 3px; 226 background-color: #ecad29; 227} 228.pagination .slide-numbers { 229 width: 50px; 230 height: 50px; 231 overflow: hidden; 232 z-index: 60; 233 position: relative; 234} 235.pagination .slide-numbers .item { 236 width: 50px; 237 height: 50px; 238 position: absolute; 239 color: white; 240 top: 0; 241 left: 0; 242 display: grid; 243 place-items: center; 244 font-size: 32px; 245 font-weight: bold; 246} 247 248.cover { 249 position: absolute; 250 left: 0; 251 top: 0; 252 width: 100vw; 253 height: 100vh; 254 background-color: #fff; 255 z-index: 100; 256} 257

The dark theme with #1a1a1a background gives a cinematic feel.

Typography uses Inter for text and Oswald for large titles.

.details styles structure the content area (titles, descriptions, buttons).

.pagination defines circular navigation arrows and a progress bar that animates between slides.

.cover creates a smooth transition overlay during page load.

Javascipt Code


1const data = [ 2 { 3 place:'Switzerland Alps', 4 title:'SAINT', 5 title2:'ANTONIEN', 6 description:'Tucked away in the Switzerland Alps, Saint Antönien offers an idyllic retreat for those seeking tranquility and adventure alike. It\'s a hidden gem for backcountry skiing in winter and boasts lush trails for hiking and mountain biking during the warmer months.', 7 image:'https://assets.codepen.io/3685267/timed-cards-1.jpg' 8 }, 9 { 10 place:'Japan Alps', 11 title:'NANGANO', 12 title2:'PREFECTURE', 13 description:'Nagano Prefecture, set within the majestic Japan Alps, is a cultural treasure trove with its historic shrines and temples, particularly the famous Zenkō-ji. The region is also a hotspot for skiing and snowboarding, offering some of the country\'s best powder.', 14 image:'https://assets.codepen.io/3685267/timed-cards-2.jpg' 15 }, 16 { 17 place:'Sahara Desert - Morocco', 18 title:'MARRAKECH', 19 title2:'MEROUGA', 20 description:'The journey from the vibrant souks and palaces of Marrakech to the tranquil, starlit sands of Merzouga showcases the diverse splendor of Morocco. Camel treks and desert camps offer an unforgettable immersion into the nomadic way of life.', 21 image:'https://assets.codepen.io/3685267/timed-cards-3.jpg' 22 }, 23 { 24 place:'Sierra Nevada - USA', 25 title:'YOSEMITE', 26 title2:'NATIONAL PARAK', 27 description:'Yosemite National Park is a showcase of the American wilderness, revered for its towering granite monoliths, ancient giant sequoias, and thundering waterfalls. The park offers year-round recreational activities, from rock climbing to serene valley walks.', 28 image:'https://assets.codepen.io/3685267/timed-cards-4.jpg' 29 }, 30 { 31 place:'Tarifa - Spain', 32 title:'LOS LANCES', 33 title2:'BEACH', 34 description:'Los Lances Beach in Tarifa is a coastal paradise known for its consistent winds, making it a world-renowned spot for kitesurfing and windsurfing. The beach\'s long, sandy shores provide ample space for relaxation and sunbathing, with a vibrant atmosphere of beach bars and cafes.', 35 image:'https://assets.codepen.io/3685267/timed-cards-5.jpg' 36 }, 37 { 38 place:'Cappadocia - Turkey', 39 title:'Göreme', 40 title2:'Valley', 41 description:'Göreme Valley in Cappadocia is a historical marvel set against a unique geological backdrop, where centuries of wind and water have sculpted the landscape into whimsical formations. The valley is also famous for its open-air museums, underground cities, and the enchanting experience of hot air ballooning.', 42 image:'https://assets.codepen.io/3685267/timed-cards-6.jpg' 43 }, 44] 45 46const _ = (id)=>document.getElementById(id) 47const cards = data.map((i, index)=>`<div class="card" id="card${index}" style="background-image:url(${i.image})" ></div>`).join('') 48 49 50 51const cardContents = data.map((i, index)=>`<div class="card-content" id="card-content-${index}"> 52<div class="content-start"></div> 53<div class="content-place">${i.place}</div> 54<div class="content-title-1">${i.title}</div> 55<div class="content-title-2">${i.title2}</div> 56 57</div>`).join('') 58 59 60const sildeNumbers = data.map((_, index)=>`<div class="item" id="slide-item-${index}" >${index+1}</div>`).join('') 61_('demo').innerHTML = cards + cardContents 62_('slide-numbers').innerHTML = sildeNumbers 63 64 65const range = (n) => 66 Array(n) 67 .fill(0) 68 .map((i, j) => i + j); 69const set = gsap.set; 70 71function getCard(index) { 72 return `#card${index}`; 73} 74function getCardContent(index) { 75 return `#card-content-${index}`; 76} 77function getSliderItem(index) { 78 return `#slide-item-${index}`; 79} 80 81function animate(target, duration, properties) { 82 return new Promise((resolve) => { 83 gsap.to(target, { 84 ...properties, 85 duration: duration, 86 onComplete: resolve, 87 }); 88 }); 89} 90 91let order = [0, 1, 2, 3, 4, 5]; 92let detailsEven = true; 93 94let offsetTop = 200; 95let offsetLeft = 700; 96let cardWidth = 200; 97let cardHeight = 300; 98let gap = 40; 99let numberSize = 50; 100const ease = "sine.inOut"; 101 102function init() { 103 const [active, ...rest] = order; 104 const detailsActive = detailsEven ? "#details-even" : "#details-odd"; 105 const detailsInactive = detailsEven ? "#details-odd" : "#details-even"; 106 const { innerHeight: height, innerWidth: width } = window; 107 offsetTop = height - 430; 108 offsetLeft = width - 830; 109 110 gsap.set("#pagination", { 111 top: offsetTop + 330, 112 left: offsetLeft, 113 y: 200, 114 opacity: 0, 115 zIndex: 60, 116 }); 117 gsap.set("nav", { y: -200, opacity: 0 }); 118 119 gsap.set(getCard(active), { 120 x: 0, 121 y: 0, 122 width: window.innerWidth, 123 height: window.innerHeight, 124 }); 125 gsap.set(getCardContent(active), { x: 0, y: 0, opacity: 0 }); 126 gsap.set(detailsActive, { opacity: 0, zIndex: 22, x: -200 }); 127 gsap.set(detailsInactive, { opacity: 0, zIndex: 12 }); 128 gsap.set(`${detailsInactive} .text`, { y: 100 }); 129 gsap.set(`${detailsInactive} .title-1`, { y: 100 }); 130 gsap.set(`${detailsInactive} .title-2`, { y: 100 }); 131 gsap.set(`${detailsInactive} .desc`, { y: 50 }); 132 gsap.set(`${detailsInactive} .cta`, { y: 60 }); 133 134 gsap.set(".progress-sub-foreground", { 135 width: 500 * (1 / order.length) * (active + 1), 136 }); 137 138 rest.forEach((i, index) => { 139 gsap.set(getCard(i), { 140 x: offsetLeft + 400 + index * (cardWidth + gap), 141 y: offsetTop, 142 width: cardWidth, 143 height: cardHeight, 144 zIndex: 30, 145 borderRadius: 10, 146 }); 147 gsap.set(getCardContent(i), { 148 x: offsetLeft + 400 + index * (cardWidth + gap), 149 zIndex: 40, 150 y: offsetTop + cardHeight - 100, 151 }); 152 gsap.set(getSliderItem(i), { x: (index + 1) * numberSize }); 153 }); 154 155 gsap.set(".indicator", { x: -window.innerWidth }); 156 157 const startDelay = 0.6; 158 159 gsap.to(".cover", { 160 x: width + 400, 161 delay: 0.5, 162 ease, 163 onComplete: () => { 164 setTimeout(() => { 165 loop(); 166 }, 500); 167 }, 168 }); 169 rest.forEach((i, index) => { 170 gsap.to(getCard(i), { 171 x: offsetLeft + index * (cardWidth + gap), 172 zIndex: 30, 173 delay: 0.05 * index, 174 ease, 175 delay: startDelay, 176 }); 177 gsap.to(getCardContent(i), { 178 x: offsetLeft + index * (cardWidth + gap), 179 zIndex: 40, 180 delay: 0.05 * index, 181 ease, 182 delay: startDelay, 183 }); 184 }); 185 gsap.to("#pagination", { y: 0, opacity: 1, ease, delay: startDelay }); 186 gsap.to("nav", { y: 0, opacity: 1, ease, delay: startDelay }); 187 gsap.to(detailsActive, { opacity: 1, x: 0, ease, delay: startDelay }); 188} 189 190let clicks = 0; 191 192function step() { 193 return new Promise((resolve) => { 194 order.push(order.shift()); 195 detailsEven = !detailsEven; 196 197 const detailsActive = detailsEven ? "#details-even" : "#details-odd"; 198 const detailsInactive = detailsEven ? "#details-odd" : "#details-even"; 199 200 document.querySelector(`${detailsActive} .place-box .text`).textContent = 201 data[order[0]].place; 202 document.querySelector(`${detailsActive} .title-1`).textContent = 203 data[order[0]].title; 204 document.querySelector(`${detailsActive} .title-2`).textContent = 205 data[order[0]].title2; 206 document.querySelector(`${detailsActive} .desc`).textContent = 207 data[order[0]].description; 208 209 gsap.set(detailsActive, { zIndex: 22 }); 210 gsap.to(detailsActive, { opacity: 1, delay: 0.4, ease }); 211 gsap.to(`${detailsActive} .text`, { 212 y: 0, 213 delay: 0.1, 214 duration: 0.7, 215 ease, 216 }); 217 gsap.to(`${detailsActive} .title-1`, { 218 y: 0, 219 delay: 0.15, 220 duration: 0.7, 221 ease, 222 }); 223 gsap.to(`${detailsActive} .title-2`, { 224 y: 0, 225 delay: 0.15, 226 duration: 0.7, 227 ease, 228 }); 229 gsap.to(`${detailsActive} .desc`, { 230 y: 0, 231 delay: 0.3, 232 duration: 0.4, 233 ease, 234 }); 235 gsap.to(`${detailsActive} .cta`, { 236 y: 0, 237 delay: 0.35, 238 duration: 0.4, 239 onComplete: resolve, 240 ease, 241 }); 242 gsap.set(detailsInactive, { zIndex: 12 }); 243 244 const [active, ...rest] = order; 245 const prv = rest[rest.length - 1]; 246 247 gsap.set(getCard(prv), { zIndex: 10 }); 248 gsap.set(getCard(active), { zIndex: 20 }); 249 gsap.to(getCard(prv), { scale: 1.5, ease }); 250 251 gsap.to(getCardContent(active), { 252 y: offsetTop + cardHeight - 10, 253 opacity: 0, 254 duration: 0.3, 255 ease, 256 }); 257 gsap.to(getSliderItem(active), { x: 0, ease }); 258 gsap.to(getSliderItem(prv), { x: -numberSize, ease }); 259 gsap.to(".progress-sub-foreground", { 260 width: 500 * (1 / order.length) * (active + 1), 261 ease, 262 }); 263 264 gsap.to(getCard(active), { 265 x: 0, 266 y: 0, 267 ease, 268 width: window.innerWidth, 269 height: window.innerHeight, 270 borderRadius: 0, 271 onComplete: () => { 272 const xNew = offsetLeft + (rest.length - 1) * (cardWidth + gap); 273 gsap.set(getCard(prv), { 274 x: xNew, 275 y: offsetTop, 276 width: cardWidth, 277 height: cardHeight, 278 zIndex: 30, 279 borderRadius: 10, 280 scale: 1, 281 }); 282 283 gsap.set(getCardContent(prv), { 284 x: xNew, 285 y: offsetTop + cardHeight - 100, 286 opacity: 1, 287 zIndex: 40, 288 }); 289 gsap.set(getSliderItem(prv), { x: rest.length * numberSize }); 290 291 gsap.set(detailsInactive, { opacity: 0 }); 292 gsap.set(`${detailsInactive} .text`, { y: 100 }); 293 gsap.set(`${detailsInactive} .title-1`, { y: 100 }); 294 gsap.set(`${detailsInactive} .title-2`, { y: 100 }); 295 gsap.set(`${detailsInactive} .desc`, { y: 50 }); 296 gsap.set(`${detailsInactive} .cta`, { y: 60 }); 297 clicks -= 1; 298 if (clicks > 0) { 299 step(); 300 } 301 }, 302 }); 303 304 rest.forEach((i, index) => { 305 if (i !== prv) { 306 const xNew = offsetLeft + index * (cardWidth + gap); 307 gsap.set(getCard(i), { zIndex: 30 }); 308 gsap.to(getCard(i), { 309 x: xNew, 310 y: offsetTop, 311 width: cardWidth, 312 height: cardHeight, 313 ease, 314 delay: 0.1 * (index + 1), 315 }); 316 317 gsap.to(getCardContent(i), { 318 x: xNew, 319 y: offsetTop + cardHeight - 100, 320 opacity: 1, 321 zIndex: 40, 322 ease, 323 delay: 0.1 * (index + 1), 324 }); 325 gsap.to(getSliderItem(i), { x: (index + 1) * numberSize, ease }); 326 } 327 }); 328 }); 329} 330 331async function loop() { 332 await animate(".indicator", 2, { x: 0 }); 333 await animate(".indicator", 0.8, { x: window.innerWidth, delay: 0.3 }); 334 set(".indicator", { x: -window.innerWidth }); 335 await step(); 336 loop(); 337} 338 339async function loadImage(src) { 340 return new Promise((resolve, reject) => { 341 let img = new Image(); 342 img.onload = () => resolve(img); 343 img.onerror = reject; 344 img.src = src; 345 }); 346} 347 348async function loadImages() { 349 const promises = data.map(({ image }) => loadImage(image)); 350 return Promise.all(promises); 351} 352 353async function start() { 354 try { 355 await loadImages(); 356 init(); 357 } catch (error) { 358 console.error("One or more images failed to load", error); 359 } 360} 361 362start() 363

GSAP (GreenSock Animation Platform) provides smooth, high-performance animations.

The code:

Moves the white cover upwards on load.

Continuously animates the progress bar to simulate slide timing.

This can be expanded to automatically change cards or content every few seconds.

Love this component?

Explore more components and build amazing UIs.

View All Components