feat(projects): intro and outro animations

This commit is contained in:
2025-12-17 20:06:46 +01:00
parent fbcc7703c9
commit aabe895325
5 changed files with 77 additions and 13 deletions

View File

@@ -8,10 +8,20 @@ onMounted(async () => {
store.$reset();
await store.loadProjects();
});
watch(
() => store.loading,
() => {
if (!store.loading) {
store.animateIntro();
}
},
);
</script>
<template>
<Background />
<Buttons v-if="!store.loading" />
<template v-if="!store.loading">
<Background />
<Buttons />
</template>
</template>

View File

@@ -90,7 +90,7 @@ useScreenClick((x, y) => {
store.scrollProjects("right");
} else if (circleContains(BUTTONS.quit.position, [x, y], CLICK_RADIUS)) {
startButtonAnimation("quit");
throw new Error("quit");
store.animateOutro();
} else if (
circleContains(BUTTONS.link.position, [x, y], CLICK_RADIUS) &&
project?.link
@@ -102,9 +102,7 @@ useScreenClick((x, y) => {
});
useRender((ctx) => {
if (!currentAnimation) return;
if (currentAnimation.showButton) {
if (currentAnimation?.showButton) {
const image = BUTTONS[currentAnimation.type].image;
ctx.drawImage(
image!,
@@ -113,7 +111,7 @@ useRender((ctx) => {
);
}
if (currentAnimation.showSmallCircle) {
if (currentAnimation?.showSmallCircle) {
ctx.drawImage(
assets.projects.bottomScreen.circleSmall,
currentAnimation.position[0] - 28,
@@ -121,15 +119,17 @@ useRender((ctx) => {
);
}
if (currentAnimation.showBigCircle) {
if (currentAnimation?.showBigCircle) {
ctx.drawImage(
assets.projects.bottomScreen.circleBig,
currentAnimation.position[0] - 44,
currentAnimation.position[1] - 44,
);
}
});
ctx.fillStyle = `rgba(0, 0, 0, ${store.isIntro ? store.intro.fadeOpacity : store.isOutro ? store.outro.fadeOpacity : 0})`;
ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
});
useKeyDown((key) => {
if (currentAnimation) return;
switch (key) {

View File

@@ -124,6 +124,9 @@ useRender((ctx) => {
"black",
"black",
);
ctx.fillStyle = `rgba(0, 0, 0, ${store.isIntro ? store.intro.fadeOpacity : store.isOutro ? store.outro.fadeOpacity : 0})`;
ctx.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
});
defineOptions({

View File

@@ -6,7 +6,8 @@ const store = useProjectsStore();
</script>
<template>
<Background />
<Project v-if="!store.loading" />
<template v-if="!store.loading">
<Background />
<Project />
</template>
</template>

View File

@@ -13,6 +13,17 @@ export const useProjectsStore = defineStore("projects", {
currentProject: 0,
loading: true,
offsetX: 0,
intro: {
fadeOpacity: 1,
},
outro: {
fadeOpacity: 0,
},
isIntro: true,
isOutro: false,
}),
actions: {
@@ -97,5 +108,44 @@ export const useProjectsStore = defineStore("projects", {
},
);
},
animateIntro() {
this.isIntro = true;
gsap.fromTo(
this.intro,
{ fadeOpacity: 1 },
{
delay: 3,
fadeOpacity: 0,
duration: 0.35,
ease: "none",
onComplete: () => {
this.isIntro = false;
},
},
);
},
animateOutro() {
this.isOutro = true;
gsap.fromTo(
this.outro,
{ fadeOpacity: 0 },
{
delay: 0.5,
fadeOpacity: 1,
duration: 0.35,
ease: "none",
onComplete: () => {
setTimeout(() => {
const router = useRouter();
router.push({ query: {} });
}, 3000);
},
},
);
},
},
});