From 74a58b345391b1332e137f9dfd21038fd8577512 Mon Sep 17 00:00:00 2001 From: Pihkaal Date: Fri, 27 Feb 2026 12:17:53 +0100 Subject: [PATCH] feat(2d-nds): intro animation --- app/components/Intro/TopScreen/TopScreen.vue | 1 - app/components/NDS2D.vue | 61 +++++++++++++++++--- app/stores/intro.ts | 7 ++- 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/app/components/Intro/TopScreen/TopScreen.vue b/app/components/Intro/TopScreen/TopScreen.vue index 0eab607..92b914b 100644 --- a/app/components/Intro/TopScreen/TopScreen.vue +++ b/app/components/Intro/TopScreen/TopScreen.vue @@ -5,7 +5,6 @@ const store = useIntroStore(); const frames = Object.keys(assets.images.intro.logoAnimated).sort(); onMounted(() => { - store.$reset(); store.animateIntro(); }); diff --git a/app/components/NDS2D.vue b/app/components/NDS2D.vue index 25d9250..e3568e5 100644 --- a/app/components/NDS2D.vue +++ b/app/components/NDS2D.vue @@ -6,6 +6,38 @@ const app = useAppStore(); const windowSize = useWindowSize(); const hintsContainer = useTemplateRef("hintsContainer"); +const { assets } = useAssets(); + +const introState = reactive({ + scaleMultiplier: 1, + rotateX: 0, + rotateY: 0, + opacity: 1, +}); + +let introPlayed = false; + +onMounted(() => { + if (app.booted || app.settings.renderingMode !== "2d" || introPlayed) return; + introPlayed = true; + + introState.scaleMultiplier = 0.6; + introState.rotateX = 70; + introState.rotateY = 0; + introState.opacity = 0; + + assets.audio.whoosh.play(); + + gsap.to(introState, { + scaleMultiplier: 1, + rotateX: 0, + rotateY: 360, + opacity: 1, + duration: 2.8, + ease: "power2.inOut", + }); +}); + const buttonsDown = reactive(new Set()); let mousePressedButton: string | null = null; @@ -72,10 +104,19 @@ const ndsScale = computed(() => { const gallery = useGalleryStore(); const TOP_SCREEN_OFFSET = 170; -const zoomStyle = computed(() => { - const scale = ndsScale.value * gallery.zoom.scale; +const ndsStyle = computed(() => { + const scale = + ndsScale.value * gallery.zoom.scale * introState.scaleMultiplier; const y = TOP_SCREEN_OFFSET * ndsScale.value * (gallery.zoom.scale - 1); - return { transform: `translateY(${y}px) scale(${scale})` }; + return { + transform: `translateY(${y}px) scale(${scale}) rotateX(${introState.rotateX}deg) rotateY(${introState.rotateY}deg)`, + opacity: introState.opacity, + }; +}); + +const showBackFace = computed(() => { + const r = ((introState.rotateY % 360) + 360) % 360; + return r > 90 && r < 270; }); watch( @@ -102,8 +143,9 @@ watch(