feat(settings/options/startUp): intro and outro animation

This commit is contained in:
2026-02-06 23:18:16 +01:00
parent e81e2733d9
commit 99e9832908
8 changed files with 92 additions and 12 deletions

View File

@@ -1,5 +1,6 @@
<script setup lang="ts">
import { until } from "@vueuse/core";
import gsap from "gsap";
const app = useAppStore();
const store = useSettingsStore();
@@ -9,6 +10,63 @@ const { assets } = useAssets();
const renderingModeAssets =
assets.images.settings.bottomScreen.options.renderingMode;
const HEADER_HEIGHT = renderingModeAssets.buttonHeader.rect.height;
const HEADER_SLIDE_DURATION = 0.2;
const BUTTON_STAGGER = 0.3;
const SLIDE_OFFSET = 96;
const SLIDE_DURATION = 0.25;
const animation = reactive({
_3dMode: { headerOffsetY: HEADER_HEIGHT * 3, opacity: 0 },
_2dMode: { headerOffsetY: HEADER_HEIGHT * 3, opacity: 0 },
outroOffsetY: 0,
outroOpacity: 1,
});
const animateIntro = async () => {
await gsap
.timeline()
.to(
animation._3dMode,
{
opacity: 1,
headerOffsetY: 0,
duration: HEADER_SLIDE_DURATION,
ease: "none",
},
0,
)
.to(
animation._2dMode,
{
opacity: 1,
headerOffsetY: 0,
duration: HEADER_SLIDE_DURATION,
ease: "none",
},
BUTTON_STAGGER,
);
};
const animateOutro = async () => {
await gsap
.timeline()
.to(
animation,
{ outroOffsetY: SLIDE_OFFSET, duration: SLIDE_DURATION, ease: "none" },
0,
)
.to(
animation,
{ outroOpacity: 0, duration: SLIDE_DURATION, ease: "none" },
0,
);
};
onMounted(() => {
animateIntro();
});
const { selected, selectorPosition } = useButtonNavigation({
buttons: {
_3dMode: [11, 27, 233, 74],
@@ -25,7 +83,8 @@ const { selected, selectorPosition } = useButtonNavigation({
},
});
const handleCancel = () => {
const handleCancel = async () => {
await animateOutro();
store.closeSubMenu();
};
@@ -39,7 +98,8 @@ const handleConfirm = () => {
mode === "3d"
? $t("settings.options.startUp.confirmation3d")
: $t("settings.options.startUp.confirmation2d"),
onClosed: () => {
onClosed: async () => {
await animateOutro();
store.closeSubMenu();
},
timeout: 2000,
@@ -62,25 +122,35 @@ onRender((ctx) => {
logo: AtlasImage,
y: number,
active: boolean,
key: "_3dMode" | "_2dMode",
) => {
ctx.save();
ctx.translate(16, y);
ctx.translate(16, y + animation.outroOffsetY);
if (active) {
renderingModeAssets.buttonActive.draw(ctx, 0, 0, { colored: true });
} else {
renderingModeAssets.button.draw(ctx, 0, 0);
}
const buttonWidth = renderingModeAssets.buttonBody.rect.width;
const buttonWidth = renderingModeAssets.button.rect.width;
const bodyImg = active
? renderingModeAssets.buttonActiveBody
: renderingModeAssets.buttonBody;
const headerImg = active
? renderingModeAssets.buttonActiveHeader
: renderingModeAssets.buttonHeader;
const colorOpts = active ? { colored: true } : undefined;
ctx.fillStyle = "#000000";
fillImageTextHCentered(ctx, logo, title, 0, 4, buttonWidth, 4);
ctx.globalAlpha = animation[key].opacity * animation.outroOpacity;
bodyImg.draw(ctx, 0, HEADER_HEIGHT - 2, colorOpts);
ctx.fillStyle = "#282828";
const text = $t("settings.options.startUp.autoStart");
fillTextHCenteredMultiline(ctx, text, 0, y, buttonWidth, 15);
ctx.translate(0, animation[key].headerOffsetY);
headerImg.draw(ctx, 0, 0, colorOpts);
ctx.fillStyle = "#000000";
fillImageTextHCentered(ctx, logo, title, 0, 4, buttonWidth, 4);
ctx.globalAlpha = 1;
ctx.restore();
};
@@ -89,12 +159,14 @@ onRender((ctx) => {
renderingModeAssets._3dMode,
32,
selected.value === "_3dMode",
"_3dMode",
);
drawButton(
$t("settings.options.startUp.2dMode"),
renderingModeAssets._2dMode,
96,
selected.value === "_2dMode",
"_2dMode",
);
});
</script>
@@ -108,5 +180,13 @@ onRender((ctx) => {
@activate-a="handleConfirm"
/>
<CommonButtonSelector :rect="selectorPosition" />
<CommonButtonSelector
:rect="[
selectorPosition[0],
selectorPosition[1] + animation.outroOffsetY,
selectorPosition[2],
selectorPosition[3],
]"
:opacity="animation[selected].opacity * animation.outroOpacity"
/>
</template>