| 1 | <template id="scene5-logo-outro-template"> |
| 2 | <div |
| 3 | data-composition-id="scene5-logo-outro" |
| 4 | data-width="1920" |
| 5 | data-height="1080" |
| 6 | data-duration="6" |
| 7 | > |
| 8 | <div class="canvas"> |
| 9 | <!-- Glow effect behind the logo --> |
| 10 | <div class="logo-glow"></div> |
| 11 | |
| 12 | <!-- Logo Container --> |
| 13 | <div class="logo-container"> |
| 14 | <svg viewBox="0 0 160 240" width="160" height="240" class="logo-svg"> |
| 15 | <!-- Figma Logo Pieces --> |
| 16 | <!-- Top-left: Red (#F24E1E) --> |
| 17 | <path |
| 18 | class="logo-piece logo-tl" |
| 19 | d="M 0 40 C 0 17.9 17.9 0 40 0 L 80 0 L 80 80 L 40 80 C 17.9 80 0 62.1 0 40 Z" |
| 20 | fill="#F24E1E" |
| 21 | /> |
| 22 | <!-- Top-right: Purple (#A259FF) --> |
| 23 | <path |
| 24 | class="logo-piece logo-tr" |
| 25 | d="M 80 0 L 120 0 C 142.1 0 160 17.9 160 40 C 160 62.1 142.1 80 120 80 L 80 80 L 80 0 Z" |
| 26 | fill="#A259FF" |
| 27 | /> |
| 28 | <!-- Middle-left: Pink (#FF7262) --> |
| 29 | <path |
| 30 | class="logo-piece logo-ml" |
| 31 | d="M 0 120 C 0 97.9 17.9 80 40 80 L 80 80 L 80 160 L 40 160 C 17.9 160 0 142.1 0 120 Z" |
| 32 | fill="#FF7262" |
| 33 | /> |
| 34 | <!-- Middle-right: Blue (#1ABCFE) --> |
| 35 | <circle class="logo-piece logo-mr" cx="120" cy="120" r="40" fill="#1ABCFE" /> |
| 36 | <!-- Bottom-left: Green (#0ACF83) --> |
| 37 | <path |
| 38 | class="logo-piece logo-bl" |
| 39 | d="M 0 200 C 0 177.9 17.9 160 40 160 L 80 160 L 80 200 C 80 222.1 62.1 240 40 240 C 17.9 240 0 222.1 0 200 Z" |
| 40 | fill="#0ACF83" |
| 41 | /> |
| 42 | </svg> |
| 43 | </div> |
| 44 | |
| 45 | <div class="text-container"> |
| 46 | <div class="tagline">Nothing great is made alone.</div> |
| 47 | <div class="url-pill"> |
| 48 | <span class="url-text">figma.com</span> |
| 49 | </div> |
| 50 | </div> |
| 51 | </div> |
| 52 | |
| 53 | <style> |
| 54 | [data-composition-id="scene5-logo-outro"] .canvas { |
| 55 | width: 1920px; |
| 56 | height: 1080px; |
| 57 | background: #0a0a0f; |
| 58 | position: relative; |
| 59 | overflow: hidden; |
| 60 | font-family: "Inter", sans-serif; |
| 61 | } |
| 62 | |
| 63 | [data-composition-id="scene5-logo-outro"] .logo-container { |
| 64 | position: absolute; |
| 65 | left: 880px; /* Center X: 960 - 80 */ |
| 66 | top: 380px; /* Adjusted for tagline space: 540 - 120 - 40 */ |
| 67 | width: 160px; |
| 68 | height: 240px; |
| 69 | z-index: 2; |
| 70 | } |
| 71 | |
| 72 | [data-composition-id="scene5-logo-outro"] .logo-piece { |
| 73 | transform-origin: center center; |
| 74 | opacity: 0; |
| 75 | } |
| 76 | |
| 77 | [data-composition-id="scene5-logo-outro"] .logo-glow { |
| 78 | position: absolute; |
| 79 | left: 760px; /* 960 - 200 */ |
| 80 | top: 300px; /* 500 - 200 */ |
| 81 | width: 400px; |
| 82 | height: 400px; |
| 83 | background: radial-gradient(circle, rgba(162, 89, 255, 0.25) 0%, rgba(10, 10, 15, 0) 70%); |
| 84 | border-radius: 50%; |
| 85 | opacity: 0; |
| 86 | pointer-events: none; |
| 87 | z-index: 1; |
| 88 | } |
| 89 | |
| 90 | [data-composition-id="scene5-logo-outro"] .text-container { |
| 91 | position: absolute; |
| 92 | top: 720px; |
| 93 | width: 100%; |
| 94 | display: flex; |
| 95 | flex-direction: column; |
| 96 | align-items: center; |
| 97 | z-index: 3; |
| 98 | } |
| 99 | |
| 100 | [data-composition-id="scene5-logo-outro"] .tagline { |
| 101 | font-size: 44px; |
| 102 | font-weight: 500; |
| 103 | color: white; |
| 104 | opacity: 0; |
| 105 | margin-bottom: 32px; |
| 106 | text-align: center; |
| 107 | } |
| 108 | |
| 109 | [data-composition-id="scene5-logo-outro"] .url-pill { |
| 110 | background: #1a1a1f; |
| 111 | border: 1px solid #2c2c2c; |
| 112 | border-radius: 100px; |
| 113 | padding: 8px 24px; |
| 114 | opacity: 0; |
| 115 | display: flex; |
| 116 | align-items: center; |
| 117 | justify-content: center; |
| 118 | } |
| 119 | |
| 120 | [data-composition-id="scene5-logo-outro"] .url-text { |
| 121 | font-size: 18px; |
| 122 | color: #666; |
| 123 | letter-spacing: 0.5px; |
| 124 | } |
| 125 | </style> |
| 126 | |
| 127 | <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script> |
| 128 | <script> |
| 129 | (function () { |
| 130 | const tl = gsap.timeline({ paused: true }); |
| 131 | |
| 132 | const pieces = { |
| 133 | tl: '[data-composition-id="scene5-logo-outro"] .logo-tl', |
| 134 | tr: '[data-composition-id="scene5-logo-outro"] .logo-tr', |
| 135 | ml: '[data-composition-id="scene5-logo-outro"] .logo-ml', |
| 136 | mr: '[data-composition-id="scene5-logo-outro"] .logo-mr', |
| 137 | bl: '[data-composition-id="scene5-logo-outro"] .logo-bl', |
| 138 | }; |
| 139 | |
| 140 | const pieceArray = [pieces.tl, pieces.tr, pieces.ml, pieces.mr, pieces.bl]; |
| 141 | const logoGlow = '[data-composition-id="scene5-logo-outro"] .logo-glow'; |
| 142 | const tagline = '[data-composition-id="scene5-logo-outro"] .tagline'; |
| 143 | const urlPill = '[data-composition-id="scene5-logo-outro"] .url-pill'; |
| 144 | |
| 145 | // 1. Pieces slide in from the RIGHT (x: 1920 -> 0) with a ripple stagger (0.08s). Duration: 1.2s. |
| 146 | pieceArray.forEach((piece, i) => { |
| 147 | tl.fromTo( |
| 148 | piece, |
| 149 | { x: 1920, opacity: 0 }, |
| 150 | { x: 0, opacity: 1, duration: 1.2, ease: "power4.out" }, |
| 151 | i * 0.08, |
| 152 | ); |
| 153 | }); |
| 154 | |
| 155 | // 2. Once at the center (960, 540), the pieces should simply EXPAND (scale 1 -> 1.15) |
| 156 | // and then CLOSE back to their done state (scale 1.15 -> 1). |
| 157 | // NO positional 'explode' or pushing to corners. |
| 158 | const expandTime = 1.2; // Start right after the first piece arrives, or after all? |
| 159 | // Let's start it after the last piece has arrived or is near arrival for a fluid motion. |
| 160 | // The last piece starts at 0.32s and takes 1.2s to arrive (1.52s total). |
| 161 | // Let's trigger the expand at 1.2s so it feels like a continuous flow. |
| 162 | |
| 163 | tl.to( |
| 164 | pieceArray, |
| 165 | { |
| 166 | scale: 1.15, |
| 167 | duration: 0.5, |
| 168 | ease: "back.out(1.7)", |
| 169 | stagger: 0.02, |
| 170 | }, |
| 171 | expandTime, |
| 172 | ); |
| 173 | |
| 174 | tl.to( |
| 175 | pieceArray, |
| 176 | { |
| 177 | scale: 1, |
| 178 | duration: 0.4, |
| 179 | ease: "power2.inOut", |
| 180 | }, |
| 181 | expandTime + 0.3, |
| 182 | ); |
| 183 | |
| 184 | // 3. Subtle glow bloom effect (optional but adds polish, keeping it from original as it fits the 'expand') |
| 185 | tl.fromTo( |
| 186 | logoGlow, |
| 187 | { opacity: 0, scale: 0.5 }, |
| 188 | { opacity: 1, scale: 1.2, duration: 0.4, ease: "power2.out" }, |
| 189 | expandTime, |
| 190 | ); |
| 191 | tl.to( |
| 192 | logoGlow, |
| 193 | { |
| 194 | opacity: 0, |
| 195 | scale: 1.8, |
| 196 | duration: 1.2, |
| 197 | ease: "power2.out", |
| 198 | }, |
| 199 | expandTime + 0.4, |
| 200 | ); |
| 201 | |
| 202 | // 4. Tagline and URL pill fade in as before. |
| 203 | const textStartTime = expandTime + 0.8; |
| 204 | tl.fromTo( |
| 205 | tagline, |
| 206 | { opacity: 0, y: 20 }, |
| 207 | { opacity: 1, y: 0, duration: 1, ease: "power3.out" }, |
| 208 | textStartTime, |
| 209 | ); |
| 210 | |
| 211 | tl.fromTo( |
| 212 | urlPill, |
| 213 | { opacity: 0, y: 15 }, |
| 214 | { opacity: 1, y: 0, duration: 0.8, ease: "power3.out" }, |
| 215 | textStartTime + 0.4, |
| 216 | ); |
| 217 | |
| 218 | // 5. Remove the final pulse animation. (Omitted) |
| 219 | // 6. After they return to the done state, there should be NO MORE movement for the logo. (Ensured) |
| 220 | |
| 221 | // Register timeline |
| 222 | window.__timelines = window.__timelines || {}; |
| 223 | window.__timelines["scene5-logo-outro"] = tl; |
| 224 | })(); |
| 225 | </script> |
| 226 | </div> |
| 227 | </template> |
| 228 |