From 6b3eaf2c706b2ea479aa7ba508b05adb4bab2db4 Mon Sep 17 00:00:00 2001 From: Janis Date: Thu, 18 Dec 2025 11:20:05 +0100 Subject: [PATCH] feat: Enhance win effects and animations in OfflineView component --- src/views/OfflineView.vue | 104 +++++++++++++++++++++++++++++++++----- vite.config.ts | 1 - 2 files changed, 92 insertions(+), 13 deletions(-) diff --git a/src/views/OfflineView.vue b/src/views/OfflineView.vue index c1c5c35..8f1eff1 100644 --- a/src/views/OfflineView.vue +++ b/src/views/OfflineView.vue @@ -12,6 +12,10 @@ const reelStates = ref([ const globalSpinning = ref(false) const hasSpun = ref(false) +const glowThird = ref(false) +const winBlink = ref(false) +const winFire = ref(false) +let winEffectsTimer: number | undefined const isWinner = computed(() => { const [r1, r2, r3] = reelStates.value; @@ -26,20 +30,56 @@ const spin = (): void => { globalSpinning.value = true; hasSpun.value = false; - - reelStates.value.forEach((reel, index) => { + // Reset possible win effects + winBlink.value = false; + winFire.value = false; + if (winEffectsTimer) { + clearTimeout(winEffectsTimer); + winEffectsTimer = undefined; + } + reelStates.value.forEach((reel) => { reel.isSpinning = true; + reel.value = getRandomSymbol(); + }); + + const base0 = 1500; + const gap = 800; + const base1 = base0 + gap; + const base2 = base1 + gap; + setTimeout(() => { + reelStates.value[0].isSpinning = false; + }, base0); + setTimeout(() => { + reelStates.value[1].isSpinning = false; + }, base1); + setTimeout(() => { + const firstTwoMatch = reelStates.value[0].value === reelStates.value[1].value && + reelStates.value[0].value !== '❓'; + const extraDelay = firstTwoMatch ? 1000 : 0; + + glowThird.value = firstTwoMatch; setTimeout(() => { - reel.value = getRandomSymbol(); - reel.isSpinning = false; + reelStates.value[2].isSpinning = false; + glowThird.value = false; + globalSpinning.value = false; + hasSpun.value = true; - if (index === 2) { - globalSpinning.value = false; - hasSpun.value = true; + const allThreeMatch = + reelStates.value[0].value !== '❓' && + reelStates.value[0].value === reelStates.value[1].value && + reelStates.value[1].value === reelStates.value[2].value; + if (allThreeMatch) { + winFire.value = true; + winBlink.value = true; + winEffectsTimer = window.setTimeout(() => { + winFire.value = false; + winBlink.value = false; + winEffectsTimer = undefined; + }, 3000); } - }, 1500 + (index * 800)); - }); + }, base2 - base1 + extraDelay); + }, base1); }; @@ -54,16 +94,20 @@ const spin = (): void => { leave-active-class="animate__animated animate__fadeOutUp" > -
Offline Casino
+
Offline Drehmaschine
-
+
{{ symbols[n % symbols.length] }}
-
{{ reel.value }}
+
{{ reel.value }}
@@ -129,4 +173,40 @@ const spin = (): void => { .animate-bounce { animation: bounce 0.5s infinite alternate; } @keyframes bounce { from { transform: scale(1); } to { transform: scale(1.1); } } + +.glow-fire { + border-color: #ff9800; + box-shadow: + 0 0 10px 2px rgba(255, 152, 0, 0.8), + 0 0 18px 6px rgba(255, 87, 34, 0.5), + inset 0 0 8px 2px rgba(255, 193, 7, 0.4); + animation: fireGlow 900ms ease-in-out infinite alternate; +} + +@keyframes fireGlow { + 0% { + box-shadow: + 0 0 6px 1px rgba(255, 152, 0, 0.6), + 0 0 12px 3px rgba(255, 87, 34, 0.35), + inset 0 0 5px 1px rgba(255, 193, 7, 0.3); + transform: translateY(0) scale(1); + } + 100% { + box-shadow: + 0 0 14px 3px rgba(255, 152, 0, 1), + 0 0 24px 8px rgba(255, 87, 34, 0.6), + inset 0 0 10px 3px rgba(255, 193, 7, 0.5); + transform: translateY(-1px) scale(1.02); + } +} + +.blink-win { + animation: blinkWin 300ms steps(1, end) infinite; +} + +@keyframes blinkWin { + 0% { opacity: 1; filter: drop-shadow(0 0 0 rgba(255,255,255,0)); } + 50% { opacity: 0.2; filter: drop-shadow(0 0 6px rgba(255,255,255,0.6)); } + 100% { opacity: 1; filter: drop-shadow(0 0 0 rgba(255,255,255,0)); } +} diff --git a/vite.config.ts b/vite.config.ts index e2200a3..e2890d8 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,7 +4,6 @@ import vue from '@vitejs/plugin-vue' import vueJsx from '@vitejs/plugin-vue-jsx' import vueDevTools from 'vite-plugin-vue-devtools' import { quasar, transformAssetUrls } from '@quasar/vite-plugin' - import { VitePWA } from 'vite-plugin-pwa' // https://vite.dev/config/