diff --git a/app/components/Achievements/BottomScreen.vue b/app/components/Achievements/BottomScreen.vue
index 00ba1bd..96d00d7 100644
--- a/app/components/Achievements/BottomScreen.vue
+++ b/app/components/Achievements/BottomScreen.vue
@@ -29,21 +29,14 @@ onClick((x, y) => {
});
onRender((ctx) => {
- assets.images.home.bottomScreen.background.draw(ctx, 0, 0);
-
- ctx.globalAlpha = store.isIntro
- ? store.intro.stage1Opacity
- : store.isOutro
- ? store.outro.stage1Opacity
- : 1;
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
// achievement list (reversed iteration because they appear in cascade)
ctx.globalAlpha = store.isIntro
- ? store.intro.stage2Opacity
+ ? store.intro.stage1Opacity
: store.isOutro
- ? store.outro.stage2Opacity
+ ? store.outro.stage1Opacity
: 1;
ctx.font = "7px NDS7";
ctx.textBaseline = "top";
@@ -78,9 +71,9 @@ onRender((ctx) => {
}
ctx.globalAlpha = store.isIntro
- ? store.intro.stage2Opacity
+ ? store.intro.stage1Opacity
: store.isOutro
- ? store.outro.stage3Opacity
+ ? store.outro.stage2Opacity
: 1;
assets.images.achievements.quit.draw(ctx, QUIT_X, QUIT_Y);
});
diff --git a/app/components/Achievements/FadeToBlack.vue b/app/components/Achievements/FadeToBlack.vue
new file mode 100644
index 0000000..9511dbd
--- /dev/null
+++ b/app/components/Achievements/FadeToBlack.vue
@@ -0,0 +1,17 @@
+
diff --git a/app/components/Achievements/TopScreen.vue b/app/components/Achievements/TopScreen.vue
index a61e728..2c59a73 100644
--- a/app/components/Achievements/TopScreen.vue
+++ b/app/components/Achievements/TopScreen.vue
@@ -2,7 +2,6 @@
const { onRender } = useScreen();
const store = useAchievementsScreen();
const achievementsStore = useAchievementsStore();
-const { assets } = useAssets();
const PROGRESS_BAR_WIDTH = 140;
const PROGRESS_BAR_HEIGHT = 10;
@@ -15,21 +14,14 @@ onMounted(() => {
});
onRender((ctx) => {
- assets.images.home.topScreen.background.draw(ctx, 0, 0);
-
- ctx.globalAlpha = store.isIntro
- ? store.intro.stage1Opacity
- : store.isOutro
- ? store.outro.stage1Opacity
- : 1;
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
// header
ctx.globalAlpha = store.isIntro
- ? store.intro.stage2Opacity
+ ? store.intro.stage1Opacity
: store.isOutro
- ? store.outro.stage3Opacity
+ ? store.outro.stage2Opacity
: 1;
ctx.fillStyle = "#ffffff";
ctx.textBaseline = "top";
@@ -87,9 +79,9 @@ onRender((ctx) => {
// achievement list (reversed iteration because they appear in cascade)
ctx.globalAlpha = store.isIntro
- ? store.intro.stage2Opacity
+ ? store.intro.stage1Opacity
: store.isOutro
- ? store.outro.stage2Opacity
+ ? store.outro.stage1Opacity
: 1;
ctx.font = "7px NDS7";
for (let i = ACHIEVEMENTS_TOP_SCREEN_COUNT - 1; i >= 0; i--) {
diff --git a/app/components/Home/BottomScreen/BottomScreen.vue b/app/components/Home/BottomScreen/BottomScreen.vue
index 0d0aa30..3cad681 100644
--- a/app/components/Home/BottomScreen/BottomScreen.vue
+++ b/app/components/Home/BottomScreen/BottomScreen.vue
@@ -5,6 +5,6 @@ import Buttons from "./Buttons.vue";
-
+
diff --git a/app/components/Home/BottomScreen/Buttons.vue b/app/components/Home/BottomScreen/Buttons.vue
index 04a5246..0d60a90 100644
--- a/app/components/Home/BottomScreen/Buttons.vue
+++ b/app/components/Home/BottomScreen/Buttons.vue
@@ -17,7 +17,7 @@ const { selected, selectorPosition } = useButtonNavigation({
settings: [112, 167, 31, 26],
achievements: [225, 167, 31, 26],
},
- initialButton: "projects",
+ initialButton: store.selectedButton,
onButtonClick: (button) => {
if (button === "theme") throw new Error(`Not implemented: ${button}`);
@@ -64,6 +64,10 @@ const { selected, selectorPosition } = useButtonNavigation({
},
});
+watch(selected, (newSelected) => {
+ store.selectedButton = newSelected;
+});
+
const getButtonOffset = (button: (typeof selected)["value"]) => {
if (selected.value === button) return store.outro.buttonOffsetY;
return 0;
diff --git a/app/components/Home/TopScreen/TopScreen.vue b/app/components/Home/TopScreen/TopScreen.vue
index 1e5e180..126c480 100644
--- a/app/components/Home/TopScreen/TopScreen.vue
+++ b/app/components/Home/TopScreen/TopScreen.vue
@@ -7,8 +7,7 @@ import StatusBar from "./StatusBar.vue";
const store = useHomeStore();
onMounted(() => {
- store.$reset();
- store.animateIntro();
+ store.reset();
});
@@ -17,4 +16,5 @@ onMounted(() => {
+
diff --git a/app/components/Settings/BottomScreen/BottomScreen.vue b/app/components/Settings/BottomScreen/BottomScreen.vue
index e8026bd..2df3aab 100644
--- a/app/components/Settings/BottomScreen/BottomScreen.vue
+++ b/app/components/Settings/BottomScreen/BottomScreen.vue
@@ -8,4 +8,5 @@ import Menus from "./Menus/Menus.vue";
+
diff --git a/app/components/Settings/BottomScreen/Menus/Clock/Alarm.vue b/app/components/Settings/BottomScreen/Menus/Clock/Alarm.vue
index 3516b43..d819b97 100644
--- a/app/components/Settings/BottomScreen/Menus/Clock/Alarm.vue
+++ b/app/components/Settings/BottomScreen/Menus/Clock/Alarm.vue
@@ -28,6 +28,7 @@ const { onRender, onClick } = useScreen();
const app = useAppStore();
const store = useSettingsStore();
const achievements = useAchievementsStore();
+const achievementsScreen = useAchievementsScreen();
const confirmationModal = useConfirmationModal();
const handleCancel = () => {
@@ -44,7 +45,7 @@ const handleReset = () => {
};
const handleVisitAll = () => {
- throw new Error("Not implemented");
+ achievementsScreen.animateFadeToBlackIntro();
};
onClick((x, y) => {
diff --git a/app/components/Settings/BottomScreen/Menus/Menus.vue b/app/components/Settings/BottomScreen/Menus/Menus.vue
index 20751f8..f5479e3 100644
--- a/app/components/Settings/BottomScreen/Menus/Menus.vue
+++ b/app/components/Settings/BottomScreen/Menus/Menus.vue
@@ -52,7 +52,7 @@ const { select, selected, selectorPosition } = useButtonNavigation({
touchScreen: [175, 119, 49, 49],
},
- initialButton: "options",
+ initialButton: settingsStore.selectedButton,
onButtonClick: (buttonName) => {
if (isSubMenu(buttonName)) {
settingsStore.openSubMenu(buttonName);
@@ -154,6 +154,8 @@ provide("menusContext", {
watch(
selected,
(newSelected) => {
+ settingsStore.selectedButton = newSelected;
+
if (settingsStore.currentSubMenu === null) {
if (isMainMenu(newSelected)) {
settingsStore.openMenu(newSelected, false);
diff --git a/app/components/Settings/TopScreen/TopScreen.vue b/app/components/Settings/TopScreen/TopScreen.vue
index 85f4874..e9fdc46 100644
--- a/app/components/Settings/TopScreen/TopScreen.vue
+++ b/app/components/Settings/TopScreen/TopScreen.vue
@@ -12,4 +12,5 @@ import Notifications from "./Notifications.vue";
+
diff --git a/app/stores/achievementsScreen.ts b/app/stores/achievementsScreen.ts
index 5cae488..e6974a1 100644
--- a/app/stores/achievementsScreen.ts
+++ b/app/stores/achievementsScreen.ts
@@ -2,9 +2,14 @@ import gsap from "gsap";
export const useAchievementsScreen = defineStore("achievementsScreen", {
state: () => ({
+ fadeToBlack: {
+ opacity: 0,
+ active: false,
+ isOutro: false,
+ },
+
intro: {
stage1Opacity: 0,
- stage2Opacity: 0,
itemOffsets: {} as Record,
progressBar: 0,
},
@@ -12,7 +17,6 @@ export const useAchievementsScreen = defineStore("achievementsScreen", {
outro: {
stage1Opacity: 1,
stage2Opacity: 1,
- stage3Opacity: 1,
},
isIntro: true,
@@ -20,6 +24,51 @@ export const useAchievementsScreen = defineStore("achievementsScreen", {
}),
actions: {
+ animateFadeToBlackIntro() {
+ this.fadeToBlack.active = true;
+ this.fadeToBlack.isOutro = false;
+
+ gsap
+ .timeline({
+ onComplete: () => {
+ const app = useAppStore();
+ app.navigateTo("achievements");
+ },
+ })
+ .fromTo(
+ this.fadeToBlack,
+ { opacity: 0 },
+ {
+ opacity: 1,
+ duration: 0.4,
+ ease: "none",
+ },
+ );
+ },
+
+ animateFadeToBlackOutro() {
+ this.fadeToBlack.active = true;
+ this.fadeToBlack.isOutro = true;
+ this.fadeToBlack.opacity = 1;
+
+ gsap
+ .timeline({
+ onComplete: () => {
+ this.fadeToBlack.active = false;
+ this.isOutro = false;
+ },
+ })
+ .fromTo(
+ this.fadeToBlack,
+ { opacity: 1 },
+ {
+ opacity: 0,
+ duration: 0.4,
+ ease: "none",
+ },
+ );
+ },
+
animateIntro() {
this.isIntro = true;
this.isOutro = false;
@@ -41,30 +90,20 @@ export const useAchievementsScreen = defineStore("achievementsScreen", {
{ stage1Opacity: 0 },
{
stage1Opacity: 1,
- duration: 0.3,
+ duration: 0.5,
ease: "none",
},
- )
- .fromTo(
- this.intro,
- { stage2Opacity: 0 },
- {
- stage2Opacity: 1,
- duration: 0.5,
- ease: "none",
- },
- 0.5,
- )
- .fromTo(
- this.intro,
- { progressBar: 0 },
- {
- progressBar: 1,
- duration: 1.5,
- ease: "power2.out",
- },
- 0.25,
- );
+ 0.5,
+ ).fromTo(
+ this.intro,
+ { progressBar: 0 },
+ {
+ progressBar: 1,
+ duration: 1.5,
+ ease: "power2.out",
+ },
+ 0.25,
+ );
for (let i = 0; i < itemCount; i++) {
tl.to(
@@ -85,6 +124,14 @@ export const useAchievementsScreen = defineStore("achievementsScreen", {
gsap
.timeline()
+ .fromTo(
+ this.outro,
+ { stage1Opacity: 1 },
+ {
+ stage1Opacity: 0,
+ duration: 0.3,
+ },
+ )
.fromTo(
this.outro,
{ stage2Opacity: 1 },
@@ -92,28 +139,12 @@ export const useAchievementsScreen = defineStore("achievementsScreen", {
stage2Opacity: 0,
duration: 0.3,
},
- )
- .fromTo(
- this.outro,
- { stage3Opacity: 1 },
- {
- stage3Opacity: 0,
- duration: 0.3,
- },
"-=0.15",
)
- .fromTo(
- this.outro,
- { stage1Opacity: 1 },
- {
- stage1Opacity: 0,
- duration: 0.3,
- ease: "none",
- },
- )
.call(() => {
const app = useAppStore();
- app.navigateTo("home");
+ app.navigateTo(app.previousScreen);
+ this.animateFadeToBlackOutro();
});
},
diff --git a/app/stores/app.ts b/app/stores/app.ts
index 3521033..cb8a3c7 100644
--- a/app/stores/app.ts
+++ b/app/stores/app.ts
@@ -29,6 +29,7 @@ export const useAppStore = defineStore("app", {
return {
booted: false,
settings,
+ previousScreen: "home" as AppScreen,
screen: "home" as AppScreen,
camera: null as THREE.Camera | null,
};
@@ -40,6 +41,7 @@ export const useAppStore = defineStore("app", {
},
navigateTo(screen: AppScreen) {
+ this.previousScreen = this.screen;
this.screen = screen;
const achievements = useAchievementsStore();
diff --git a/app/stores/home.ts b/app/stores/home.ts
index c487d9c..63b6e87 100644
--- a/app/stores/home.ts
+++ b/app/stores/home.ts
@@ -1,5 +1,13 @@
import gsap from "gsap";
+export type HomeButton =
+ | "projects"
+ | "contact"
+ | "gallery"
+ | "theme"
+ | "settings"
+ | "achievements";
+
export const useHomeStore = defineStore("home", {
state: () => ({
intro: {
@@ -14,11 +22,25 @@ export const useHomeStore = defineStore("home", {
animateTop: false,
},
+ selectedButton: "projects" as HomeButton,
+
isIntro: true,
isOutro: false,
}),
actions: {
+ reset() {
+ const app = useAppStore();
+ if (app.previousScreen === "achievements") {
+ return;
+ }
+
+ const selectedButton = this.selectedButton;
+ this.$reset();
+ this.selectedButton = selectedButton;
+ this.animateIntro();
+ },
+
animateIntro() {
this.isIntro = true;
@@ -52,12 +74,18 @@ export const useHomeStore = defineStore("home", {
},
animateOutro(to: AppScreen) {
+ if (to === "achievements") {
+ const achievementsScreen = useAchievementsScreen();
+ achievementsScreen.animateFadeToBlackIntro();
+ return;
+ }
+
this.isOutro = true;
this.outro.animateTop = to !== "settings";
const timeline = gsap.timeline({
onComplete: () => {
- this.isOutro = true;
+ this.isOutro = false;
const app = useAppStore();
if (to === "gallery") {
diff --git a/app/stores/settings.ts b/app/stores/settings.ts
index d543075..8dbb421 100644
--- a/app/stores/settings.ts
+++ b/app/stores/settings.ts
@@ -1,8 +1,25 @@
+export type SettingsButton =
+ | "options"
+ | "optionsLanguage"
+ | "optionsGbaMode"
+ | "optionsStartUp"
+ | "clock"
+ | "clockAlarm"
+ | "clockTime"
+ | "clockDate"
+ | "user"
+ | "userBirthday"
+ | "userUserName"
+ | "userMessage"
+ | "userColor"
+ | "touchScreen";
+
export const useSettingsStore = defineStore("settings", {
state: () => ({
currentMenu: null as SettingsMenu | null,
currentSubMenu: null as SettingsSubMenu | null,
menuExpanded: false,
+ selectedButton: "options" as SettingsButton,
}),
actions: {