| 1 | <template id="scene1-logo-intro-template"> |
| 2 | <div |
| 3 | data-composition-id="scene1-logo-intro" |
| 4 | data-width="1920" |
| 5 | data-height="1080" |
| 6 | data-duration="1.5" |
| 7 | > |
| 8 | <div class="canvas"> |
| 9 | <!-- Logo Container --> |
| 10 | <div class="logo-container"> |
| 11 | <svg viewBox="0 0 160 240" width="160" height="240"> |
| 12 | <!-- Figma Logo Pieces --> |
| 13 | <!-- Top-left: Red (F24E1E) --> |
| 14 | <path |
| 15 | class="logo-piece logo-tl" |
| 16 | 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" |
| 17 | fill="#F24E1E" |
| 18 | /> |
| 19 | <!-- Top-right: Purple (A259FF) --> |
| 20 | <path |
| 21 | class="logo-piece logo-tr" |
| 22 | 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" |
| 23 | fill="#A259FF" |
| 24 | /> |
| 25 | <!-- Middle-left: Pink (FF7262) --> |
| 26 | <path |
| 27 | class="logo-piece logo-ml" |
| 28 | 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" |
| 29 | fill="#FF7262" |
| 30 | /> |
| 31 | <!-- Middle-right: Blue (1ABCFE) --> |
| 32 | <circle class="logo-piece logo-mr" cx="120" cy="120" r="40" fill="#1ABCFE" /> |
| 33 | <!-- Bottom-left: Green (0ACF83) --> |
| 34 | <path |
| 35 | class="logo-piece logo-bl" |
| 36 | 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" |
| 37 | fill="#0ACF83" |
| 38 | /> |
| 39 | </svg> |
| 40 | </div> |
| 41 | |
| 42 | <!-- Expanding Ring --> |
| 43 | <div class="ring-container"> |
| 44 | <svg viewBox="0 0 400 400" width="400" height="400"> |
| 45 | <circle |
| 46 | class="ring" |
| 47 | cx="200" |
| 48 | cy="200" |
| 49 | r="80" |
| 50 | fill="none" |
| 51 | stroke="#FFFFFF" |
| 52 | stroke-width="4" |
| 53 | /> |
| 54 | </svg> |
| 55 | </div> |
| 56 | </div> |
| 57 | |
| 58 | <style> |
| 59 | [data-composition-id="scene1-logo-intro"] .canvas { |
| 60 | width: 1920px; |
| 61 | height: 1080px; |
| 62 | background-color: #0a0a0f; |
| 63 | position: relative; |
| 64 | overflow: hidden; |
| 65 | } |
| 66 | |
| 67 | [data-composition-id="scene1-logo-intro"] .logo-container { |
| 68 | position: absolute; |
| 69 | left: 880px; /* Center X: 960 - 80 */ |
| 70 | top: 420px; /* Center Y: 540 - 120 */ |
| 71 | width: 160px; |
| 72 | height: 240px; |
| 73 | transform-origin: center center; |
| 74 | } |
| 75 | |
| 76 | [data-composition-id="scene1-logo-intro"] .ring-container { |
| 77 | position: absolute; |
| 78 | left: 760px; /* 960 - 200 */ |
| 79 | top: 340px; /* 540 - 200 */ |
| 80 | width: 400px; |
| 81 | height: 400px; |
| 82 | pointer-events: none; |
| 83 | } |
| 84 | |
| 85 | [data-composition-id="scene1-logo-intro"] .ring { |
| 86 | transform-origin: center center; |
| 87 | opacity: 0; |
| 88 | } |
| 89 | </style> |
| 90 | |
| 91 | <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script> |
| 92 | <script> |
| 93 | (function () { |
| 94 | const tl = gsap.timeline({ paused: true }); |
| 95 | |
| 96 | const pieces = { |
| 97 | tl: '[data-composition-id="scene1-logo-intro"] .logo-tl', |
| 98 | tr: '[data-composition-id="scene1-logo-intro"] .logo-tr', |
| 99 | ml: '[data-composition-id="scene1-logo-intro"] .logo-ml', |
| 100 | mr: '[data-composition-id="scene1-logo-intro"] .logo-mr', |
| 101 | bl: '[data-composition-id="scene1-logo-intro"] .logo-bl', |
| 102 | }; |
| 103 | |
| 104 | const ring = '[data-composition-id="scene1-logo-intro"] .ring'; |
| 105 | const logoContainer = '[data-composition-id="scene1-logo-intro"] .logo-container'; |
| 106 | |
| 107 | // Initial positions: Corners of the screen |
| 108 | // Viewport is 1920x1080. Center is 960, 540. |
| 109 | // logo-container is at 880, 420. |
| 110 | |
| 111 | tl.set(pieces.tl, { x: -960, y: -540 }); |
| 112 | tl.set(pieces.tr, { x: 960, y: -540 }); |
| 113 | tl.set(pieces.ml, { x: -960, y: 0 }); |
| 114 | tl.set(pieces.mr, { x: 960, y: 0 }); |
| 115 | tl.set(pieces.bl, { x: -960, y: 540 }); |
| 116 | |
| 117 | // 1. Converge to center with 3-frame stagger (approx 0.05s at 60fps) |
| 118 | // 2. Collide with slight bounce (overshoot 1.1x) |
| 119 | const convergeDuration = 0.6; |
| 120 | const stagger = 0.05; |
| 121 | |
| 122 | const pieceArray = [pieces.tl, pieces.tr, pieces.ml, pieces.mr, pieces.bl]; |
| 123 | |
| 124 | pieceArray.forEach((piece, i) => { |
| 125 | tl.to( |
| 126 | piece, |
| 127 | { |
| 128 | x: 0, |
| 129 | y: 0, |
| 130 | duration: convergeDuration, |
| 131 | ease: "back.out(1.1)", |
| 132 | }, |
| 133 | i * stagger, |
| 134 | ); |
| 135 | }); |
| 136 | |
| 137 | // 3. On collision (approx at 0.6 + 4*0.05 = 0.8s), white ring expands |
| 138 | const collisionTime = convergeDuration + (pieceArray.length - 1) * stagger; |
| 139 | |
| 140 | tl.fromTo( |
| 141 | ring, |
| 142 | { scale: 0.2, opacity: 1 }, |
| 143 | { |
| 144 | scale: 2.5, |
| 145 | opacity: 0, |
| 146 | duration: 0.4, |
| 147 | ease: "power2.out", |
| 148 | }, |
| 149 | collisionTime, |
| 150 | ); |
| 151 | |
| 152 | // 4. Logo pulses slightly |
| 153 | tl.to( |
| 154 | logoContainer, |
| 155 | { |
| 156 | scale: 1.05, |
| 157 | duration: 0.15, |
| 158 | ease: "power2.out", |
| 159 | }, |
| 160 | collisionTime, |
| 161 | ); |
| 162 | |
| 163 | tl.to( |
| 164 | logoContainer, |
| 165 | { |
| 166 | scale: 1, |
| 167 | duration: 0.15, |
| 168 | ease: "power2.in", |
| 169 | }, |
| 170 | collisionTime + 0.15, |
| 171 | ); |
| 172 | |
| 173 | // 5. Scale down to 0 |
| 174 | tl.to( |
| 175 | logoContainer, |
| 176 | { |
| 177 | scale: 0, |
| 178 | duration: 0.3, |
| 179 | ease: "expo.in", |
| 180 | delay: 0.1, |
| 181 | }, |
| 182 | collisionTime + 0.3, |
| 183 | ); |
| 184 | |
| 185 | window.__timelines = window.__timelines || {}; |
| 186 | window.__timelines["scene1-logo-intro"] = tl; |
| 187 | })(); |
| 188 | </script> |
| 189 | </div> |
| 190 | </template> |
| 191 |