TweenLabs LogoTweenLabs
TweenLabs/Components/Source Code

Gravity Drop Code

Endpoint: /01-gravity-drop

Staggered letters falling down onto a shelf collider with realistic physics bounce.

📦 GSAP: ^3.15.0
📦 @gsap/react: ^2.1.2
⚙️ ScrollTrigger: ❌ Not Used
page.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
"use client";

import { useGSAP } from "@gsap/react";
import gsap from "gsap";
import { useRef, useState } from "react";

gsap.registerPlugin(useGSAP);

export default function AnimationOnePage() {
  const containerRef = useRef<HTMLDivElement>(null);
  const [textInput, setTextInput] = useState("GRAVITY DROP");
  const [triggerKey, setTriggerKey] = useState(0);

  useGSAP(
    () => {
      // Animate the letters falling down
      gsap.fromTo(
        ".falling-letter",
        {
          y: -400,
          rotation: () => gsap.utils.random(-90, 90),
          opacity: 0,
          scale: 2,
        },
        {
          y: 0,
          rotation: 0,
          opacity: 1,
          scale: 1,
          duration: 1.2,
          stagger: {
            each: 0.08,
            from: "random",
          },
          ease: "bounce.out",
        },
      );
    },
    { scope: containerRef, dependencies: [triggerKey] },
  );

  const handleReplay = () => {
    setTriggerKey((prev) => prev + 1);
  };

  return (
    <div
      className="relative min-h-screen bg-[#f0eadf] text-[#2a2a2a] flex flex-col items-center justify-center p-4 selection:bg-wtf-yellow selection:text-black"
      ref={containerRef}
    >
      <div className="absolute inset-0 dot-grid pointer-events-none z-0" />

      <div className="z-10 w-full max-w-2xl brutalist-card p-8 bg-white flex flex-col gap-8 text-center relative overflow-hidden">
        {/* Header tag */}
        <div className="inline-flex self-center items-center gap-2 bg-wtf-orange border-2 border-[#2a2a2a] px-4 py-1.5 rounded-full text-[10px] font-mono font-bold text-white uppercase tracking-widest shadow-[3px_3px_0px_#2a2a2a] tilt-right">
          <span>Gravity Drop Sandbox</span>
        </div>

        {/* Shelf container where text lands */}
        <div className="relative min-h-[160px] flex items-center justify-center border-b-4 border-[#2a2a2a] pb-4 bg-zinc-50 rounded-lg shadow-inner">
          <div className="absolute top-2 left-2 font-mono text-[9px] text-zinc-400">
            SHELF COLLIDER
          </div>
          <h1 className="text-5xl md:text-7xl font-serif font-black tracking-tight flex flex-wrap justify-center gap-x-2">
            {textInput.split(" ").map((word, wordIdx) => (
              <span key={wordIdx} className="inline-block whitespace-nowrap">
                {word.split("").map((char, charIdx) => (
                  <span
                    key={charIdx}
                    className="falling-letter inline-block transform origin-bottom font-black text-wtf-orange will-change-transform"
                    style={{ textShadow: "2px 2px 0px #2a2a2a" }}
                  >
                    {char}
                  </span>
                ))}
              </span>
            ))}
          </h1>
        </div>

        {/* User Controls */}
        <div className="flex flex-col md:flex-row gap-4 justify-center items-center">
          <input
            type="text"
            maxLength={20}
            value={textInput}
            onChange={(e) => setTextInput(e.target.value.toUpperCase())}
            placeholder="TYPE TEXT HERE"
            className="w-full md:w-64 border-3 border-[#2a2a2a] px-4 py-2.5 font-mono font-bold rounded-lg focus:outline-none focus:bg-yellow-50 placeholder-zinc-400 shadow-[3px_3px_0px_#2a2a2a]"
          />
          <div className="flex gap-3 w-full md:w-auto">
            <button
              onClick={handleReplay}
              className="flex-1 md:flex-none brutalist-btn bg-wtf-orange text-white font-mono font-bold text-sm py-3 px-6 rounded-lg uppercase tracking-wider cursor-pointer"
            >
              ☄️ Trigger Drop
            </button>
            <div className="flex-1 md:flex-none">
              <button
                onClick={() =>
                  window.history.length > 1
                    ? window.history.back()
                    : (window.location.href = "/")
                }
                className="w-full brutalist-btn bg-wtf-yellow text-[#2a2a2a] font-mono font-bold text-sm py-3 px-6 rounded-lg uppercase tracking-wider cursor-pointer"
              >
                ← Back
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
master*0 ⓧ0 ⚠
Ln 116, Col 1Spaces: 2UTF-8TypeScript JSXPrettier

⚙️ Setup & Integration Guide

How to install, import, and configure this animation in your project

💻

Option A: Install via CLI (Recommended)

You can install this component directly into your project via the TweenLabs CLI. It automatically creates the file and configures dependencies:

npx tweenlabs add gravity-drop

Option B: Manual Installation

Follow these steps to integrate the component into your project manually:

1

Install Packages

First, install GSAP and its official React hook helper library (@gsap/react).

npm install gsap @gsap/react
2

Add Required CSS Styles

Copy the styles from the Required CSS tab above, or open the styles.css file that was automatically downloaded with your component. Paste these classes into your global stylesheet (e.g. src/app/globals.css or similar).

3

Create Component File

Create a new file in your React or Next.js project (e.g. src/components/GravityDrop.tsx) and paste the code from the Standalone React Component tab above. If no standalone tab is available, copy the full page file code and adjust the routing logic for your needs.

4

Import & Render

Import and render the component in your page or view layout:

App Page
import GravityDrop from "@/components/GravityDrop";

export default function Page() {
  return (
    <main className="min-h-screen p-8 bg-[#f5f5f5] flex items-center justify-center">
      <GravityDrop />
    </main>
  );
}
💡

Customization & Component Properties

🛠️ Customization & Component Properties (Props)

You can pass the following settings to configure the layout and animation details:

  • initialText (string): The text characters to drop and bounce. Defaults to 'GRAVITY DROP'.