Introduce Particles Header

This commit is contained in:
Alexander Zinchuk 2025-07-29 14:33:44 +02:00
parent 02ada70d43
commit c6c2336a66
21 changed files with 1151 additions and 276 deletions

View File

@ -0,0 +1,18 @@
<svg width="88" height="84" viewBox="0 0 88 84" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M40.908 69.9386L21.33 81.9306C20.7381 82.293 20.0517 82.4706 19.3584 82.4409C18.665 82.4112 17.9963 82.1755 17.4376 81.7638C16.8789 81.3522 16.4556 80.7833 16.2218 80.1299C15.988 79.4765 15.9543 78.7683 16.125 78.0956L19.155 66.1666C19.6658 64.1578 20.6111 62.2854 21.9243 60.6817C23.2374 59.0779 24.8864 57.7817 26.755 56.8846L48.113 46.6296C48.7285 46.3329 49.2161 45.8238 49.4859 45.196C49.7558 44.5683 49.7897 43.8642 49.5816 43.2134C49.3734 42.5626 48.9371 42.0089 48.353 41.6543C47.769 41.2997 47.0764 41.1681 46.403 41.2836L22.629 45.3996C18.037 46.1946 13.329 44.9266 9.758 41.9336L2.247 35.6396C1.71618 35.1943 1.32991 34.6011 1.13741 33.9355C0.944901 33.2699 0.954871 32.5621 1.16605 31.9022C1.37722 31.2422 1.78004 30.6601 2.3232 30.23C2.86636 29.7998 3.52527 29.541 4.216 29.4866L27.163 27.6906C28.1114 27.6161 29.0206 27.2809 29.7904 26.722C30.5602 26.1631 31.1605 25.4023 31.525 24.5236L40.377 3.15362C40.6413 2.51611 41.0886 1.97125 41.6624 1.58792C42.2363 1.2046 42.9109 1 43.601 1C44.2911 1 44.9657 1.2046 45.5396 1.58792C46.1134 1.97125 46.5607 2.51611 46.825 3.15362L55.677 24.5236C56.0415 25.4023 56.6418 26.1631 57.4116 26.722C58.1814 27.2809 59.0907 27.6161 60.039 27.6906L83.112 29.4966C83.8003 29.5507 84.4571 29.8078 84.9992 30.2352C85.5414 30.6626 85.9446 31.2413 86.1579 31.8979C86.3711 32.5546 86.3848 33.2597 86.1972 33.9241C86.0096 34.5886 85.6292 35.1824 85.104 35.6306L67.507 50.6336C66.7828 51.2516 66.2436 52.0579 65.9493 52.9633C65.6549 53.8687 65.6167 54.8379 65.839 55.7636L71.249 78.2376C71.4104 78.9088 71.3691 79.6127 71.1303 80.2604C70.8916 80.908 70.4662 81.4704 69.9079 81.8763C69.3496 82.2821 68.6834 82.5134 67.9937 82.5407C67.304 82.568 66.6217 82.3901 66.033 82.0296L46.294 69.9386C45.4833 69.4426 44.5514 69.1801 43.601 69.1801C42.6506 69.1801 41.7187 69.4426 40.908 69.9386Z" fill="url(#paint0_linear_1_48)"/>
<path style="mix-blend-mode:soft-light" d="M40.908 69.9386L21.33 81.9306C20.7381 82.293 20.0517 82.4706 19.3584 82.4409C18.665 82.4112 17.9963 82.1755 17.4376 81.7638C16.8789 81.3522 16.4556 80.7833 16.2218 80.1299C15.988 79.4765 15.9543 78.7683 16.125 78.0956L19.155 66.1666C19.6658 64.1578 20.6111 62.2854 21.9243 60.6817C23.2374 59.0779 24.8864 57.7817 26.755 56.8846L48.113 46.6296C48.7285 46.3329 49.2161 45.8238 49.4859 45.196C49.7558 44.5683 49.7897 43.8642 49.5816 43.2134C49.3734 42.5626 48.9371 42.0089 48.353 41.6543C47.769 41.2997 47.0764 41.1681 46.403 41.2836L22.629 45.3996C18.037 46.1946 13.329 44.9266 9.758 41.9336L2.247 35.6396C1.71618 35.1943 1.32991 34.6011 1.13741 33.9355C0.944901 33.2699 0.954871 32.5621 1.16605 31.9022C1.37722 31.2422 1.78004 30.6601 2.3232 30.23C2.86636 29.7998 3.52527 29.541 4.216 29.4866L27.163 27.6906C28.1114 27.6161 29.0206 27.2809 29.7904 26.722C30.5602 26.1631 31.1605 25.4023 31.525 24.5236L40.377 3.15362C40.6413 2.51611 41.0886 1.97125 41.6624 1.58792C42.2363 1.2046 42.9109 1 43.601 1C44.2911 1 44.9657 1.2046 45.5396 1.58792C46.1134 1.97125 46.5607 2.51611 46.825 3.15362L55.677 24.5236C56.0415 25.4023 56.6418 26.1631 57.4116 26.722C58.1814 27.2809 59.0907 27.6161 60.039 27.6906L83.112 29.4966C83.8003 29.5507 84.4571 29.8078 84.9992 30.2352C85.5414 30.6626 85.9446 31.2413 86.1579 31.8979C86.3711 32.5546 86.3848 33.2597 86.1972 33.9241C86.0096 34.5886 85.6292 35.1824 85.104 35.6306L67.507 50.6336C66.7828 51.2516 66.2436 52.0579 65.9493 52.9633C65.6549 53.8687 65.6167 54.8379 65.839 55.7636L71.249 78.2376C71.4104 78.9088 71.3691 79.6127 71.1303 80.2604C70.8916 80.908 70.4662 81.4704 69.9079 81.8763C69.3496 82.2821 68.6834 82.5134 67.9937 82.5407C67.304 82.568 66.6217 82.3901 66.033 82.0296L46.294 69.9386C45.4833 69.4426 44.5514 69.1801 43.601 69.1801C42.6506 69.1801 41.7187 69.4426 40.908 69.9386Z" stroke="url(#paint1_linear_1_48)" stroke-width="1.667"/>
<defs>
<linearGradient id="paint0_linear_1_48" x1="-7.399" y1="101.459" x2="80.17" y2="-5.03838" gradientUnits="userSpaceOnUse">
<stop stop-color="#FDEB32"/>
<stop offset="0.439" stop-color="#FEBD04"/>
<stop offset="1" stop-color="#D75902"/>
</linearGradient>
<linearGradient id="paint1_linear_1_48" x1="94.018" y1="26.1256" x2="43.664" y2="41.7716" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.396" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.521" stop-color="white"/>
<stop offset="0.646" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -0,0 +1,10 @@
<svg width="86" height="82" viewBox="0 0 86 82" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M39.908 68.9386L20.33 80.9306C19.7381 81.293 19.0517 81.4706 18.3584 81.4409C17.665 81.4112 16.9963 81.1755 16.4376 80.7638C15.8789 80.3522 15.4556 79.7833 15.2218 79.1299C14.988 78.4765 14.9543 77.7683 15.125 77.0956L18.155 65.1666C18.6658 63.1578 19.6111 61.2854 20.9243 59.6817C22.2374 58.0779 23.8864 56.7817 25.755 55.8846L47.113 45.6296C47.7285 45.3329 48.2161 44.8238 48.4859 44.196C48.7558 43.5683 48.7897 42.8642 48.5816 42.2134C48.3734 41.5626 47.9371 41.0089 47.353 40.6543C46.769 40.2997 46.0764 40.1681 45.403 40.2836L21.629 44.3996C17.037 45.1946 12.329 43.9266 8.758 40.9336L1.247 34.6396C0.716175 34.1943 0.32991 33.6011 0.137406 32.9355C-0.0550987 32.2699 -0.0451286 31.5621 0.166046 30.9022C0.377221 30.2422 0.780042 29.6601 1.3232 29.23C1.86636 28.7998 2.52527 28.541 3.216 28.4866L26.163 26.6906C27.1114 26.6161 28.0206 26.2809 28.7904 25.722C29.5602 25.1631 30.1605 24.4023 30.525 23.5236L39.377 2.15362C39.6413 1.51611 40.0886 0.971254 40.6624 0.587925C41.2363 0.204595 41.9109 0 42.601 0C43.2911 0 43.9657 0.204595 44.5396 0.587925C45.1134 0.971254 45.5607 1.51611 45.825 2.15362L54.677 23.5236C55.0415 24.4023 55.6418 25.1631 56.4116 25.722C57.1814 26.2809 58.0907 26.6161 59.039 26.6906L82.112 28.4966C82.8003 28.5507 83.4571 28.8078 83.9992 29.2352C84.5414 29.6626 84.9446 30.2413 85.1579 30.8979C85.3711 31.5546 85.3848 32.2597 85.1972 32.9241C85.0096 33.5886 84.6292 34.1824 84.104 34.6306L66.507 49.6336C65.7828 50.2516 65.2436 51.0579 64.9493 51.9633C64.6549 52.8687 64.6167 53.8379 64.839 54.7636L70.249 77.2376C70.4104 77.9088 70.3691 78.6127 70.1303 79.2604C69.8916 79.908 69.4662 80.4704 68.9079 80.8763C68.3496 81.2821 67.6834 81.5134 66.9937 81.5407C66.304 81.568 65.6217 81.3901 65.033 81.0296L45.294 68.9386C44.4833 68.4426 43.5514 68.1801 42.601 68.1801C41.6506 68.1801 40.7187 68.4426 39.908 68.9386Z" fill="url(#paint0_linear_16_52)"/>
<defs>
<linearGradient id="paint0_linear_16_52" x1="-8.399" y1="100.459" x2="79.17" y2="-6.03838" gradientUnits="userSpaceOnUse">
<stop stop-color="#FDEB32"/>
<stop offset="0.439" stop-color="#FEBD04"/>
<stop offset="1" stop-color="#D75902"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="88" height="84" fill="none"><path fill="#fff" d="M41.307 70.48 21.729 82.472a3.49 3.49 0 0 1-5.205-3.835l3.03-11.929a14.17 14.17 0 0 1 7.6-9.282l21.358-10.255a2.834 2.834 0 0 0-1.71-5.346l-23.774 4.116c-4.592.795-9.3-.473-12.871-3.466l-7.511-6.294a3.49 3.49 0 0 1 1.969-6.153l22.947-1.796a5.16 5.16 0 0 0 4.362-3.167l8.852-21.37a3.49 3.49 0 0 1 6.448 0l8.852 21.37a5.16 5.16 0 0 0 4.362 3.167l23.073 1.806a3.49 3.49 0 0 1 1.992 6.134L67.906 51.175a5.16 5.16 0 0 0-1.668 5.13l5.41 22.474a3.49 3.49 0 0 1-5.216 3.792L46.693 70.48a5.16 5.16 0 0 0-5.386 0"/><path fill="url(#a)" d="M41.307 70.48 21.729 82.472a3.49 3.49 0 0 1-5.205-3.835l3.03-11.929a14.17 14.17 0 0 1 7.6-9.282l21.358-10.255a2.834 2.834 0 0 0-1.71-5.346l-23.774 4.116c-4.592.795-9.3-.473-12.871-3.466l-7.511-6.294a3.49 3.49 0 0 1 1.969-6.153l22.947-1.796a5.16 5.16 0 0 0 4.362-3.167l8.852-21.37a3.49 3.49 0 0 1 6.448 0l8.852 21.37a5.16 5.16 0 0 0 4.362 3.167l23.073 1.806a3.49 3.49 0 0 1 1.992 6.134L67.906 51.175a5.16 5.16 0 0 0-1.668 5.13l5.41 22.474a3.49 3.49 0 0 1-5.216 3.792L46.693 70.48a5.16 5.16 0 0 0-5.386 0"/><path fill="url(#b)" d="M41.307 70.48 21.729 82.472a3.49 3.49 0 0 1-5.205-3.835l3.03-11.929a14.17 14.17 0 0 1 7.6-9.282l21.358-10.255a2.834 2.834 0 0 0-1.71-5.346l-23.774 4.116c-4.592.795-9.3-.473-12.871-3.466l-7.511-6.294a3.49 3.49 0 0 1 1.969-6.153l22.947-1.796a5.16 5.16 0 0 0 4.362-3.167l8.852-21.37a3.49 3.49 0 0 1 6.448 0l8.852 21.37a5.16 5.16 0 0 0 4.362 3.167l23.073 1.806a3.49 3.49 0 0 1 1.992 6.134L67.906 51.175a5.16 5.16 0 0 0-1.668 5.13l5.41 22.474a3.49 3.49 0 0 1-5.216 3.792L46.693 70.48a5.16 5.16 0 0 0-5.386 0"/><path stroke="url(#c)" stroke-width="1.667" d="M41.307 70.48 21.729 82.472a3.49 3.49 0 0 1-5.205-3.835l3.03-11.929a14.17 14.17 0 0 1 7.6-9.282l21.358-10.255a2.834 2.834 0 0 0-1.71-5.346l-23.774 4.116c-4.592.795-9.3-.473-12.871-3.466l-7.511-6.294a3.49 3.49 0 0 1 1.969-6.153l22.947-1.796a5.16 5.16 0 0 0 4.362-3.167l8.852-21.37a3.49 3.49 0 0 1 6.448 0l8.852 21.37a5.16 5.16 0 0 0 4.362 3.167l23.073 1.806a3.49 3.49 0 0 1 1.992 6.134L67.906 51.175a5.16 5.16 0 0 0-1.668 5.13l5.41 22.474a3.49 3.49 0 0 1-5.216 3.792L46.693 70.48a5.16 5.16 0 0 0-5.386 0Z" style="mix-blend-mode:soft-light"/><defs><linearGradient id="a" x1="3" x2="84.148" y1="63.5" y2="-1.323" gradientUnits="userSpaceOnUse"><stop stop-color="#6B93FF"/><stop offset=".439" stop-color="#976FFF"/><stop offset="1" stop-color="#E46ACE"/></linearGradient><linearGradient id="b" x1="-7" x2="80.569" y1="102" y2="-4.497" gradientUnits="userSpaceOnUse"><stop stop-color="#FDEB32"/><stop offset=".439" stop-color="#FEBD04"/><stop offset="1" stop-color="#D75902"/></linearGradient><linearGradient id="c" x1="94.417" x2="44.063" y1="26.667" y2="42.313" gradientUnits="userSpaceOnUse"><stop stop-color="#fff" stop-opacity="0"/><stop offset=".396" stop-color="#fff" stop-opacity=".85"/><stop offset=".521" stop-color="#fff"/><stop offset=".646" stop-color="#fff" stop-opacity=".85"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient></defs></svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -1,181 +0,0 @@
<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M47.3065 75.4791L27.7285 87.4727C26.0852 88.4794 23.9369 87.9633 22.9303 86.32C22.4386 85.5175 22.292 84.5503 22.5238 83.638L25.5544 71.7092C26.5877 67.6424 29.3706 64.2428 33.1533 62.4267L54.512 52.172C55.9226 51.4947 56.5171 49.8021 55.8398 48.3915C55.2914 47.2491 54.051 46.6098 52.8023 46.826L29.0274 50.942C24.4362 51.7369 19.7279 50.4691 16.1566 47.4762L8.6459 41.182C7.16885 39.9442 6.97491 37.7434 8.21272 36.2664C8.81474 35.548 9.68047 35.102 10.6149 35.0289L33.5623 33.233C35.496 33.0817 37.1812 31.8579 37.9235 30.066L46.7762 8.69618C47.5137 6.91577 49.5549 6.07037 51.3354 6.80793C52.1903 7.16207 52.8695 7.84129 53.2236 8.69618L62.0763 30.066C62.8186 31.8579 64.5038 33.0817 66.4375 33.233L89.511 35.0387C91.4322 35.1891 92.8678 36.8685 92.7175 38.7897C92.6451 39.714 92.208 40.5714 91.5025 41.1729L73.9053 56.1749C72.4277 57.4345 71.7831 59.4175 72.2375 61.3053L77.6474 83.7792C78.0984 85.6528 76.9452 87.5373 75.0716 87.9883C74.1713 88.205 73.2218 88.055 72.4322 87.5713L52.6933 75.4791C51.0404 74.4666 48.9594 74.4666 47.3065 75.4791Z" fill="white"/>
<path d="M47.3065 75.4791L27.7285 87.4727C26.0852 88.4794 23.9369 87.9633 22.9303 86.32C22.4386 85.5175 22.292 84.5503 22.5238 83.638L25.5544 71.7092C26.5877 67.6424 29.3706 64.2428 33.1533 62.4267L54.512 52.172C55.9226 51.4947 56.5171 49.8021 55.8398 48.3915C55.2914 47.2491 54.051 46.6098 52.8023 46.826L29.0274 50.942C24.4362 51.7369 19.7279 50.4691 16.1566 47.4762L8.6459 41.182C7.16885 39.9442 6.97491 37.7434 8.21272 36.2664C8.81474 35.548 9.68047 35.102 10.6149 35.0289L33.5623 33.233C35.496 33.0817 37.1812 31.8579 37.9235 30.066L46.7762 8.69618C47.5137 6.91577 49.5549 6.07037 51.3354 6.80793C52.1903 7.16207 52.8695 7.84129 53.2236 8.69618L62.0763 30.066C62.8186 31.8579 64.5038 33.0817 66.4375 33.233L89.511 35.0387C91.4322 35.1891 92.8678 36.8685 92.7175 38.7897C92.6451 39.714 92.208 40.5714 91.5025 41.1729L73.9053 56.1749C72.4277 57.4345 71.7831 59.4175 72.2375 61.3053L77.6474 83.7792C78.0984 85.6528 76.9452 87.5373 75.0716 87.9883C74.1713 88.205 73.2218 88.055 72.4322 87.5713L52.6933 75.4791C51.0404 74.4666 48.9594 74.4666 47.3065 75.4791Z" fill="url(#paint0_linear_124_4926)"/>
<path d="M47.3065 75.4791L27.7285 87.4727C26.0852 88.4794 23.9369 87.9633 22.9303 86.32C22.4386 85.5175 22.292 84.5503 22.5238 83.638L25.5544 71.7092C26.5877 67.6424 29.3706 64.2428 33.1533 62.4267L54.512 52.172C55.9226 51.4947 56.5171 49.8021 55.8398 48.3915C55.2914 47.2491 54.051 46.6098 52.8023 46.826L29.0274 50.942C24.4362 51.7369 19.7279 50.4691 16.1566 47.4762L8.6459 41.182C7.16885 39.9442 6.97491 37.7434 8.21272 36.2664C8.81474 35.548 9.68047 35.102 10.6149 35.0289L33.5623 33.233C35.496 33.0817 37.1812 31.8579 37.9235 30.066L46.7762 8.69618C47.5137 6.91577 49.5549 6.07037 51.3354 6.80793C52.1903 7.16207 52.8695 7.84129 53.2236 8.69618L62.0763 30.066C62.8186 31.8579 64.5038 33.0817 66.4375 33.233L89.511 35.0387C91.4322 35.1891 92.8678 36.8685 92.7175 38.7897C92.6451 39.714 92.208 40.5714 91.5025 41.1729L73.9053 56.1749C72.4277 57.4345 71.7831 59.4175 72.2375 61.3053L77.6474 83.7792C78.0984 85.6528 76.9452 87.5373 75.0716 87.9883C74.1713 88.205 73.2218 88.055 72.4322 87.5713L52.6933 75.4791C51.0404 74.4666 48.9594 74.4666 47.3065 75.4791Z" stroke="url(#paint1_linear_124_4926)" stroke-width="1.66667" style="mix-blend-mode:soft-light"/>
<g opacity="0.3">
<path d="M87.1958 21.9339C87.1162 22.1962 87.0513 22.4925 86.9933 22.8247C86.9318 22.4938 86.8645 22.1997 86.7836 21.9402C86.6432 21.4904 86.4523 21.1117 86.1497 20.81C85.8465 20.5076 85.4699 20.3211 85.026 20.1879C84.7934 20.1181 84.5335 20.0605 84.245 20.0089C85.0724 19.8756 85.7113 19.6695 86.1663 19.2123C86.4708 18.9063 86.6622 18.5214 86.8003 18.066C86.8792 17.806 86.9437 17.5126 87.0013 17.1838C87.0613 17.5123 87.1276 17.805 87.2077 18.0641C87.3478 18.517 87.5394 18.8994 87.8429 19.2038C88.2893 19.6514 88.9123 19.8586 89.7194 19.9966C88.9076 20.1302 88.2795 20.3367 87.8304 20.7875C87.5256 21.0935 87.3341 21.4785 87.1958 21.9339Z" fill="white"/>
<path d="M87.1958 21.9339C87.1162 22.1962 87.0513 22.4925 86.9933 22.8247C86.9318 22.4938 86.8645 22.1997 86.7836 21.9402C86.6432 21.4904 86.4523 21.1117 86.1497 20.81C85.8465 20.5076 85.4699 20.3211 85.026 20.1879C84.7934 20.1181 84.5335 20.0605 84.245 20.0089C85.0724 19.8756 85.7113 19.6695 86.1663 19.2123C86.4708 18.9063 86.6622 18.5214 86.8003 18.066C86.8792 17.806 86.9437 17.5126 87.0013 17.1838C87.0613 17.5123 87.1276 17.805 87.2077 18.0641C87.3478 18.517 87.5394 18.8994 87.8429 19.2038C88.2893 19.6514 88.9123 19.8586 89.7194 19.9966C88.9076 20.1302 88.2795 20.3367 87.8304 20.7875C87.5256 21.0935 87.3341 21.4785 87.1958 21.9339Z" fill="url(#paint2_linear_124_4926)"/>
<path d="M87.1958 21.9339C87.1162 22.1962 87.0513 22.4925 86.9933 22.8247C86.9318 22.4938 86.8645 22.1997 86.7836 21.9402C86.6432 21.4904 86.4523 21.1117 86.1497 20.81C85.8465 20.5076 85.4699 20.3211 85.026 20.1879C84.7934 20.1181 84.5335 20.0605 84.245 20.0089C85.0724 19.8756 85.7113 19.6695 86.1663 19.2123C86.4708 18.9063 86.6622 18.5214 86.8003 18.066C86.8792 17.806 86.9437 17.5126 87.0013 17.1838C87.0613 17.5123 87.1276 17.805 87.2077 18.0641C87.3478 18.517 87.5394 18.8994 87.8429 19.2038C88.2893 19.6514 88.9123 19.8586 89.7194 19.9966C88.9076 20.1302 88.2795 20.3367 87.8304 20.7875C87.5256 21.0935 87.3341 21.4785 87.1958 21.9339Z" stroke="url(#paint3_linear_124_4926)" style="mix-blend-mode:soft-light"/>
</g>
<path d="M4.19585 55.9339C4.11625 56.1962 4.05127 56.4925 3.99329 56.8247C3.93183 56.4938 3.86453 56.1997 3.78356 55.9402C3.64322 55.4904 3.45227 55.1117 3.14971 54.81C2.84652 54.5076 2.46991 54.3211 2.02602 54.1879C1.79338 54.1181 1.53351 54.0605 1.24504 54.0089C2.07244 53.8756 2.7113 53.6695 3.16632 53.2123C3.47085 52.9063 3.66216 52.5214 3.80029 52.066C3.87917 51.806 3.94369 51.5126 4.00128 51.1838C4.06133 51.5123 4.12764 51.805 4.20775 52.0641C4.34777 52.517 4.53935 52.8994 4.84292 53.2038C5.28932 53.6514 5.9123 53.8586 6.71942 53.9966C5.9076 54.1302 5.27951 54.3367 4.83043 54.7875C4.52556 55.0935 4.33407 55.4785 4.19585 55.9339Z" fill="white"/>
<path d="M4.19585 55.9339C4.11625 56.1962 4.05127 56.4925 3.99329 56.8247C3.93183 56.4938 3.86453 56.1997 3.78356 55.9402C3.64322 55.4904 3.45227 55.1117 3.14971 54.81C2.84652 54.5076 2.46991 54.3211 2.02602 54.1879C1.79338 54.1181 1.53351 54.0605 1.24504 54.0089C2.07244 53.8756 2.7113 53.6695 3.16632 53.2123C3.47085 52.9063 3.66216 52.5214 3.80029 52.066C3.87917 51.806 3.94369 51.5126 4.00128 51.1838C4.06133 51.5123 4.12764 51.805 4.20775 52.0641C4.34777 52.517 4.53935 52.8994 4.84292 53.2038C5.28932 53.6514 5.9123 53.8586 6.71942 53.9966C5.9076 54.1302 5.27951 54.3367 4.83043 54.7875C4.52556 55.0935 4.33407 55.4785 4.19585 55.9339Z" fill="url(#paint4_linear_124_4926)"/>
<path d="M4.19585 55.9339C4.11625 56.1962 4.05127 56.4925 3.99329 56.8247C3.93183 56.4938 3.86453 56.1997 3.78356 55.9402C3.64322 55.4904 3.45227 55.1117 3.14971 54.81C2.84652 54.5076 2.46991 54.3211 2.02602 54.1879C1.79338 54.1181 1.53351 54.0605 1.24504 54.0089C2.07244 53.8756 2.7113 53.6695 3.16632 53.2123C3.47085 52.9063 3.66216 52.5214 3.80029 52.066C3.87917 51.806 3.94369 51.5126 4.00128 51.1838C4.06133 51.5123 4.12764 51.805 4.20775 52.0641C4.34777 52.517 4.53935 52.8994 4.84292 53.2038C5.28932 53.6514 5.9123 53.8586 6.71942 53.9966C5.9076 54.1302 5.27951 54.3367 4.83043 54.7875C4.52556 55.0935 4.33407 55.4785 4.19585 55.9339Z" stroke="url(#paint5_linear_124_4926)" style="mix-blend-mode:soft-light"/>
<path d="M32.2998 21.9989C30.8424 22.1689 29.8077 22.3889 29.1266 23.0726C28.7649 23.4357 28.5337 23.8961 28.3644 24.4537C28.2101 24.9622 28.0996 25.5784 27.9963 26.3166C27.8832 25.5784 27.7672 24.9658 27.6101 24.4625C27.4383 23.9117 27.2078 23.4589 26.8489 23.101C26.4893 22.7424 26.0395 22.5175 25.4966 22.3546C25.0022 22.2063 24.4041 22.1019 23.6882 22.0024C25.1497 21.8322 26.187 21.6128 26.8693 20.9272C27.2306 20.5641 27.4616 20.1038 27.6307 19.5462C27.7848 19.0384 27.8952 18.4232 27.9984 17.6862C28.1082 18.4232 28.2226 19.0372 28.3791 19.5432C28.5506 20.0979 28.7819 20.5553 29.1422 20.9165C29.8199 21.5961 30.847 21.8183 32.2998 21.9989ZM32.5 22C32.5 21.9978 32.5002 21.9956 32.5004 21.9935L32.5012 22L32.5026 22.0121C32.5005 22.0068 32.5 22.0023 32.5 22ZM23.4986 22.024L23.4382 22.4728L23.4987 22.024L23.4986 22.024Z" fill="white"/>
<path d="M32.2998 21.9989C30.8424 22.1689 29.8077 22.3889 29.1266 23.0726C28.7649 23.4357 28.5337 23.8961 28.3644 24.4537C28.2101 24.9622 28.0996 25.5784 27.9963 26.3166C27.8832 25.5784 27.7672 24.9658 27.6101 24.4625C27.4383 23.9117 27.2078 23.4589 26.8489 23.101C26.4893 22.7424 26.0395 22.5175 25.4966 22.3546C25.0022 22.2063 24.4041 22.1019 23.6882 22.0024C25.1497 21.8322 26.187 21.6128 26.8693 20.9272C27.2306 20.5641 27.4616 20.1038 27.6307 19.5462C27.7848 19.0384 27.8952 18.4232 27.9984 17.6862C28.1082 18.4232 28.2226 19.0372 28.3791 19.5432C28.5506 20.0979 28.7819 20.5553 29.1422 20.9165C29.8199 21.5961 30.847 21.8183 32.2998 21.9989ZM32.5 22C32.5 21.9978 32.5002 21.9956 32.5004 21.9935L32.5012 22L32.5026 22.0121C32.5005 22.0068 32.5 22.0023 32.5 22ZM23.4986 22.024L23.4382 22.4728L23.4987 22.024L23.4986 22.024Z" fill="url(#paint6_linear_124_4926)"/>
<path d="M32.2998 21.9989C30.8424 22.1689 29.8077 22.3889 29.1266 23.0726C28.7649 23.4357 28.5337 23.8961 28.3644 24.4537C28.2101 24.9622 28.0996 25.5784 27.9963 26.3166C27.8832 25.5784 27.7672 24.9658 27.6101 24.4625C27.4383 23.9117 27.2078 23.4589 26.8489 23.101C26.4893 22.7424 26.0395 22.5175 25.4966 22.3546C25.0022 22.2063 24.4041 22.1019 23.6882 22.0024C25.1497 21.8322 26.187 21.6128 26.8693 20.9272C27.2306 20.5641 27.4616 20.1038 27.6307 19.5462C27.7848 19.0384 27.8952 18.4232 27.9984 17.6862C28.1082 18.4232 28.2226 19.0372 28.3791 19.5432C28.5506 20.0979 28.7819 20.5553 29.1422 20.9165C29.8199 21.5961 30.847 21.8183 32.2998 21.9989ZM32.5 22C32.5 21.9978 32.5002 21.9956 32.5004 21.9935L32.5012 22L32.5026 22.0121C32.5005 22.0068 32.5 22.0023 32.5 22ZM23.4986 22.024L23.4382 22.4728L23.4987 22.024L23.4986 22.024Z" stroke="url(#paint7_linear_124_4926)" style="mix-blend-mode:soft-light"/>
<path d="M71.2998 12.9989C69.8424 13.1689 68.8077 13.3889 68.1266 14.0726C67.7649 14.4357 67.5337 14.8961 67.3644 15.4537C67.2101 15.9622 67.0996 16.5784 66.9963 17.3166C66.8832 16.5784 66.7672 15.9658 66.6101 15.4625C66.4383 14.9117 66.2078 14.4589 65.8489 14.101C65.4893 13.7424 65.0395 13.5175 64.4966 13.3546C64.0022 13.2063 63.4041 13.1019 62.6882 13.0024C64.1497 12.8322 65.187 12.6128 65.8693 11.9272C66.2306 11.5641 66.4616 11.1038 66.6307 10.5462C66.7848 10.0384 66.8952 9.42317 66.9984 8.68625C67.1082 9.42315 67.2226 10.0372 67.3791 10.5432C67.5506 11.0979 67.7819 11.5553 68.1422 11.9165C68.8199 12.5961 69.847 12.8183 71.2998 12.9989ZM71.5 13C71.5 12.9978 71.5002 12.9956 71.5004 12.9935L71.5012 13L71.5026 13.0121C71.5005 13.0068 71.5 13.0023 71.5 13ZM62.4986 13.024L62.4382 13.4728L62.4987 13.024L62.4986 13.024Z" fill="white"/>
<path d="M71.2998 12.9989C69.8424 13.1689 68.8077 13.3889 68.1266 14.0726C67.7649 14.4357 67.5337 14.8961 67.3644 15.4537C67.2101 15.9622 67.0996 16.5784 66.9963 17.3166C66.8832 16.5784 66.7672 15.9658 66.6101 15.4625C66.4383 14.9117 66.2078 14.4589 65.8489 14.101C65.4893 13.7424 65.0395 13.5175 64.4966 13.3546C64.0022 13.2063 63.4041 13.1019 62.6882 13.0024C64.1497 12.8322 65.187 12.6128 65.8693 11.9272C66.2306 11.5641 66.4616 11.1038 66.6307 10.5462C66.7848 10.0384 66.8952 9.42317 66.9984 8.68625C67.1082 9.42315 67.2226 10.0372 67.3791 10.5432C67.5506 11.0979 67.7819 11.5553 68.1422 11.9165C68.8199 12.5961 69.847 12.8183 71.2998 12.9989ZM71.5 13C71.5 12.9978 71.5002 12.9956 71.5004 12.9935L71.5012 13L71.5026 13.0121C71.5005 13.0068 71.5 13.0023 71.5 13ZM62.4986 13.024L62.4382 13.4728L62.4987 13.024L62.4986 13.024Z" fill="url(#paint8_linear_124_4926)"/>
<path d="M71.2998 12.9989C69.8424 13.1689 68.8077 13.3889 68.1266 14.0726C67.7649 14.4357 67.5337 14.8961 67.3644 15.4537C67.2101 15.9622 67.0996 16.5784 66.9963 17.3166C66.8832 16.5784 66.7672 15.9658 66.6101 15.4625C66.4383 14.9117 66.2078 14.4589 65.8489 14.101C65.4893 13.7424 65.0395 13.5175 64.4966 13.3546C64.0022 13.2063 63.4041 13.1019 62.6882 13.0024C64.1497 12.8322 65.187 12.6128 65.8693 11.9272C66.2306 11.5641 66.4616 11.1038 66.6307 10.5462C66.7848 10.0384 66.8952 9.42317 66.9984 8.68625C67.1082 9.42315 67.2226 10.0372 67.3791 10.5432C67.5506 11.0979 67.7819 11.5553 68.1422 11.9165C68.8199 12.5961 69.847 12.8183 71.2998 12.9989ZM71.5 13C71.5 12.9978 71.5002 12.9956 71.5004 12.9935L71.5012 13L71.5026 13.0121C71.5005 13.0068 71.5 13.0023 71.5 13ZM62.4986 13.024L62.4382 13.4728L62.4987 13.024L62.4986 13.024Z" stroke="url(#paint9_linear_124_4926)" style="mix-blend-mode:soft-light"/>
<g opacity="0.3">
<path d="M15.2998 70.9989C13.8424 71.1689 12.8077 71.3889 12.1266 72.0726C11.7649 72.4357 11.5337 72.8961 11.3644 73.4537C11.2101 73.9622 11.0996 74.5784 10.9963 75.3166C10.8832 74.5784 10.7672 73.9658 10.6101 73.4625C10.4383 72.9117 10.2078 72.4589 9.84888 72.101C9.4893 71.7424 9.03946 71.5175 8.4966 71.3546C8.00217 71.2063 7.40406 71.1019 6.68822 71.0024C8.14969 70.8322 9.18698 70.6128 9.8693 69.9272C10.2306 69.5641 10.4616 69.1038 10.6307 68.5462C10.7848 68.0384 10.8952 67.4232 10.9984 66.6862C11.1082 67.4232 11.2226 68.0372 11.3791 68.5432C11.5506 69.0979 11.7819 69.5553 12.1422 69.9165C12.8199 70.5961 13.847 70.8183 15.2998 70.9989ZM15.5 71C15.5 70.9978 15.5002 70.9956 15.5004 70.9935L15.5012 71L15.5026 71.0121C15.5005 71.0068 15.5 71.0023 15.5 71ZM6.4986 71.024L6.43822 71.4728L6.49866 71.024L6.4986 71.024Z" fill="white"/>
<path d="M15.2998 70.9989C13.8424 71.1689 12.8077 71.3889 12.1266 72.0726C11.7649 72.4357 11.5337 72.8961 11.3644 73.4537C11.2101 73.9622 11.0996 74.5784 10.9963 75.3166C10.8832 74.5784 10.7672 73.9658 10.6101 73.4625C10.4383 72.9117 10.2078 72.4589 9.84888 72.101C9.4893 71.7424 9.03946 71.5175 8.4966 71.3546C8.00217 71.2063 7.40406 71.1019 6.68822 71.0024C8.14969 70.8322 9.18698 70.6128 9.8693 69.9272C10.2306 69.5641 10.4616 69.1038 10.6307 68.5462C10.7848 68.0384 10.8952 67.4232 10.9984 66.6862C11.1082 67.4232 11.2226 68.0372 11.3791 68.5432C11.5506 69.0979 11.7819 69.5553 12.1422 69.9165C12.8199 70.5961 13.847 70.8183 15.2998 70.9989ZM15.5 71C15.5 70.9978 15.5002 70.9956 15.5004 70.9935L15.5012 71L15.5026 71.0121C15.5005 71.0068 15.5 71.0023 15.5 71ZM6.4986 71.024L6.43822 71.4728L6.49866 71.024L6.4986 71.024Z" fill="url(#paint10_linear_124_4926)"/>
<path d="M15.2998 70.9989C13.8424 71.1689 12.8077 71.3889 12.1266 72.0726C11.7649 72.4357 11.5337 72.8961 11.3644 73.4537C11.2101 73.9622 11.0996 74.5784 10.9963 75.3166C10.8832 74.5784 10.7672 73.9658 10.6101 73.4625C10.4383 72.9117 10.2078 72.4589 9.84888 72.101C9.4893 71.7424 9.03946 71.5175 8.4966 71.3546C8.00217 71.2063 7.40406 71.1019 6.68822 71.0024C8.14969 70.8322 9.18698 70.6128 9.8693 69.9272C10.2306 69.5641 10.4616 69.1038 10.6307 68.5462C10.7848 68.0384 10.8952 67.4232 10.9984 66.6862C11.1082 67.4232 11.2226 68.0372 11.3791 68.5432C11.5506 69.0979 11.7819 69.5553 12.1422 69.9165C12.8199 70.5961 13.847 70.8183 15.2998 70.9989ZM15.5 71C15.5 70.9978 15.5002 70.9956 15.5004 70.9935L15.5012 71L15.5026 71.0121C15.5005 71.0068 15.5 71.0023 15.5 71ZM6.4986 71.024L6.43822 71.4728L6.49866 71.024L6.4986 71.024Z" stroke="url(#paint11_linear_124_4926)" style="mix-blend-mode:soft-light"/>
</g>
<path d="M96.2998 75.9989C94.8424 76.1689 93.8077 76.3889 93.1266 77.0726C92.7649 77.4357 92.5337 77.8961 92.3644 78.4537C92.2101 78.9622 92.0996 79.5784 91.9963 80.3166C91.8832 79.5784 91.7672 78.9658 91.6101 78.4625C91.4383 77.9117 91.2078 77.4589 90.8489 77.101C90.4893 76.7424 90.0395 76.5175 89.4966 76.3546C89.0022 76.2063 88.4041 76.1019 87.6882 76.0024C89.1497 75.8322 90.187 75.6128 90.8693 74.9272C91.2306 74.5641 91.4616 74.1038 91.6307 73.5462C91.7848 73.0384 91.8952 72.4232 91.9984 71.6862C92.1082 72.4232 92.2226 73.0372 92.3791 73.5432C92.5506 74.0979 92.7819 74.5553 93.1422 74.9165C93.8199 75.5961 94.847 75.8183 96.2998 75.9989ZM96.5 76C96.5 75.9978 96.5002 75.9956 96.5004 75.9935L96.5012 76L96.5026 76.0121C96.5005 76.0068 96.5 76.0023 96.5 76ZM87.4986 76.024L87.4382 76.4728L87.4987 76.024L87.4986 76.024Z" fill="white"/>
<path d="M96.2998 75.9989C94.8424 76.1689 93.8077 76.3889 93.1266 77.0726C92.7649 77.4357 92.5337 77.8961 92.3644 78.4537C92.2101 78.9622 92.0996 79.5784 91.9963 80.3166C91.8832 79.5784 91.7672 78.9658 91.6101 78.4625C91.4383 77.9117 91.2078 77.4589 90.8489 77.101C90.4893 76.7424 90.0395 76.5175 89.4966 76.3546C89.0022 76.2063 88.4041 76.1019 87.6882 76.0024C89.1497 75.8322 90.187 75.6128 90.8693 74.9272C91.2306 74.5641 91.4616 74.1038 91.6307 73.5462C91.7848 73.0384 91.8952 72.4232 91.9984 71.6862C92.1082 72.4232 92.2226 73.0372 92.3791 73.5432C92.5506 74.0979 92.7819 74.5553 93.1422 74.9165C93.8199 75.5961 94.847 75.8183 96.2998 75.9989ZM96.5 76C96.5 75.9978 96.5002 75.9956 96.5004 75.9935L96.5012 76L96.5026 76.0121C96.5005 76.0068 96.5 76.0023 96.5 76ZM87.4986 76.024L87.4382 76.4728L87.4987 76.024L87.4986 76.024Z" fill="url(#paint12_linear_124_4926)"/>
<path d="M96.2998 75.9989C94.8424 76.1689 93.8077 76.3889 93.1266 77.0726C92.7649 77.4357 92.5337 77.8961 92.3644 78.4537C92.2101 78.9622 92.0996 79.5784 91.9963 80.3166C91.8832 79.5784 91.7672 78.9658 91.6101 78.4625C91.4383 77.9117 91.2078 77.4589 90.8489 77.101C90.4893 76.7424 90.0395 76.5175 89.4966 76.3546C89.0022 76.2063 88.4041 76.1019 87.6882 76.0024C89.1497 75.8322 90.187 75.6128 90.8693 74.9272C91.2306 74.5641 91.4616 74.1038 91.6307 73.5462C91.7848 73.0384 91.8952 72.4232 91.9984 71.6862C92.1082 72.4232 92.2226 73.0372 92.3791 73.5432C92.5506 74.0979 92.7819 74.5553 93.1422 74.9165C93.8199 75.5961 94.847 75.8183 96.2998 75.9989ZM96.5 76C96.5 75.9978 96.5002 75.9956 96.5004 75.9935L96.5012 76L96.5026 76.0121C96.5005 76.0068 96.5 76.0023 96.5 76ZM87.4986 76.024L87.4382 76.4728L87.4987 76.024L87.4986 76.024Z" stroke="url(#paint13_linear_124_4926)" style="mix-blend-mode:soft-light"/>
<g opacity="0.3">
<path d="M15.1958 16.9339C15.1162 17.1962 15.0513 17.4925 14.9933 17.8247C14.9318 17.4938 14.8645 17.1997 14.7836 16.9402C14.6432 16.4904 14.4523 16.1117 14.1497 15.81C13.8465 15.5076 13.4699 15.3211 13.026 15.1879C12.7934 15.1181 12.5335 15.0605 12.245 15.0089C13.0724 14.8756 13.7113 14.6695 14.1663 14.2123C14.4708 13.9063 14.6622 13.5214 14.8003 13.066C14.8792 12.806 14.9437 12.5126 15.0013 12.1838C15.0613 12.5123 15.1276 12.805 15.2077 13.0641C15.3478 13.517 15.5394 13.8994 15.8429 14.2038C16.2893 14.6514 16.9123 14.8586 17.7194 14.9966C16.9076 15.1302 16.2795 15.3367 15.8304 15.7875C15.5256 16.0935 15.3341 16.4785 15.1958 16.9339Z" fill="white"/>
<path d="M15.1958 16.9339C15.1162 17.1962 15.0513 17.4925 14.9933 17.8247C14.9318 17.4938 14.8645 17.1997 14.7836 16.9402C14.6432 16.4904 14.4523 16.1117 14.1497 15.81C13.8465 15.5076 13.4699 15.3211 13.026 15.1879C12.7934 15.1181 12.5335 15.0605 12.245 15.0089C13.0724 14.8756 13.7113 14.6695 14.1663 14.2123C14.4708 13.9063 14.6622 13.5214 14.8003 13.066C14.8792 12.806 14.9437 12.5126 15.0013 12.1838C15.0613 12.5123 15.1276 12.805 15.2077 13.0641C15.3478 13.517 15.5394 13.8994 15.8429 14.2038C16.2893 14.6514 16.9123 14.8586 17.7194 14.9966C16.9076 15.1302 16.2795 15.3367 15.8304 15.7875C15.5256 16.0935 15.3341 16.4785 15.1958 16.9339Z" fill="url(#paint14_linear_124_4926)"/>
<path d="M15.1958 16.9339C15.1162 17.1962 15.0513 17.4925 14.9933 17.8247C14.9318 17.4938 14.8645 17.1997 14.7836 16.9402C14.6432 16.4904 14.4523 16.1117 14.1497 15.81C13.8465 15.5076 13.4699 15.3211 13.026 15.1879C12.7934 15.1181 12.5335 15.0605 12.245 15.0089C13.0724 14.8756 13.7113 14.6695 14.1663 14.2123C14.4708 13.9063 14.6622 13.5214 14.8003 13.066C14.8792 12.806 14.9437 12.5126 15.0013 12.1838C15.0613 12.5123 15.1276 12.805 15.2077 13.0641C15.3478 13.517 15.5394 13.8994 15.8429 14.2038C16.2893 14.6514 16.9123 14.8586 17.7194 14.9966C16.9076 15.1302 16.2795 15.3367 15.8304 15.7875C15.5256 16.0935 15.3341 16.4785 15.1958 16.9339Z" stroke="url(#paint15_linear_124_4926)" style="mix-blend-mode:soft-light"/>
</g>
<g opacity="0.6">
<path d="M20.1958 60.9339C20.1162 61.1962 20.0513 61.4925 19.9933 61.8247C19.9318 61.4938 19.8645 61.1997 19.7836 60.9402C19.6432 60.4904 19.4523 60.1117 19.1497 59.81C18.8465 59.5076 18.4699 59.3211 18.026 59.1879C17.7934 59.1181 17.5335 59.0605 17.245 59.0089C18.0724 58.8756 18.7113 58.6695 19.1663 58.2123C19.4708 57.9063 19.6622 57.5214 19.8003 57.066C19.8792 56.806 19.9437 56.5126 20.0013 56.1838C20.0613 56.5123 20.1276 56.805 20.2077 57.0641C20.3478 57.517 20.5394 57.8994 20.8429 58.2038C21.2893 58.6514 21.9123 58.8586 22.7194 58.9966C21.9076 59.1302 21.2795 59.3367 20.8304 59.7875C20.5256 60.0935 20.3341 60.4785 20.1958 60.9339Z" fill="white"/>
<path d="M20.1958 60.9339C20.1162 61.1962 20.0513 61.4925 19.9933 61.8247C19.9318 61.4938 19.8645 61.1997 19.7836 60.9402C19.6432 60.4904 19.4523 60.1117 19.1497 59.81C18.8465 59.5076 18.4699 59.3211 18.026 59.1879C17.7934 59.1181 17.5335 59.0605 17.245 59.0089C18.0724 58.8756 18.7113 58.6695 19.1663 58.2123C19.4708 57.9063 19.6622 57.5214 19.8003 57.066C19.8792 56.806 19.9437 56.5126 20.0013 56.1838C20.0613 56.5123 20.1276 56.805 20.2077 57.0641C20.3478 57.517 20.5394 57.8994 20.8429 58.2038C21.2893 58.6514 21.9123 58.8586 22.7194 58.9966C21.9076 59.1302 21.2795 59.3367 20.8304 59.7875C20.5256 60.0935 20.3341 60.4785 20.1958 60.9339Z" fill="url(#paint16_linear_124_4926)"/>
<path d="M20.1958 60.9339C20.1162 61.1962 20.0513 61.4925 19.9933 61.8247C19.9318 61.4938 19.8645 61.1997 19.7836 60.9402C19.6432 60.4904 19.4523 60.1117 19.1497 59.81C18.8465 59.5076 18.4699 59.3211 18.026 59.1879C17.7934 59.1181 17.5335 59.0605 17.245 59.0089C18.0724 58.8756 18.7113 58.6695 19.1663 58.2123C19.4708 57.9063 19.6622 57.5214 19.8003 57.066C19.8792 56.806 19.9437 56.5126 20.0013 56.1838C20.0613 56.5123 20.1276 56.805 20.2077 57.0641C20.3478 57.517 20.5394 57.8994 20.8429 58.2038C21.2893 58.6514 21.9123 58.8586 22.7194 58.9966C21.9076 59.1302 21.2795 59.3367 20.8304 59.7875C20.5256 60.0935 20.3341 60.4785 20.1958 60.9339Z" stroke="url(#paint17_linear_124_4926)" style="mix-blend-mode:soft-light"/>
</g>
<g opacity="0.3">
<path d="M83.1958 64.9339C83.1162 65.1962 83.0513 65.4925 82.9933 65.8247C82.9318 65.4938 82.8645 65.1997 82.7836 64.9402C82.6432 64.4904 82.4523 64.1117 82.1497 63.81C81.8465 63.5076 81.4699 63.3211 81.026 63.1879C80.7934 63.1181 80.5335 63.0605 80.245 63.0089C81.0724 62.8756 81.7113 62.6695 82.1663 62.2123C82.4708 61.9063 82.6622 61.5214 82.8003 61.066C82.8792 60.806 82.9437 60.5126 83.0013 60.1838C83.0613 60.5123 83.1276 60.805 83.2077 61.0641C83.3478 61.517 83.5394 61.8994 83.8429 62.2038C84.2893 62.6514 84.9123 62.8586 85.7194 62.9966C84.9076 63.1302 84.2795 63.3367 83.8304 63.7875C83.5256 64.0935 83.3341 64.4785 83.1958 64.9339Z" fill="white"/>
<path d="M83.1958 64.9339C83.1162 65.1962 83.0513 65.4925 82.9933 65.8247C82.9318 65.4938 82.8645 65.1997 82.7836 64.9402C82.6432 64.4904 82.4523 64.1117 82.1497 63.81C81.8465 63.5076 81.4699 63.3211 81.026 63.1879C80.7934 63.1181 80.5335 63.0605 80.245 63.0089C81.0724 62.8756 81.7113 62.6695 82.1663 62.2123C82.4708 61.9063 82.6622 61.5214 82.8003 61.066C82.8792 60.806 82.9437 60.5126 83.0013 60.1838C83.0613 60.5123 83.1276 60.805 83.2077 61.0641C83.3478 61.517 83.5394 61.8994 83.8429 62.2038C84.2893 62.6514 84.9123 62.8586 85.7194 62.9966C84.9076 63.1302 84.2795 63.3367 83.8304 63.7875C83.5256 64.0935 83.3341 64.4785 83.1958 64.9339Z" fill="url(#paint18_linear_124_4926)"/>
<path d="M83.1958 64.9339C83.1162 65.1962 83.0513 65.4925 82.9933 65.8247C82.9318 65.4938 82.8645 65.1997 82.7836 64.9402C82.6432 64.4904 82.4523 64.1117 82.1497 63.81C81.8465 63.5076 81.4699 63.3211 81.026 63.1879C80.7934 63.1181 80.5335 63.0605 80.245 63.0089C81.0724 62.8756 81.7113 62.6695 82.1663 62.2123C82.4708 61.9063 82.6622 61.5214 82.8003 61.066C82.8792 60.806 82.9437 60.5126 83.0013 60.1838C83.0613 60.5123 83.1276 60.805 83.2077 61.0641C83.3478 61.517 83.5394 61.8994 83.8429 62.2038C84.2893 62.6514 84.9123 62.8586 85.7194 62.9966C84.9076 63.1302 84.2795 63.3367 83.8304 63.7875C83.5256 64.0935 83.3341 64.4785 83.1958 64.9339Z" stroke="url(#paint19_linear_124_4926)" style="mix-blend-mode:soft-light"/>
</g>
<g opacity="0.6">
<path d="M74.1958 25.9339C74.1162 26.1962 74.0513 26.4925 73.9933 26.8247C73.9318 26.4938 73.8645 26.1997 73.7836 25.9402C73.6432 25.4904 73.4523 25.1117 73.1497 24.81C72.8465 24.5076 72.4699 24.3211 72.026 24.1879C71.7934 24.1181 71.5335 24.0605 71.245 24.0089C72.0724 23.8756 72.7113 23.6695 73.1663 23.2123C73.4708 22.9063 73.6622 22.5214 73.8003 22.066C73.8792 21.806 73.9437 21.5126 74.0013 21.1838C74.0613 21.5123 74.1276 21.805 74.2077 22.0641C74.3478 22.517 74.5394 22.8994 74.8429 23.2038C75.2893 23.6514 75.9123 23.8586 76.7194 23.9966C75.9076 24.1302 75.2795 24.3367 74.8304 24.7875C74.5256 25.0935 74.3341 25.4785 74.1958 25.9339Z" fill="white"/>
<path d="M74.1958 25.9339C74.1162 26.1962 74.0513 26.4925 73.9933 26.8247C73.9318 26.4938 73.8645 26.1997 73.7836 25.9402C73.6432 25.4904 73.4523 25.1117 73.1497 24.81C72.8465 24.5076 72.4699 24.3211 72.026 24.1879C71.7934 24.1181 71.5335 24.0605 71.245 24.0089C72.0724 23.8756 72.7113 23.6695 73.1663 23.2123C73.4708 22.9063 73.6622 22.5214 73.8003 22.066C73.8792 21.806 73.9437 21.5126 74.0013 21.1838C74.0613 21.5123 74.1276 21.805 74.2077 22.0641C74.3478 22.517 74.5394 22.8994 74.8429 23.2038C75.2893 23.6514 75.9123 23.8586 76.7194 23.9966C75.9076 24.1302 75.2795 24.3367 74.8304 24.7875C74.5256 25.0935 74.3341 25.4785 74.1958 25.9339Z" fill="url(#paint20_linear_124_4926)"/>
<path d="M74.1958 25.9339C74.1162 26.1962 74.0513 26.4925 73.9933 26.8247C73.9318 26.4938 73.8645 26.1997 73.7836 25.9402C73.6432 25.4904 73.4523 25.1117 73.1497 24.81C72.8465 24.5076 72.4699 24.3211 72.026 24.1879C71.7934 24.1181 71.5335 24.0605 71.245 24.0089C72.0724 23.8756 72.7113 23.6695 73.1663 23.2123C73.4708 22.9063 73.6622 22.5214 73.8003 22.066C73.8792 21.806 73.9437 21.5126 74.0013 21.1838C74.0613 21.5123 74.1276 21.805 74.2077 22.0641C74.3478 22.517 74.5394 22.8994 74.8429 23.2038C75.2893 23.6514 75.9123 23.8586 76.7194 23.9966C75.9076 24.1302 75.2795 24.3367 74.8304 24.7875C74.5256 25.0935 74.3341 25.4785 74.1958 25.9339Z" stroke="url(#paint21_linear_124_4926)" style="mix-blend-mode:soft-light"/>
</g>
<defs>
<linearGradient id="paint0_linear_124_4926" x1="9" y1="68.5" x2="90.1475" y2="3.67735" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
<linearGradient id="paint1_linear_124_4926" x1="100.417" y1="31.6667" x2="50.063" y2="47.3132" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.395833" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.520833" stop-color="white"/>
<stop offset="0.645833" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint2_linear_124_4926" x1="83" y1="21.3624" x2="90.8409" y2="15.8603" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
<linearGradient id="paint3_linear_124_4926" x1="91.6304" y1="18.4957" x2="86.965" y2="19.8823" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.395833" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.520833" stop-color="white"/>
<stop offset="0.645833" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint4_linear_124_4926" x1="-4.71218e-07" y1="55.3624" x2="7.84087" y2="49.8603" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
<linearGradient id="paint5_linear_124_4926" x1="8.63037" y1="52.4957" x2="3.96502" y2="53.8823" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.395833" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.520833" stop-color="white"/>
<stop offset="0.645833" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint6_linear_124_4926" x1="23" y1="23.703" x2="32.8011" y2="16.8253" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
<linearGradient id="paint7_linear_124_4926" x1="33.788" y1="20.1197" x2="27.9563" y2="21.8529" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.395833" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.520833" stop-color="white"/>
<stop offset="0.645833" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint8_linear_124_4926" x1="62" y1="14.703" x2="71.8011" y2="7.82533" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
<linearGradient id="paint9_linear_124_4926" x1="72.788" y1="11.1197" x2="66.9563" y2="12.8529" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.395833" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.520833" stop-color="white"/>
<stop offset="0.645833" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint10_linear_124_4926" x1="6" y1="72.703" x2="15.8011" y2="65.8253" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
<linearGradient id="paint11_linear_124_4926" x1="16.788" y1="69.1197" x2="10.9563" y2="70.8529" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.395833" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.520833" stop-color="white"/>
<stop offset="0.645833" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint12_linear_124_4926" x1="87" y1="77.703" x2="96.8011" y2="70.8253" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
<linearGradient id="paint13_linear_124_4926" x1="97.788" y1="74.1197" x2="91.9563" y2="75.8529" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.395833" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.520833" stop-color="white"/>
<stop offset="0.645833" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint14_linear_124_4926" x1="11" y1="16.3624" x2="18.8409" y2="10.8603" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
<linearGradient id="paint15_linear_124_4926" x1="19.6304" y1="13.4957" x2="14.965" y2="14.8823" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.395833" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.520833" stop-color="white"/>
<stop offset="0.645833" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint16_linear_124_4926" x1="16" y1="60.3624" x2="23.8409" y2="54.8603" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
<linearGradient id="paint17_linear_124_4926" x1="24.6304" y1="57.4957" x2="19.965" y2="58.8823" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.395833" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.520833" stop-color="white"/>
<stop offset="0.645833" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint18_linear_124_4926" x1="79" y1="64.3624" x2="86.8409" y2="58.8603" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
<linearGradient id="paint19_linear_124_4926" x1="87.6304" y1="61.4957" x2="82.965" y2="62.8823" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.395833" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.520833" stop-color="white"/>
<stop offset="0.645833" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint20_linear_124_4926" x1="70" y1="25.3624" x2="77.8409" y2="19.8603" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
<linearGradient id="paint21_linear_124_4926" x1="78.6304" y1="22.4957" x2="73.965" y2="23.8823" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.395833" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.520833" stop-color="white"/>
<stop offset="0.645833" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 33 KiB

View File

@ -0,0 +1,18 @@
<svg width="88" height="84" viewBox="0 0 88 84" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M40.9088 69.9378L21.3308 81.9314C19.6875 82.9381 17.5392 82.422 16.5326 80.7787C16.0409 79.9762 15.8943 79.009 16.1261 78.0967L19.1567 66.1679C20.19 62.1011 22.9729 58.7015 26.7556 56.8854L48.1143 46.6307C49.5249 45.9534 50.1194 44.2608 49.4421 42.8502C48.8937 41.7078 47.6533 41.0685 46.4046 41.2847L22.6297 45.4007C18.0385 46.1956 13.3302 44.9278 9.75892 41.9349L2.24821 35.6407C0.771165 34.4029 0.577225 32.2021 1.81503 30.7251C2.41705 30.0067 3.28278 29.5607 4.21721 29.4876L27.1646 27.6917C29.0983 27.5404 30.7835 26.3166 31.5258 24.5247L40.3785 3.15483C41.116 1.37442 43.1572 0.529024 44.9377 1.26658C45.7926 1.62072 46.4718 2.29994 46.8259 3.15483L55.6786 24.5247C56.4209 26.3166 58.1061 27.5404 60.0398 27.6917L83.1133 29.4974C85.0345 29.6478 86.4701 31.3272 86.3198 33.2484C86.2474 34.1727 85.8103 35.0301 85.1048 35.6316L67.5076 50.6336C66.03 51.8932 65.3854 53.8762 65.8398 55.764L71.2497 78.2379C71.7007 80.1115 70.5475 81.996 68.6739 82.447C67.7736 82.6637 66.8241 82.5137 66.0345 82.03L46.2956 69.9378C44.6427 68.9253 42.5617 68.9253 40.9088 69.9378Z" fill="url(#paint0_linear_1_47)"/>
<path style="mix-blend-mode:soft-light" d="M40.9088 69.9378L21.3308 81.9314C19.6875 82.9381 17.5392 82.422 16.5326 80.7787C16.0409 79.9762 15.8943 79.009 16.1261 78.0967L19.1567 66.1679C20.19 62.1011 22.9729 58.7015 26.7556 56.8854L48.1143 46.6307C49.5249 45.9534 50.1194 44.2608 49.4421 42.8502C48.8937 41.7078 47.6533 41.0685 46.4046 41.2847L22.6297 45.4007C18.0385 46.1956 13.3302 44.9278 9.75892 41.9349L2.24821 35.6407C0.771165 34.4029 0.577225 32.2021 1.81503 30.7251C2.41705 30.0067 3.28278 29.5607 4.21721 29.4876L27.1646 27.6917C29.0983 27.5404 30.7835 26.3166 31.5258 24.5247L40.3785 3.15483C41.116 1.37442 43.1572 0.529024 44.9377 1.26658C45.7926 1.62072 46.4718 2.29994 46.8259 3.15483L55.6786 24.5247C56.4209 26.3166 58.1061 27.5404 60.0398 27.6917L83.1133 29.4974C85.0345 29.6478 86.4701 31.3272 86.3198 33.2484C86.2474 34.1727 85.8103 35.0301 85.1048 35.6316L67.5076 50.6336C66.03 51.8932 65.3854 53.8762 65.8398 55.764L71.2497 78.2379C71.7007 80.1115 70.5475 81.996 68.6739 82.447C67.7736 82.6637 66.8241 82.5137 66.0345 82.03L46.2956 69.9378C44.6427 68.9253 42.5617 68.9253 40.9088 69.9378Z" stroke="url(#paint1_linear_1_47)" stroke-width="1.66667"/>
<defs>
<linearGradient id="paint0_linear_1_47" x1="2.60231" y1="62.9586" x2="83.7498" y2="-1.864" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
<linearGradient id="paint1_linear_1_47" x1="94.0193" y1="26.1254" x2="43.6653" y2="41.7719" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="0.395833" stop-color="white" stop-opacity="0.85"/>
<stop offset="0.520833" stop-color="white"/>
<stop offset="0.645833" stop-color="white" stop-opacity="0.85"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,10 @@
<svg width="86" height="82" viewBox="0 0 86 82" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M39.9088 68.9378L20.3308 80.9314C18.6875 81.9381 16.5392 81.422 15.5326 79.7787C15.0409 78.9762 14.8943 78.009 15.1261 77.0967L18.1567 65.1679C19.19 61.1011 21.9729 57.7015 25.7556 55.8854L47.1143 45.6307C48.5249 44.9534 49.1194 43.2608 48.4421 41.8502C47.8937 40.7078 46.6533 40.0685 45.4046 40.2847L21.6297 44.4007C17.0385 45.1956 12.3302 43.9278 8.75892 40.9349L1.24821 34.6407C-0.228835 33.4029 -0.422775 31.2021 0.815035 29.7251C1.41705 29.0067 2.28278 28.5607 3.21721 28.4876L26.1646 26.6917C28.0983 26.5404 29.7835 25.3166 30.5258 23.5247L39.3785 2.15483C40.116 0.374424 42.1572 -0.470976 43.9377 0.266584C44.7926 0.620724 45.4718 1.29994 45.8259 2.15483L54.6786 23.5247C55.4209 25.3166 57.1061 26.5404 59.0398 26.6917L82.1133 28.4974C84.0345 28.6478 85.4701 30.3272 85.3198 32.2484C85.2474 33.1727 84.8103 34.0301 84.1048 34.6316L66.5076 49.6336C65.03 50.8932 64.3854 52.8762 64.8398 54.764L70.2497 77.2379C70.7007 79.1115 69.5475 80.996 67.6739 81.447C66.7736 81.6637 65.8241 81.5137 65.0345 81.03L45.2956 68.9378C43.6427 67.9253 41.5617 67.9253 39.9088 68.9378Z" fill="url(#paint0_linear_18_56)"/>
<defs>
<linearGradient id="paint0_linear_18_56" x1="1.60231" y1="61.9586" x2="82.7498" y2="-2.864" gradientUnits="userSpaceOnUse">
<stop stop-color="#6B93FF"/>
<stop offset="0.439058" stop-color="#976FFF"/>
<stop offset="1" stop-color="#E46ACE"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -179,11 +179,15 @@ const AnimatedSticker: FC<OwnProps> = ({
useSharedIntersectionObserver(sharedCanvas, throttledInit);
useEffect(() => {
if (!animation) return;
animation.setColor(rgbColor.current);
animation?.setColor(rgbColor.current);
}, [color, animation]);
useEffect(() => {
if (typeof speed === 'number') {
animation?.setSpeed(speed);
}
}, [speed, animation]);
useUnmountCleanup(() => {
animationRef.current?.removeView(viewId);
});

View File

@ -62,7 +62,7 @@ import GiftBlueRound from '../../../assets/premium/GiftBlueRound.svg';
import GiftGreenRound from '../../../assets/premium/GiftGreenRound.svg';
import GiftRedRound from '../../../assets/premium/GiftRedRound.svg';
import GiftStar from '../../../assets/premium/GiftStar.svg';
import PremiumLogo from '../../../assets/premium/PremiumLogo.svg';
import PremiumLogo from '../../../assets/premium/PremiumStar.svg';
export type OwnProps = {
isOpen?: boolean;

View File

@ -43,13 +43,6 @@
@include mixins.adapt-padding-to-scrollbar(0.5rem);
}
.logo {
width: 6.25rem;
height: 6.25rem;
min-height: 6.25rem;
margin: 1rem;
}
.status-emoji {
--custom-emoji-size: 8rem;

View File

@ -1,22 +1,21 @@
import type { FC } from '../../../lib/teact/teact';
import type React from '../../../lib/teact/teact';
import {
memo, useEffect, useMemo, useRef, useState,
} from '../../../lib/teact/teact';
import type { FC } from '@teact';
import { memo, useEffect, useMemo, useRef, useState } from '@teact';
import { getActions, withGlobal } from '../../../global';
import type {
ApiPremiumPromo, ApiPremiumSection, ApiPremiumSubscriptionOption, ApiSticker, ApiStickerSet, ApiUser,
ApiPremiumPromo,
ApiPremiumSection,
ApiPremiumSubscriptionOption,
ApiSticker,
ApiStickerSet,
ApiUser,
} from '../../../api/types';
import type { GlobalState } from '../../../global/types';
import type { LangPair } from '../../../types/language';
import { PREMIUM_FEATURE_SECTIONS, TME_LINK_PREFIX } from '../../../config';
import { getUserFullName } from '../../../global/helpers';
import {
selectIsCurrentUserPremium, selectStickerSet,
selectTabState, selectUser,
} from '../../../global/selectors';
import { selectIsCurrentUserPremium, selectStickerSet, selectTabState, selectUser } from '../../../global/selectors';
import { selectPremiumLimit } from '../../../global/selectors/limits';
import buildClassName from '../../../util/buildClassName';
import { formatCurrency } from '../../../util/formatCurrency';
@ -31,14 +30,12 @@ import useSyncEffect from '../../../hooks/useSyncEffect';
import CustomEmoji from '../../common/CustomEmoji';
import Icon from '../../common/icons/Icon';
import ParticlesHeader from '../../modals/common/ParticlesHeader.tsx';
import Button from '../../ui/Button';
import Modal from '../../ui/Modal';
import Transition from '../../ui/Transition';
import PremiumFeatureItem from './PremiumFeatureItem';
import PremiumFeatureModal, {
PREMIUM_FEATURE_DESCRIPTIONS,
PREMIUM_FEATURE_TITLES,
} from './PremiumFeatureModal';
import PremiumFeatureModal, { PREMIUM_FEATURE_DESCRIPTIONS, PREMIUM_FEATURE_TITLES } from './PremiumFeatureModal';
import PremiumSubscriptionOption from './PremiumSubscriptionOption';
import styles from './PremiumMainModal.module.scss';
@ -51,7 +48,6 @@ import PremiumEmoji from '../../../assets/premium/PremiumEmoji.svg';
import PremiumFile from '../../../assets/premium/PremiumFile.svg';
import PremiumLastSeen from '../../../assets/premium/PremiumLastSeen.svg';
import PremiumLimits from '../../../assets/premium/PremiumLimits.svg';
import PremiumLogo from '../../../assets/premium/PremiumLogo.svg';
import PremiumMessagePrivacy from '../../../assets/premium/PremiumMessagePrivacy.svg';
import PremiumReactions from '../../../assets/premium/PremiumReactions.svg';
import PremiumSpeed from '../../../assets/premium/PremiumSpeed.svg';
@ -374,29 +370,35 @@ const PremiumMainModal: FC<OwnProps & StateProps> = ({
size="smaller"
className={styles.closeButton}
color="translucent"
onClick={() => closePremiumModal()}
ariaLabel={oldLang('Close')}
>
<Icon name="close" />
</Button>
{(fromUserStatusEmoji && !isGift) ? (
<CustomEmoji
className={styles.statusEmoji}
onClick={handleOpenStatusSet}
documentId={fromUserStatusEmoji.id}
isBig
size={STATUS_EMOJI_SIZE}
{!fromUserStatusEmoji ? (
<ParticlesHeader
model="swaying-star"
color="purple"
title={getHeaderText()}
description={renderText(getHeaderDescription(), ['simple_markdown', 'emoji'])}
/>
) : (
<img className={styles.logo} src={PremiumLogo} alt="" draggable={false} />
<>
<CustomEmoji
className={styles.statusEmoji}
onClick={handleOpenStatusSet}
documentId={fromUserStatusEmoji.id}
isBig
size={STATUS_EMOJI_SIZE}
/>
<h2 className={buildClassName(styles.headerText, fromUserStatusSet && styles.stickerSetText)}>
{getHeaderText()}
</h2>
<div className={styles.description}>
{renderText(getHeaderDescription(), ['simple_markdown', 'emoji'])}
</div>
</>
)}
<h2 className={buildClassName(styles.headerText, fromUserStatusSet && styles.stickerSetText)}>
{getHeaderText()}
</h2>
<div className={styles.description}>
{renderText(getHeaderDescription(), ['simple_markdown', 'emoji'])}
</div>
{!isPremium && !isGift && renderSubscriptionOptions()}
<div className={buildClassName(styles.header, isHeaderHidden && styles.hiddenHeader)}>
<h2 className={styles.premiumHeaderText}>

View File

@ -0,0 +1,32 @@
.root {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 9rem;
}
.particles {
position: absolute;
top: 0;
}
.title {
z-index: 0;
margin-inline: 0.5rem;
font-size: 1.5rem;
font-weight: var(--font-weight-medium);
text-align: center;
}
.description {
z-index: 0;
margin-bottom: 1rem;
margin-inline: 0.5rem;
line-height: 1.375;
text-align: center;
text-wrap: balance;
}

View File

@ -0,0 +1,76 @@
import type { TeactNode } from '@teact';
import { memo, useLayoutEffect, useRef } from '@teact';
import { PARTICLE_BURST_PARAMS, PARTICLE_COLORS, setupParticles } from '../../../util/particles.ts';
import useLastCallback from '../../../hooks/useLastCallback.ts';
import SpeedingDiamond from './SpeedingDiamond.tsx';
import SwayingStar from './SwayingStar.tsx';
import styles from './ParticlesHeader.module.scss';
interface OwnProps {
model: 'swaying-star' | 'speeding-diamond';
color: 'purple' | 'gold' | 'blue';
title: TeactNode;
description: TeactNode;
isDisabled?: boolean;
}
const PARTICLE_PARAMS = {
centerShift: [0, -36] as const,
};
function ParticlesHeader({
model,
color,
title,
description,
isDisabled,
}: OwnProps) {
const canvasRef = useRef<HTMLCanvasElement>();
useLayoutEffect(() => {
if (isDisabled) return undefined;
return setupParticles(canvasRef.current!, {
color: PARTICLE_COLORS[`${color}Gradient`],
...PARTICLE_PARAMS,
});
}, [color, isDisabled]);
const handleMouseMove = useLastCallback(() => {
setupParticles(canvasRef.current!, {
color: PARTICLE_COLORS[`${color}Gradient`],
...PARTICLE_PARAMS,
...PARTICLE_BURST_PARAMS,
});
});
return (
<div className={styles.root}>
<canvas ref={canvasRef} className={styles.particles} />
{model === 'swaying-star' ? (
<SwayingStar
color={color as 'purple' | 'gold'}
centerShift={PARTICLE_PARAMS.centerShift}
onMouseMove={handleMouseMove}
/>
) : model === 'speeding-diamond' && (
<SpeedingDiamond onMouseMove={handleMouseMove} />
)}
<h2 className={styles.title}>
{title}
</h2>
<div className={styles.description}>
{description}
</div>
</div>
);
}
export default memo(ParticlesHeader);

View File

@ -0,0 +1,21 @@
.root {
position: absolute;
z-index: 1;
top: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 14.375rem;
}
.diamond {
margin-top: calc(-2rem * 2); // Centered minus center shift
transition: transform 0.25s ease-out;
&:hover {
transform: scale(1.1);
}
}

View File

@ -0,0 +1,80 @@
import { memo, useState } from '@teact';
import { requestMutation } from '../../../lib/fasterdom/fasterdom.ts';
import { animateSingle } from '../../../util/animation.ts';
import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets.ts';
import useLastCallback from '../../../hooks/useLastCallback.ts';
import AnimatedIconWithPreview from '../../common/AnimatedIconWithPreview.tsx';
import styles from './SpeedingDiamond.module.scss';
interface OwnProps {
onMouseMove: NoneToVoidFunction;
}
const MAX_SPEED = 5;
const MIN_SPEED = 1;
const SLOWDOWN_DELAY = 300;
const SLOWDOWN_DURATION = 1500;
let slowdownTimeout: number | undefined;
let isAnimating = true;
function SpeedingDiamond({ onMouseMove }: OwnProps) {
const [speed, setSpeed] = useState(MIN_SPEED);
const handleMouseMove = useLastCallback(() => {
if (slowdownTimeout) {
clearTimeout(slowdownTimeout);
slowdownTimeout = undefined;
}
slowdownTimeout = window.setTimeout(() => {
const startAt = Date.now();
isAnimating = true;
animateSingle(() => {
if (!isAnimating) return false;
const t = Math.min((Date.now() - startAt) / SLOWDOWN_DURATION, 1);
const speed = (MAX_SPEED - MIN_SPEED) * (1 - transition(t));
setSpeed(speed);
isAnimating = t < 1 && speed > 1;
return isAnimating;
}, requestMutation);
}, SLOWDOWN_DELAY);
isAnimating = false;
setSpeed(MAX_SPEED);
onMouseMove();
});
return (
<div className={styles.root}>
<div
className={styles.diamond}
onMouseMove={handleMouseMove}
>
<AnimatedIconWithPreview
speed={speed}
size={130}
tgsUrl={LOCAL_TGS_URLS.Diamond}
nonInteractive
noLoop={false}
/>
</div>
</div>
);
}
export default memo(SpeedingDiamond);
function transition(t: number) {
return 1 - ((1 - t) ** 2);
}

View File

@ -0,0 +1,75 @@
.root {
position: absolute;
z-index: 1;
top: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 14.375rem;
}
.star {
pointer-events: none; // Let wrapper handle mouse events
position: relative;
transform-style: preserve-3d;
width: 6.25rem;
height: 6.25rem;
min-height: 6.25rem;
margin-top: calc(-2.25rem * 2); // Centered minus center shift
background-image: url('../../../assets/icons/GoldStar.svg');
background-repeat: no-repeat;
background-position: center;
background-size: contain;
transition: transform 0.6s ease-out;
// Create depth effect with pseudo-elements
&::before,
&::after {
pointer-events: none;
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('../../../assets/icons/GoldStarFill.svg');
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}
&::before {
z-index: -1;
transform: translateZ(-3px);
filter: brightness(0.8);
}
&::after {
z-index: -2;
transform: translateZ(-6px);
filter: brightness(0.8);
}
.root:hover & {
transition-duration: 0.5s;
}
&_purple {
background-image: url('../../../assets/premium/PremiumStar.svg');
&::before,
&::after {
background-image: url('../../../assets/premium/PremiumStarFill.svg');
}
}
}

View File

@ -0,0 +1,65 @@
import { memo, useRef } from '@teact';
import { requestMutation } from '../../../lib/fasterdom/fasterdom.ts';
import buildClassName from '../../../util/buildClassName.ts';
import useLastCallback from '../../../hooks/useLastCallback.ts';
import styles from './SwayingStar.module.scss';
interface OwnProps {
color: 'purple' | 'gold';
centerShift: readonly [number, number];
onMouseMove: NoneToVoidFunction;
}
const INTERACTIVE_RADIUS = 50;
function SwayingStar({
color,
centerShift,
onMouseMove,
}: OwnProps) {
const starRef = useRef<HTMLDivElement>();
const handleMouseMove = useLastCallback((e: React.MouseEvent<HTMLDivElement>) => {
const rect = e.currentTarget.getBoundingClientRect();
const centerX = rect.left + rect.width / 2 + centerShift[0];
const centerY = rect.top + rect.height / 2 + centerShift[1];
const mouseX = e.clientX - centerX;
const mouseY = e.clientY - centerY;
const normalizedX = Math.max(-1, Math.min(1, mouseX / INTERACTIVE_RADIUS));
const normalizedY = Math.max(-1, Math.min(1, mouseY / INTERACTIVE_RADIUS));
const rotateY = normalizedX * 40;
const rotateX = -normalizedY * 40;
requestMutation(() => {
starRef.current!.style.transform = `scale(1.1) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
});
onMouseMove();
});
const handleMouseLeave = useLastCallback(() => {
requestMutation(() => {
starRef.current!.style.transform = '';
});
});
return (
<div
className={styles.root}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
>
<div
ref={starRef}
className={buildClassName(styles.star, `${styles.star}_${color}`)}
role="img"
aria-label="Telegram Stars"
/>
</div>
);
}
export default memo(SwayingStar);

View File

@ -18,7 +18,7 @@ import TableInfoModal, { type TableData } from '../common/TableInfoModal';
import styles from './GiftCodeModal.module.scss';
import PremiumLogo from '../../../assets/premium/PremiumLogo.svg';
import PremiumLogo from '../../../assets/premium/PremiumStar.svg';
export type OwnProps = {
modal: TabState['giftCodeModal'];

View File

@ -67,13 +67,6 @@
background-color: var(--color-background-secondary);
}
.logo {
width: 6.25rem;
height: 6.25rem;
min-height: 6.25rem;
margin: 1rem;
}
.topUpButton,
.tonBalanceContainer {
margin-bottom: 0.5rem;
@ -105,22 +98,6 @@
color: var(--color-primary);
}
.logoBackground {
position: absolute;
top: 0.75rem;
left: 50%;
transform: translateX(-50%);
height: 8rem;
}
.headerHext {
margin-inline: 0.5rem;
font-size: 1.5rem;
font-weight: var(--font-weight-medium);
text-align: center;
}
.description {
margin-bottom: 1rem;
margin-inline: 0.5rem;

View File

@ -1,7 +1,4 @@
import type React from '../../../lib/teact/teact';
import {
memo, useEffect, useMemo, useState,
} from '../../../lib/teact/teact';
import { memo, useEffect, useMemo, useState } from '@teact';
import { getActions, getGlobal, withGlobal } from '../../../global';
import type { ApiStarTopupOption } from '../../../api/types';
@ -20,7 +17,6 @@ import { getPeerTitle } from '../../../global/helpers/peers';
import { selectChat, selectIsPremiumPurchaseBlocked, selectUser } from '../../../global/selectors';
import buildClassName from '../../../util/buildClassName';
import { convertCurrencyFromBaseUnit, convertTonToUsd, formatCurrencyAsString } from '../../../util/formatCurrency';
import { LOCAL_TGS_URLS } from '../../common/helpers/animatedAssets';
import renderText from '../../common/helpers/renderText';
import useFlag from '../../../hooks/useFlag';
@ -28,7 +24,6 @@ import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import useOldLang from '../../../hooks/useOldLang';
import AnimatedIconWithPreview from '../../common/AnimatedIconWithPreview';
import Icon from '../../common/icons/Icon';
import SafeLink from '../../common/SafeLink';
import Button from '../../ui/Button';
@ -36,6 +31,7 @@ import InfiniteScroll from '../../ui/InfiniteScroll';
import Modal from '../../ui/Modal';
import TabList, { type TabWithProperties } from '../../ui/TabList';
import Transition from '../../ui/Transition';
import ParticlesHeader from '../common/ParticlesHeader.tsx';
import BalanceBlock from './BalanceBlock';
import StarTopupOptionList from './StarTopupOptionList';
import StarsSubscriptionItem from './subscription/StarsSubscriptionItem';
@ -43,9 +39,6 @@ import StarsTransactionItem from './transaction/StarsTransactionItem';
import styles from './StarsBalanceModal.module.scss';
import StarLogo from '../../../assets/icons/StarLogo.svg';
import StarsBackground from '../../../assets/stars-bg.png';
const TRANSACTION_TYPES = ['all', 'inbound', 'outbound'] as const;
const TRANSACTION_TABS_KEYS: RegularLangKey[] = [
'StarsTransactionsAll',
@ -178,17 +171,16 @@ const StarsBalanceModal = ({
const renderStarsSection = () => {
return (
<>
<img className={styles.logo} src={StarLogo} alt="" draggable={false} />
<img className={styles.logoBackground} src={StarsBackground} alt="" draggable={false} />
<h2 className={styles.headerText}>
{starsNeeded ? oldLang('StarsNeededTitle', ongoingTransactionAmount) : oldLang('TelegramStars')}
</h2>
<div className={styles.description}>
{renderText(
<ParticlesHeader
model="swaying-star"
color="gold"
title={starsNeeded ? oldLang('StarsNeededTitle', ongoingTransactionAmount) : oldLang('TelegramStars')}
description={renderText(
starsNeededText || oldLang('TelegramStarsInfo'),
['simple_markdown', 'emoji'],
)}
</div>
isDisabled={!isOpen}
/>
{canBuyPremium && !areBuyOptionsShown && (
<Button
className={styles.starButton}
@ -222,18 +214,13 @@ const StarsBalanceModal = ({
const tonAmount = convertCurrencyFromBaseUnit(balance?.amount || 0, TON_CURRENCY_CODE);
return (
<>
<AnimatedIconWithPreview
size={160}
tgsUrl={LOCAL_TGS_URLS.Diamond}
nonInteractive
noLoop={false}
<ParticlesHeader
model="speeding-diamond"
color="blue"
title={lang('CurrencyTon')}
description={lang('DescriptionAboutTon')}
isDisabled={!isOpen}
/>
<h2 className={styles.headerText}>
{lang('CurrencyTon')}
</h2>
<div className={styles.description}>
{lang('DescriptionAboutTon')}
</div>
<div className={styles.tonBalanceContainer}>
<div className={styles.tonBalance}>
<Icon name="toncoin" className={styles.tonIconBalance} />

View File

@ -32,7 +32,7 @@ import StarTopupOptionList from '../StarTopupOptionList';
import styles from './StarsGiftModal.module.scss';
import StarLogo from '../../../../assets/icons/StarLogo.svg';
import StarLogo from '../../../../assets/icons/GoldStar.svg';
import StarsBackground from '../../../../assets/stars-bg.png';
export type OwnProps = {

689
src/util/particles.ts Normal file
View File

@ -0,0 +1,689 @@
// GPU-Accelerated Particle System Library
import generateUniqueId from './generateUniqueId.ts';
import { getIsInBackground } from '../hooks/window/useBackgroundMode.ts';
export interface ParticleConfig {
width?: number;
height?: number;
particleCount?: number;
color?: Color | ColorPair;
speed?: number;
baseSize?: number;
minSpawnRadius?: number;
maxSpawnRadius?: number;
distanceLimit?: number;
fadeInTime?: number;
fadeOutTime?: number;
minLifetime?: number;
maxLifetime?: number;
maxStartTimeDelay?: number;
edgeFadeZone?: number;
centerShift?: readonly [number, number];
accelerationFactor?: number;
selfDestroyTime?: number;
}
interface Locations {
attributes: {
startPosition: number;
velocity: number;
startTime: number;
lifetime: number;
size: number;
baseOpacity: number;
color: number;
};
uniforms: {
resolution: WebGLUniformLocation | null;
time: WebGLUniformLocation | null;
canvasWidth: WebGLUniformLocation | null;
canvasHeight: WebGLUniformLocation | null;
accelerationFactor: WebGLUniformLocation | null;
fadeInTime: WebGLUniformLocation | null;
fadeOutTime: WebGLUniformLocation | null;
edgeFadeZone: WebGLUniformLocation | null;
rotationMatrices: WebGLUniformLocation | null;
spawnCenter: WebGLUniformLocation | null;
};
}
interface Buffers {
startPosition: WebGLBuffer | null;
velocity: WebGLBuffer | null;
startTime: WebGLBuffer | null;
lifetime: WebGLBuffer | null;
size: WebGLBuffer | null;
baseOpacity: WebGLBuffer | null;
color: WebGLBuffer | null;
}
interface ParticleSystem {
id: string;
config: Required<ParticleConfig>;
buffers: Buffers;
startTime: number;
seed: number;
centerX: number;
centerY: number;
avgDistance: number;
selfDestroyTimeout?: number;
}
interface ParticleSystemManager {
addSystem: (options: Partial<ParticleConfig>) => NoneToVoidFunction;
}
type Color = readonly [number, number, number];
type ColorPair = readonly [Color, Color];
export const PARTICLE_COLORS = {
blue: [0, 152 / 255, 234 / 255] as Color,
blueGradient: [
[1 / 255, 88 / 255, 175 / 255],
[103 / 255, 208 / 255, 255 / 255],
] as ColorPair,
purple: [150 / 255, 111 / 255, 254 / 255] as Color,
purpleGradient: [
[107 / 255, 147 / 255, 255 / 255],
[228 / 255, 106 / 255, 206 / 255],
] as ColorPair,
gold: [255 / 255, 191 / 255, 10 / 255] as Color,
goldGradient: [
[253 / 255, 235 / 255, 50 / 255],
[215 / 255, 89 / 255, 2 / 255],
] as ColorPair,
};
export const PARTICLE_BURST_PARAMS: Partial<ParticleConfig> = {
particleCount: 5,
distanceLimit: 1,
fadeInTime: 0.05,
minLifetime: 3,
maxLifetime: 3,
maxStartTimeDelay: 0,
selfDestroyTime: 3,
minSpawnRadius: 5,
maxSpawnRadius: 50,
};
const DEFAULT_CONFIG: Required<ParticleConfig> = {
width: 350,
height: 230,
particleCount: 100,
color: [0, 152 / 255, 234 / 255], // #0098EA (TON)
speed: 18,
baseSize: 6,
minSpawnRadius: 35,
maxSpawnRadius: 70,
distanceLimit: 0.7,
fadeInTime: 0.25,
fadeOutTime: 1,
minLifetime: 4,
maxLifetime: 6,
maxStartTimeDelay: 3,
edgeFadeZone: 50,
centerShift: [0, 0],
accelerationFactor: 3,
selfDestroyTime: 0,
};
const SIZE_SMALL = 0.67;
const SIZE_MEDIUM = 1.33;
const SIZE_LARGE = 2.2;
const canvasManagers = new Map<HTMLCanvasElement, ParticleSystemManager>();
export function setupParticles(
canvas: HTMLCanvasElement,
options: Partial<ParticleConfig>,
) {
let manager = canvasManagers.get(canvas);
if (!manager) {
manager = createParticleSystemManager(canvas);
canvasManagers.set(canvas, manager);
}
return manager.addSystem(options);
}
function createParticleSystemManager(canvas: HTMLCanvasElement) {
const gl = canvas.getContext('webgl', {
alpha: true,
antialias: false,
preserveDrawingBuffer: false,
})!;
if (!gl) {
throw new Error('WebGL not supported');
}
const vertexShader = createShader(gl, gl.VERTEX_SHADER, VERTEX_SHADER_SOURCE);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE);
if (!vertexShader || !fragmentShader) {
throw new Error('Failed to create shaders');
}
const program = createProgram(gl, vertexShader, fragmentShader)!;
if (!program) {
throw new Error('Failed to create shader program');
}
const dpr = window.devicePixelRatio || 1;
const systems = new Map<string, ParticleSystem>();
const locations: Locations = {
attributes: {
startPosition: gl.getAttribLocation(program, 'a_startPosition'),
velocity: gl.getAttribLocation(program, 'a_velocity'),
startTime: gl.getAttribLocation(program, 'a_startTime'),
lifetime: gl.getAttribLocation(program, 'a_lifetime'),
size: gl.getAttribLocation(program, 'a_size'),
baseOpacity: gl.getAttribLocation(program, 'a_baseOpacity'),
color: gl.getAttribLocation(program, 'a_color'),
},
uniforms: {
resolution: gl.getUniformLocation(program, 'u_resolution'),
time: gl.getUniformLocation(program, 'u_time'),
canvasWidth: gl.getUniformLocation(program, 'u_canvasWidth'),
canvasHeight: gl.getUniformLocation(program, 'u_canvasHeight'),
accelerationFactor: gl.getUniformLocation(program, 'u_accelerationFactor'),
fadeInTime: gl.getUniformLocation(program, 'u_fadeInTime'),
fadeOutTime: gl.getUniformLocation(program, 'u_fadeOutTime'),
edgeFadeZone: gl.getUniformLocation(program, 'u_edgeFadeZone'),
rotationMatrices: gl.getUniformLocation(program, 'u_rotationMatrices'),
spawnCenter: gl.getUniformLocation(program, 'u_spawnCenter'),
},
};
let animationId: number | undefined;
let unsubscribeFromIsInBackground: NoneToVoidFunction | undefined = undefined;
function initParticleData(system: ParticleSystem): void {
const rng = new SeededRandom(system.seed);
const { config } = system;
const startPositions = new Float32Array(config.particleCount * 2);
const velocities = new Float32Array(config.particleCount * 2);
const startTimes = new Float32Array(config.particleCount);
const lifetimes = new Float32Array(config.particleCount);
const sizes = new Float32Array(config.particleCount);
const baseOpacities = new Float32Array(config.particleCount);
const colors = new Float32Array(config.particleCount * 3); // RGB for each particle
for (let i = 0; i < config.particleCount; i++) {
const angle = rng.next() * Math.PI * 2;
const spawnRadius = rng.nextBetween(config.minSpawnRadius, config.maxSpawnRadius);
const cos = Math.cos(angle);
const sin = Math.sin(angle);
const spawnX = system.centerX + cos * spawnRadius;
const spawnY = system.centerY + sin * spawnRadius;
startPositions[i * 2] = spawnX * dpr;
startPositions[i * 2 + 1] = spawnY * dpr;
lifetimes[i] = rng.nextBetween(config.minLifetime, config.maxLifetime);
startTimes[i] = rng.next() * config.maxStartTimeDelay;
const travelDist = rng.nextBetween(
system.avgDistance * config.distanceLimit * 0.5,
system.avgDistance * config.distanceLimit,
);
// Calculate speed based on travel distance and lifetime
const speed = (travelDist / lifetimes[i]) * dpr;
velocities[i * 2] = cos * speed;
velocities[i * 2 + 1] = sin * speed;
const sizeVariant = rng.next();
if (sizeVariant < 0.3) {
sizes[i] = config.baseSize * SIZE_SMALL * dpr;
} else if (sizeVariant < 0.7) {
sizes[i] = config.baseSize * SIZE_MEDIUM * dpr;
} else {
sizes[i] = config.baseSize * SIZE_LARGE * dpr;
}
baseOpacities[i] = rng.nextBetween(0.3, 0.8);
const particleColor = resolveColor(config.color, rng);
colors[i * 3] = particleColor[0];
colors[i * 3 + 1] = particleColor[1];
colors[i * 3 + 2] = particleColor[2];
}
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.startPosition);
gl.bufferData(gl.ARRAY_BUFFER, startPositions, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.velocity);
gl.bufferData(gl.ARRAY_BUFFER, velocities, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.startTime);
gl.bufferData(gl.ARRAY_BUFFER, startTimes, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.lifetime);
gl.bufferData(gl.ARRAY_BUFFER, lifetimes, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.size);
gl.bufferData(gl.ARRAY_BUFFER, sizes, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.baseOpacity);
gl.bufferData(gl.ARRAY_BUFFER, baseOpacities, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.color);
gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
}
function initCanvas(): void {
// Find the max canvas size from all systems
let maxWidth = 0;
let maxHeight = 0;
systems.forEach((system) => {
maxWidth = Math.max(maxWidth, system.config.width);
maxHeight = Math.max(maxHeight, system.config.height);
});
// Default to first system's size if no systems yet
if (systems.size === 0) {
maxWidth = DEFAULT_CONFIG.width;
maxHeight = DEFAULT_CONFIG.height;
}
if (canvas.width !== maxWidth * dpr || canvas.height !== maxHeight * dpr) {
canvas.width = maxWidth * dpr;
canvas.height = maxHeight * dpr;
canvas.style.width = maxWidth + 'px';
canvas.style.height = maxHeight + 'px';
}
gl.viewport(0, 0, canvas.width, canvas.height);
}
function initWebGLState(): void {
gl.useProgram(program);
// Set static uniforms that will be updated per system
gl.uniform2f(locations.uniforms.resolution, canvas.width, canvas.height);
gl.uniformMatrix2fv(locations.uniforms.rotationMatrices, false, getRotations());
// Set blending state
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
// Set clear color
gl.clearColor(0, 0, 0, 0);
}
function render(currentTime: number): void {
if (!animationId) return;
gl.clear(gl.COLOR_BUFFER_BIT);
// Render all systems
systems.forEach((system) => {
const systemTime = (currentTime - system.startTime) / 1000;
// Set uniforms for this system
gl.uniform1f(locations.uniforms.time, systemTime);
gl.uniform1f(locations.uniforms.canvasWidth, system.config.width * dpr);
gl.uniform1f(locations.uniforms.canvasHeight, system.config.height * dpr);
gl.uniform1f(locations.uniforms.accelerationFactor, system.config.accelerationFactor);
gl.uniform1f(locations.uniforms.fadeInTime, system.config.fadeInTime);
gl.uniform1f(locations.uniforms.fadeOutTime, system.config.fadeOutTime);
gl.uniform1f(locations.uniforms.edgeFadeZone, system.config.edgeFadeZone * dpr);
gl.uniform2f(locations.uniforms.spawnCenter, system.centerX * dpr, system.centerY * dpr);
// Bind attributes for this system
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.startPosition);
gl.enableVertexAttribArray(locations.attributes.startPosition);
gl.vertexAttribPointer(locations.attributes.startPosition, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.velocity);
gl.enableVertexAttribArray(locations.attributes.velocity);
gl.vertexAttribPointer(locations.attributes.velocity, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.startTime);
gl.enableVertexAttribArray(locations.attributes.startTime);
gl.vertexAttribPointer(locations.attributes.startTime, 1, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.lifetime);
gl.enableVertexAttribArray(locations.attributes.lifetime);
gl.vertexAttribPointer(locations.attributes.lifetime, 1, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.size);
gl.enableVertexAttribArray(locations.attributes.size);
gl.vertexAttribPointer(locations.attributes.size, 1, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.baseOpacity);
gl.enableVertexAttribArray(locations.attributes.baseOpacity);
gl.vertexAttribPointer(locations.attributes.baseOpacity, 1, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, system.buffers.color);
gl.enableVertexAttribArray(locations.attributes.color);
gl.vertexAttribPointer(locations.attributes.color, 3, gl.FLOAT, false, 0, 0);
// Draw particles for this system
gl.drawArrays(gl.POINTS, 0, system.config.particleCount);
});
animationId = requestAnimationFrame(render);
}
function addSystem(options: Partial<ParticleConfig>) {
const id = generateUniqueId();
const config: Required<ParticleConfig> = { ...DEFAULT_CONFIG, ...options };
const buffers: Buffers = {
startPosition: gl.createBuffer(),
velocity: gl.createBuffer(),
startTime: gl.createBuffer(),
lifetime: gl.createBuffer(),
size: gl.createBuffer(),
baseOpacity: gl.createBuffer(),
color: gl.createBuffer(),
};
const system: ParticleSystem = {
id,
config,
buffers,
startTime: performance.now(),
seed: Math.floor(Math.random() * 1000000),
centerX: config.width / 2 + config.centerShift[0],
centerY: config.height / 2 + config.centerShift[1],
avgDistance: (config.width / 2 + config.height / 2) / 2,
};
systems.set(id, system);
initParticleData(system);
initCanvas();
if (config.selfDestroyTime) {
system.selfDestroyTimeout = window.setTimeout(() => {
removeSystem(id);
}, config.selfDestroyTime * 1000);
}
if (systems.size === 1) {
initWebGLState();
unsubscribeFromIsInBackground = getIsInBackground.subscribe(() => {
const isActive = !getIsInBackground();
if (isActive && !animationId) {
animationId = requestAnimationFrame(render);
} else if (!isActive && animationId) {
cancelAnimationFrame(animationId);
animationId = undefined;
}
});
animationId = requestAnimationFrame(render);
}
return () => removeSystem(id);
}
function removeSystem(id: string): void {
const system = systems.get(id);
if (!system) return;
if (system.selfDestroyTimeout) {
clearTimeout(system.selfDestroyTimeout);
}
Object.values(system.buffers).forEach((buffer) => {
if (buffer) gl.deleteBuffer(buffer);
});
systems.delete(id);
if (systems.size === 0) {
destroy();
}
}
function destroy(): void {
if (animationId !== undefined) {
cancelAnimationFrame(animationId);
animationId = undefined;
}
unsubscribeFromIsInBackground?.();
systems.clear();
gl.deleteProgram(program);
gl.deleteShader(vertexShader!);
gl.deleteShader(fragmentShader!);
canvasManagers.delete(canvas);
}
return { addSystem };
}
const VERTEX_SHADER_SOURCE = `
attribute vec2 a_startPosition;
attribute vec2 a_velocity;
attribute float a_startTime;
attribute float a_lifetime;
attribute float a_size;
attribute float a_baseOpacity;
attribute vec3 a_color;
uniform vec2 u_resolution;
uniform float u_time;
uniform float u_canvasWidth;
uniform float u_canvasHeight;
uniform float u_accelerationFactor;
uniform float u_fadeInTime;
uniform float u_fadeOutTime;
uniform float u_edgeFadeZone;
uniform mat2 u_rotationMatrices[18];
uniform vec2 u_spawnCenter;
varying float v_opacity;
varying vec3 v_color;
void main() {
float totalAge = u_time - a_startTime;
float age = mod(totalAge, a_lifetime);
// For the initial animation, fade in all particles
float globalFadeIn = min(u_time / u_fadeInTime, 1.0);
float lifeRatio = age / a_lifetime;
// Calculate rotation based on completed lifecycles
float lifecycleCount = floor(totalAge / a_lifetime);
int rotationIndex = int(mod(lifecycleCount, 18.0));
// Get rotation matrix
mat2 rotationMatrix = u_rotationMatrices[rotationIndex];
// Rotate start position around spawn center
vec2 startOffset = a_startPosition - u_spawnCenter;
vec2 rotatedStartOffset = rotationMatrix * startOffset;
vec2 rotatedStartPosition = u_spawnCenter + rotatedStartOffset;
// Apply rotation matrix to velocity
vec2 rotatedVelocity = rotationMatrix * a_velocity;
// Apply shoot-out effect: fast initial speed that slows down
float speedMultiplier = 1.0 + u_accelerationFactor * exp(-3.0 * lifeRatio);
vec2 position = rotatedStartPosition + rotatedVelocity * age * speedMultiplier;
float opacity = 1.0;
if (lifeRatio < u_fadeInTime / a_lifetime) {
opacity = (lifeRatio * a_lifetime) / u_fadeInTime;
} else if (lifeRatio > 1.0 - u_fadeOutTime / a_lifetime) {
opacity = (1.0 - lifeRatio) * a_lifetime / u_fadeOutTime;
}
opacity *= a_baseOpacity * globalFadeIn;
float distToLeft = position.x;
float distToRight = u_canvasWidth - position.x;
float distToTop = position.y;
float distToBottom = u_canvasHeight - position.y;
float distToEdge = min(min(distToLeft, distToRight), min(distToTop, distToBottom));
if (distToEdge < u_edgeFadeZone) {
opacity *= distToEdge / u_edgeFadeZone;
}
vec2 clipSpace = ((position / u_resolution) * 2.0 - 1.0) * vec2(1, -1);
gl_Position = vec4(clipSpace, 0, 1);
gl_PointSize = a_size;
v_opacity = opacity;
v_color = a_color;
}
`;
const FRAGMENT_SHADER_SOURCE = `
precision mediump float;
varying float v_opacity;
varying vec3 v_color;
void main() {
vec2 coord = gl_PointCoord - vec2(0.5);
// Create a four-pointed star
float absX = abs(coord.x);
float absY = abs(coord.y);
// Star parameters
float innerSize = 0.12; // Size of center square
float armLength = 0.45; // Length of star arms
float armWidth = 0.08; // Half-width of star arms at base
float dist = 1.0; // Default to outside
// Center square
if (absX <= innerSize && absY <= innerSize) {
dist = max(absX, absY) - innerSize;
}
// Horizontal arms (left and right points)
else if (absY <= armWidth && absX <= armLength) {
// Taper the arms - they get narrower toward the tips
float normalizedX = (absX - innerSize) / (armLength - innerSize);
float taperFactor = 1.0 - normalizedX * 0.8; // Taper to 20% of original width
float currentArmWidth = armWidth * taperFactor;
dist = absY - currentArmWidth;
}
// Vertical arms (top and bottom points)
else if (absX <= armWidth && absY <= armLength) {
// Taper the arms - they get narrower toward the tips
float normalizedY = (absY - innerSize) / (armLength - innerSize);
float taperFactor = 1.0 - normalizedY * 0.8; // Taper to 20% of original width
float currentArmWidth = armWidth * taperFactor;
dist = absX - currentArmWidth;
}
// Use smoothstep for anti-aliasing to reduce subpixel artifacts
float alpha = 1.0 - smoothstep(-0.01, 0.01, dist);
if (alpha <= 0.0) {
discard;
}
gl_FragColor = vec4(v_color * v_opacity * alpha, v_opacity * alpha);
}
`;
function createShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader | undefined {
const shader = gl.createShader(type);
if (!shader) return undefined;
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
gl.deleteShader(shader);
return undefined;
}
return shader;
}
function createProgram(gl: WebGLRenderingContext,
vertexShader: WebGLShader,
fragmentShader: WebGLShader): WebGLProgram | undefined {
const program = gl.createProgram();
if (!program) return undefined;
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
gl.deleteProgram(program);
return undefined;
}
return program;
}
class SeededRandom {
private seed: number;
constructor(seed: number) {
this.seed = seed;
}
next(): number {
this.seed = (this.seed * 9301 + 49297) % 233280;
return this.seed / 233280;
}
nextBetween(min: number, max: number): number {
return min + (max - min) * this.next();
}
}
let rotationsCache: Float32Array | undefined;
function getRotations(): Float32Array {
if (!rotationsCache) {
const ROTATION_COUNT = 18; // n = [0..17]
const ROTATION_ANGLE_DEGREES = 220;
rotationsCache = new Float32Array(ROTATION_COUNT * 4); // mat2 = 4 floats
for (let i = 0; i < ROTATION_COUNT; i++) {
const angle = (ROTATION_ANGLE_DEGREES * Math.PI / 180) * i;
const cos = Math.cos(angle);
const sin = Math.sin(angle);
// mat2 in column-major order: [cos, sin, -sin, cos]
rotationsCache[i * 4] = cos;
rotationsCache[i * 4 + 1] = sin;
rotationsCache[i * 4 + 2] = -sin;
rotationsCache[i * 4 + 3] = cos;
}
}
return rotationsCache;
}
function resolveColor(colorDefinition: Color | ColorPair, rng: SeededRandom) {
if (Array.isArray(colorDefinition[0])) {
const [color1, color2] = colorDefinition as ColorPair;
return [
rng.nextBetween(color1[0], color2[0]),
rng.nextBetween(color1[1], color2[1]),
rng.nextBetween(color1[2], color2[2]),
] as Color;
}
return colorDefinition as Color;
}