157 lines
3.3 KiB
TypeScript
157 lines
3.3 KiB
TypeScript
import gsap from "gsap";
|
|
|
|
export const CREDITS = ["model3d", "css2d", "nintendo"] as const;
|
|
export type CreditId = (typeof CREDITS)[number];
|
|
|
|
export const useCreditsStore = defineStore("credits", {
|
|
state: () => ({
|
|
fadeToBlack: {
|
|
opacity: 0,
|
|
active: false,
|
|
isOutro: false,
|
|
},
|
|
|
|
intro: {
|
|
stage1Opacity: 0,
|
|
itemOffsets: {} as Record<number, number>,
|
|
},
|
|
|
|
outro: {
|
|
stage1Opacity: 1,
|
|
stage2Opacity: 1,
|
|
},
|
|
|
|
isIntro: true,
|
|
isOutro: false,
|
|
}),
|
|
|
|
actions: {
|
|
animateFadeToBlackIntro() {
|
|
this.fadeToBlack.active = true;
|
|
this.fadeToBlack.isOutro = false;
|
|
|
|
gsap
|
|
.timeline({
|
|
onComplete: () => {
|
|
const app = useAppStore();
|
|
app.navigateTo("credits");
|
|
},
|
|
})
|
|
.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(itemCount: number) {
|
|
this.isIntro = true;
|
|
this.isOutro = false;
|
|
|
|
for (let i = 0; i < itemCount; i++) {
|
|
this.intro.itemOffsets[i] = -CREDITS_LINE_HEIGHT;
|
|
}
|
|
|
|
const tl = gsap.timeline({
|
|
onComplete: () => {
|
|
this.isIntro = false;
|
|
},
|
|
});
|
|
|
|
tl.fromTo(
|
|
this.intro,
|
|
{ stage1Opacity: 0 },
|
|
{
|
|
stage1Opacity: 1,
|
|
duration: 0.5,
|
|
ease: "none",
|
|
},
|
|
0.5,
|
|
);
|
|
|
|
for (let i = 0; i < itemCount; i++) {
|
|
tl.to(
|
|
this.intro.itemOffsets,
|
|
{
|
|
[i]: 0,
|
|
duration: 0.4,
|
|
ease: "power2.out",
|
|
},
|
|
0.75 + i * 0.05,
|
|
);
|
|
}
|
|
},
|
|
|
|
animateOutro() {
|
|
this.isIntro = false;
|
|
this.isOutro = true;
|
|
|
|
gsap
|
|
.timeline()
|
|
.fromTo(
|
|
this.outro,
|
|
{ stage1Opacity: 1 },
|
|
{
|
|
stage1Opacity: 0,
|
|
duration: 0.3,
|
|
},
|
|
)
|
|
.fromTo(
|
|
this.outro,
|
|
{ stage2Opacity: 1 },
|
|
{
|
|
stage2Opacity: 0,
|
|
duration: 0.3,
|
|
},
|
|
"-=0.15",
|
|
)
|
|
.call(() => {
|
|
const app = useAppStore();
|
|
app.navigateTo(app.previousScreen);
|
|
this.animateFadeToBlackOutro();
|
|
});
|
|
},
|
|
|
|
getItemOffset(index: number): number {
|
|
return this.intro.itemOffsets[index] ?? 0;
|
|
},
|
|
},
|
|
});
|
|
|
|
export const CREDITS_LINE_HEIGHT = 14;
|
|
export const CREDITS_ENTRY_GAP = 12;
|
|
export const CREDITS_HEADER_Y = 30;
|
|
export const CREDITS_LIST_START_Y = CREDITS_HEADER_Y + 35;
|
|
export const CREDITS_ENTRY_HEIGHT = CREDITS_LINE_HEIGHT * 3 + CREDITS_ENTRY_GAP;
|
|
export const CREDITS_TOP_SCREEN_COUNT = Math.floor(
|
|
(LOGICAL_HEIGHT - CREDITS_LIST_START_Y) / CREDITS_ENTRY_HEIGHT,
|
|
);
|
|
export const CREDITS_BOTTOM_START_Y = 30;
|