feat: animate home screen buttons on click

This commit is contained in:
2025-11-13 13:52:40 +01:00
parent 0bca11dfe0
commit e7912c90a2
7 changed files with 63 additions and 5 deletions

View File

@@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import gsap from "gsap";
import GameButton from "./GameButton.vue"; import GameButton from "./GameButton.vue";
import PictochatButton from "./PictochatButton.vue"; import PictochatButton from "./PictochatButton.vue";
import DownloadPlayButton from "./DownloadPlayButton.vue"; import DownloadPlayButton from "./DownloadPlayButton.vue";
@@ -26,15 +27,44 @@ const nextBottomButton = ref<"downloadPlay" | "pictochat">("pictochat");
const selectorPosition = computed(() => BUTTONS_CONFIG[selectedButton.value]); const selectorPosition = computed(() => BUTTONS_CONFIG[selectedButton.value]);
const animationPercentage = ref(0);
const getButtonOffset = (button: ButtonType) => {
if (selectedButton.value === button) return animationPercentage.value * -200;
return 0;
};
const getOpacity = () => (1 - animationPercentage.value) * 100;
useScreenClick((x: number, y: number) => { useScreenClick((x: number, y: number) => {
for (const [buttonName, config] of Object.entries(BUTTONS_CONFIG)) { if (animationPercentage.value != 0) return;
for (const [buttonName, config] of Object.entries(BUTTONS_CONFIG) as [
ButtonType,
ButtonConfig,
][]) {
if ( if (
x >= config.sx && x >= config.sx &&
x <= config.sx + config.sw && x <= config.sx + config.sw &&
y >= config.sy && y >= config.sy &&
y <= config.sy + config.sh y <= config.sy + config.sh
) { ) {
selectedButton.value = buttonName as ButtonType; if (selectedButton.value === buttonName) {
gsap.fromTo(
animationPercentage,
{ value: 0 },
{
value: 1,
duration: 0.35,
ease: "none",
onComplete: () => {
throw new Error("not implemented: onComplete in button click");
},
},
);
} else {
selectedButton.value = buttonName;
}
if (buttonName === "pictochat" || buttonName === "downloadPlay") { if (buttonName === "pictochat" || buttonName === "downloadPlay") {
nextBottomButton.value = buttonName; nextBottomButton.value = buttonName;
@@ -99,14 +129,20 @@ onUnmounted(() => {
</script> </script>
<template> <template>
<GameButton :x="BUTTONS_CONFIG.game.x" :y="BUTTONS_CONFIG.game.y" /> <GameButton
:x="BUTTONS_CONFIG.game.x"
:y="BUTTONS_CONFIG.game.y + getButtonOffset('game')"
:opacity="getOpacity()"
/>
<DownloadPlayButton <DownloadPlayButton
:x="BUTTONS_CONFIG.downloadPlay.x" :x="BUTTONS_CONFIG.downloadPlay.x"
:y="BUTTONS_CONFIG.downloadPlay.y" :y="BUTTONS_CONFIG.downloadPlay.y + getButtonOffset('downloadPlay')"
:opacity="getOpacity()"
/> />
<PictochatButton <PictochatButton
:x="BUTTONS_CONFIG.pictochat.x" :x="BUTTONS_CONFIG.pictochat.x"
:y="BUTTONS_CONFIG.pictochat.y" :y="BUTTONS_CONFIG.pictochat.y + getButtonOffset('pictochat')"
:opacity="getOpacity()"
/> />
<Selector <Selector
@@ -114,5 +150,6 @@ onUnmounted(() => {
:y="selectorPosition.sy" :y="selectorPosition.sy"
:width="selectorPosition.sw" :width="selectorPosition.sw"
:height="selectorPosition.sh" :height="selectorPosition.sh"
:opacity="getOpacity()"
/> />
</template> </template>

View File

@@ -2,6 +2,7 @@
const props = defineProps<{ const props = defineProps<{
x: number; x: number;
y: number; y: number;
opacity: number;
}>(); }>();
const buttonImage = useTemplateRef("buttonImage"); const buttonImage = useTemplateRef("buttonImage");
@@ -9,6 +10,7 @@ const buttonImage = useTemplateRef("buttonImage");
useRender((ctx) => { useRender((ctx) => {
if (!buttonImage.value) return; if (!buttonImage.value) return;
ctx.globalAlpha = props.opacity / 100;
ctx.drawImage(buttonImage.value, props.x, props.y); ctx.drawImage(buttonImage.value, props.x, props.y);
}); });
</script> </script>

View File

@@ -2,6 +2,7 @@
const props = defineProps<{ const props = defineProps<{
x: number; x: number;
y: number; y: number;
opacity: number;
}>(); }>();
const buttonImage = useTemplateRef("buttonImage"); const buttonImage = useTemplateRef("buttonImage");
@@ -9,6 +10,7 @@ const buttonImage = useTemplateRef("buttonImage");
useRender((ctx) => { useRender((ctx) => {
if (!buttonImage.value) return; if (!buttonImage.value) return;
ctx.globalAlpha = props.opacity / 100;
ctx.drawImage(buttonImage.value, props.x, props.y); ctx.drawImage(buttonImage.value, props.x, props.y);
}); });
</script> </script>

View File

@@ -2,6 +2,7 @@
const props = defineProps<{ const props = defineProps<{
x: number; x: number;
y: number; y: number;
opacity: number;
}>(); }>();
const buttonImage = useTemplateRef("buttonImage"); const buttonImage = useTemplateRef("buttonImage");
@@ -9,6 +10,7 @@ const buttonImage = useTemplateRef("buttonImage");
useRender((ctx) => { useRender((ctx) => {
if (!buttonImage.value) return; if (!buttonImage.value) return;
ctx.globalAlpha = props.opacity / 100;
ctx.drawImage(buttonImage.value, props.x, props.y); ctx.drawImage(buttonImage.value, props.x, props.y);
}); });
</script> </script>

View File

@@ -4,6 +4,7 @@ const props = defineProps<{
y: number; y: number;
width: number; width: number;
height: number; height: number;
opacity: number;
}>(); }>();
const cornerImage = useTemplateRef("cornerImage"); const cornerImage = useTemplateRef("cornerImage");
@@ -45,6 +46,8 @@ useRender((ctx) => {
const w = Math.floor(currentWidth); const w = Math.floor(currentWidth);
const h = Math.floor(currentHeight); const h = Math.floor(currentHeight);
ctx.globalAlpha = props.opacity / 100;
ctx.drawImage(cornerImage.value, x, y); ctx.drawImage(cornerImage.value, x, y);
ctx.save(); ctx.save();

View File

@@ -12,6 +12,7 @@
"lint": "eslint --fix --cache ." "lint": "eslint --fix --cache ."
}, },
"dependencies": { "dependencies": {
"gsap": "^3.13.0",
"nuxt": "^4.2.1", "nuxt": "^4.2.1",
"vue": "^3.5.22", "vue": "^3.5.22",
"vue-router": "^4.6.3" "vue-router": "^4.6.3"

11
pnpm-lock.yaml generated
View File

@@ -7,6 +7,9 @@ settings:
importers: importers:
.: .:
dependencies: dependencies:
gsap:
specifier: ^3.13.0
version: 3.13.0
nuxt: nuxt:
specifier: ^4.2.1 specifier: ^4.2.1
version: 4.2.1(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.24)(db0@0.3.4)(eslint@9.39.1(jiti@2.6.1))(ioredis@5.8.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.53.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.2.2(jiti@2.6.1)(terser@5.44.1)(yaml@2.8.1))(yaml@2.8.1) version: 4.2.1(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.24)(db0@0.3.4)(eslint@9.39.1(jiti@2.6.1))(ioredis@5.8.2)(magicast@0.5.1)(optionator@0.9.4)(rollup@4.53.1)(terser@5.44.1)(typescript@5.9.3)(vite@7.2.2(jiti@2.6.1)(terser@5.44.1)(yaml@2.8.1))(yaml@2.8.1)
@@ -3698,6 +3701,12 @@ packages:
integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==, integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==,
} }
gsap@3.13.0:
resolution:
{
integrity: sha512-QL7MJ2WMjm1PHWsoFrAQH/J8wUeqZvMtHO58qdekHpCfhvhSL4gSiz6vJf5EeMP0LOn3ZCprL2ki/gjED8ghVw==,
}
gzip-size@7.0.0: gzip-size@7.0.0:
resolution: resolution:
{ {
@@ -8869,6 +8878,8 @@ snapshots:
graphemer@1.4.0: {} graphemer@1.4.0: {}
gsap@3.13.0: {}
gzip-size@7.0.0: gzip-size@7.0.0:
dependencies: dependencies:
duplexer: 0.1.2 duplexer: 0.1.2