A free animated delivery truck button where clicking triggers a full GSAP timeline: the truck drives in on a moving road, stops with a suspension bounce, opens its door with sparks, drops a FRAGILE package, then drives away. No images — pure CSS divs. GSAP 3. Copy-paste ready.
🚛Entry + Road
→
💨Bounce + Dust
→
✨Door + Sparks
→
📦Package Drop
→
🔧Detach + Close
→
💨Exit + Reset
GSAP 3 Timelinebounce.out easegsap.set / tl.callCSS div truck (no images)repeating-linear-gradient roadanimation-play-state togglegetBoundingClientRect detach
Windows Tip: After downloading → right-click folder → Properties → check "Unblock" → Apply → OK.
Cinematic Truck Button by Coodeverse is a free animated delivery truck button built with pure HTML, CSS, and GSAP 3. Clicking triggers a cinematic GSAP timeline: a CSS div-based truck (no images) drives across an animated road, stops with a suspension bounce.out, opens its door with JavaScript sparks, drops a FRAGILE package with 720° rotation, detaches the package via getBoundingClientRect coordinate repositioning, closes the door, and drives off screen. Full source code free at coodeverse.com/projects/cinematic-truck-button.
⚡Engine:GSAP 3 Timeline
·
🚛Truck:Pure CSS Divs — Zero Images
·
🎬Stages:6 Cinematic Stages
·
📦Package:FRAGILE Drop + 720° Spin
·
🖼️Images:None Required
Live Preview — Click the Button!
🎬 All 6 Stages — Technical Reference
Every GSAP call, CSS technique, and JavaScript function behind each cinematic stage.
① GSAP + CSS
Entry + Road
GSAP moves truck left:-120 to left:110 using power2.inOut over 1.6s. Road .road-mini uses repeating-linear-gradient with @keyframes roadMove shifting background-position by 39px (one pattern width). JavaScript adds class .moving to toggle animation-play-state from paused to running.
Two tl.to calls create the bounce. First: y:-7, rotationZ:-1 with power2.out at 0.22s — the overshoot up. Second: y:0, rotationZ:0 with bounce.out at 0.28s — the settle. Five exhaust .exhaust divs are created in a loop with staggered gsap.set and gsap.to calls scaling up and fading out.
GSAP animates .truck-door to rotationY:-115deg over 0.75s with power2.inOut. The door's transform-origin: left center makes it hinge from the left edge. createSparks helper fires 6 spark divs using CSS --dx/--dy custom properties calculated from Math.random() * 360 angle and 12–30px distance.
Box opacity is set to 1 with tl.set. GSAP animates top from 12 to 34 with rotation:720 (two full spins) and bounce.out over 0.6s, simulating gravity and impact. Impact sparks fire on onStart. Dust particles called with tl.call. The FRAGILE text label uses 3.2px font with diagonal rotation.
In tl.call, getBoundingClientRect gets the box's current screen position. btn.appendChild(box) moves it from truck's DOM to button's DOM. gsap.set repositions it using coordinate difference: x = bx.left - b.left, y = bx.top - b.top. This seamlessly transfers coordinate spaces while the box visually stays in place as the truck exits.
Truck drives to left:370 (off right edge) with power1.inOut over 1.5s. Button scale resets to 1 with power2.out. In timeline onComplete: btn.disabled = false, text.style.opacity = 1, road.classList.remove('moving') to pause the road. gsap.set resets all positions for the next click.
How the CSS truck, GSAP timeline, road animation, package detach, and sparks work.
The truck is entirely HTML divs with CSS styling. The red cab uses linear-gradient with perspective(250px) rotateY(-7deg) for the 3D angle. The windshield is a ::before pseudo-element with a blue gradient. The cargo body uses a blue gradient with perspective. Wheels use radial-gradient for the rubber look and repeating-conic-gradient with a radial mask for tread. Headlights use radial-gradient(#fff, #ffeb3b, #ffb300) with glowing box-shadow. The FRAGILE box uses diagonal repeating-linear-gradient for wood grain. Zero images, zero SVG — pure CSS.
A GSAP timeline chains every stage. gsap.set resets positions before each click. tl.to moves the truck with power2.inOut. Position strings like '-=0.35' create overlap between stages for cinematic timing. The suspension uses two tl.to calls: y:-7 with power2.out (overshoot up) then y:0 with bounce.out (settle). Door uses rotationY:-115. Package uses rotation:720 and bounce.out. tl.call() runs JavaScript at exact timeline moments. The timeline's onComplete resets the button.
The .road-mini uses repeating-linear-gradient to draw asphalt with yellow dash markings at 39px intervals. @keyframes roadMove shifts background-position from 0 to 39px, creating the scrolling road illusion. The animation starts in paused state via animation: roadMove 0.45s linear infinite paused. JavaScript adds the .moving class on click, which sets animation-play-state: running via the CSS selector .moving .road-mini. The wheel spin @keyframes also activates via .moving .truck-wheel. On timeline completion, .moving is removed.
In tl.call, three steps happen: (1) btn.appendChild(box) moves the .box element from the truck's DOM to the button's DOM. (2) getBoundingClientRect() captures the box's screen position before and after the parent change. (3) gsap.set repositions it using the coordinate difference: x = bx.left - b.left, y = bx.top - b.top, with left and top set to 'auto'. This transfers the element between coordinate systems while maintaining its exact visual position, so the box stays where it landed while the truck drives away.
createSparks creates 6 .spark divs. Each gets CSS custom properties --dx and --dy from a random angle (Math.random() * 360) and distance (12–30px): Math.cos(angle)*distance and Math.sin(angle)*distance. The spark is positioned at the source element's center relative to the container using getBoundingClientRect. The CSS @keyframes spark uses transform: translate(var(--dx), var(--dy)) scale(0) to move each spark in its unique direction while shrinking to nothing. setTimeout removes each after 700ms.
Yes. It works perfectly for add-to-cart confirmations, shipping notifications, order tracking, and delivery confirmation CTAs. Replace 'DELIVER PACKAGE' with 'Add to Cart' or 'Place Order'. Add your checkout API call inside the tl.onComplete callback after btn.disabled = false. The button automatically disables during animation to prevent double-clicks. Consider reducing timeline durations by 30–40% for a snappier e-commerce feel. The frosted glass button style matches premium dark-themed storefronts.