Spaces:
Running
Running
| <script lang="ts"> | |
| import { onMount } from 'svelte'; | |
| import { gsap } from 'gsap'; | |
| export let loading = true; | |
| let container: HTMLDivElement; | |
| let spinner: HTMLDivElement; | |
| let fadeOut = false; | |
| onMount(() => { | |
| const tl = gsap.timeline(); | |
| tl.from('.loading-title', { | |
| opacity: 0, | |
| y: 10, | |
| duration: 0.3, | |
| ease: 'power3.out' | |
| }) | |
| .from('.spinner', { | |
| opacity: 0, | |
| scale: 0.8, | |
| duration: 0.2, | |
| ease: 'power3.out' | |
| }, '-=0.1'); | |
| gsap.to(spinner, { | |
| rotation: 360, | |
| duration: 1, | |
| repeat: -1, | |
| ease: 'none' | |
| }); | |
| return () => { | |
| tl.kill(); | |
| gsap.killTweensOf(spinner); | |
| }; | |
| }); | |
| $: if (!loading && container && !fadeOut) { | |
| fadeOut = true; | |
| gsap.to(container, { | |
| opacity: 0, | |
| duration: 0.25, | |
| ease: 'power2.inOut', | |
| onComplete: () => { | |
| container.style.display = 'none'; | |
| } | |
| }); | |
| } | |
| </script> | |
| {#if loading || fadeOut} | |
| <div bind:this={container} class="loading-screen"> | |
| <div class="loading-content"> | |
| <h1 class="loading-title">VibeGame</h1> | |
| <div bind:this={spinner} class="spinner"> | |
| <div class="spinner-ring"></div> | |
| <div class="spinner-ring"></div> | |
| <div class="spinner-ring"></div> | |
| </div> | |
| </div> | |
| </div> | |
| {/if} | |
| <style> | |
| .loading-screen { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100vw; | |
| height: 100vh; | |
| background: #0B0A09; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| z-index: 10000; | |
| } | |
| .loading-content { | |
| text-align: center; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 2.5rem; | |
| } | |
| .loading-title { | |
| font-size: 2.5rem; | |
| font-weight: 200; | |
| margin: 0; | |
| color: #ffffff; | |
| letter-spacing: -0.02em; | |
| } | |
| .spinner { | |
| position: relative; | |
| width: 40px; | |
| height: 40px; | |
| } | |
| .spinner-ring { | |
| position: absolute; | |
| width: 100%; | |
| height: 100%; | |
| border: 2px solid transparent; | |
| border-radius: 50%; | |
| border-top-color: #ffffff; | |
| opacity: 0.3; | |
| } | |
| .spinner-ring:nth-child(1) { | |
| animation: spin 1.5s linear infinite; | |
| } | |
| .spinner-ring:nth-child(2) { | |
| width: 80%; | |
| height: 80%; | |
| top: 10%; | |
| left: 10%; | |
| border-top-color: #ffffff; | |
| opacity: 0.5; | |
| animation: spin 1.2s linear infinite reverse; | |
| } | |
| .spinner-ring:nth-child(3) { | |
| width: 60%; | |
| height: 60%; | |
| top: 20%; | |
| left: 20%; | |
| border-top-color: #ffffff; | |
| opacity: 0.8; | |
| animation: spin 0.9s linear infinite; | |
| } | |
| @keyframes spin { | |
| to { | |
| transform: rotate(360deg); | |
| } | |
| } | |
| </style> | |