feat(assets): new assets loading system (currently only for images)

This commit is contained in:
2025-12-17 12:28:48 +01:00
parent 05398d5252
commit b85899617b
106 changed files with 359 additions and 366 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 306 B

View File

@@ -1,6 +1,4 @@
<script setup lang="ts">
import CORNER_IMAGE from "/assets/images/home/bottom-screen/buttons/corner.webp";
const props = withDefaults(
defineProps<{
rect: [x: number, y: number, width: number, height: number];
@@ -11,7 +9,7 @@ const props = withDefaults(
},
);
const [cornerImage] = useImages(CORNER_IMAGE);
const { assets } = useAssets();
const ANIMATION_SPEED = 0.25;
@@ -45,21 +43,21 @@ useRender((ctx) => {
ctx.globalAlpha = props.opacity;
ctx.drawImage(cornerImage!, x, y);
ctx.drawImage(assets.home.bottomScreen.buttons.corner, x, y);
ctx.save();
ctx.scale(-1, 1);
ctx.drawImage(cornerImage!, -(x + w), y);
ctx.drawImage(assets.home.bottomScreen.buttons.corner, -(x + w), y);
ctx.restore();
ctx.save();
ctx.scale(1, -1);
ctx.drawImage(cornerImage!, x, -(y + h));
ctx.drawImage(assets.home.bottomScreen.buttons.corner, x, -(y + h));
ctx.restore();
ctx.save();
ctx.scale(-1, -1);
ctx.drawImage(cornerImage!, -(x + w), -(y + h));
ctx.drawImage(assets.home.bottomScreen.buttons.corner, -(x + w), -(y + h));
ctx.restore();
});

View File

@@ -1,21 +1,15 @@
<script setup lang="ts">
import HOME_BACKGROUND_IMAGE from "/assets/images/home/bottom-screen/background.webp";
import CONTACT_BACKGROUND_IMAGE from "/assets/images/contact/bottom-screen/background.webp";
const store = useContactStore();
const [homeBackgroundImage, contactBackgroundImage] = useImages(
HOME_BACKGROUND_IMAGE,
CONTACT_BACKGROUND_IMAGE,
);
const { assets } = useAssets();
useRender((ctx) => {
ctx.drawImage(homeBackgroundImage!, 0, 0);
ctx.drawImage(assets.home.bottomScreen.background, 0, 0);
ctx.globalAlpha = store.isIntro
? store.intro.stage2Opacity
: store.outro.stage3Opacity;
ctx.drawImage(contactBackgroundImage!, 0, 0);
ctx.drawImage(assets.contact.bottomScreen.background, 0, 0);
});
defineOptions({

View File

@@ -1,19 +1,11 @@
<script setup lang="ts">
import TOP_BAR_IMAGE from "/assets/images/contact/bottom-screen/top-bar.webp";
import BOTTOM_BAR_IMAGE from "/assets/images/contact/bottom-screen/bottom-bar.webp";
import BOTTOM_BAR_OK_IMAGE from "/assets/images/contact/bottom-screen/ok-button.webp";
const props = defineProps<{
okLabel: "Copy" | "Open";
}>();
const store = useContactStore();
const [topBarImage, bottomBarImage, bottomBarOkImage] = useImages(
TOP_BAR_IMAGE,
BOTTOM_BAR_IMAGE,
BOTTOM_BAR_OK_IMAGE,
);
const { assets } = useAssets();
useRender((ctx) => {
ctx.globalAlpha = store.isIntro
@@ -21,13 +13,17 @@ useRender((ctx) => {
: store.outro.stage2Opacity;
// top bar
ctx.drawImage(topBarImage!, 0, store.isIntro ? store.intro.topBarY : 0);
ctx.drawImage(
assets.contact.bottomScreen.topBar,
0,
store.isIntro ? store.intro.topBarY : 0,
);
// bottom bar
ctx.translate(0, store.isIntro ? store.intro.bottomBarY : SCREEN_HEIGHT - 24);
ctx.drawImage(bottomBarImage!, 0, 0);
ctx.drawImage(assets.contact.bottomScreen.bottomBar, 0, 0);
ctx.drawImage(bottomBarOkImage!, 144, 4);
ctx.drawImage(assets.contact.bottomScreen.okButton, 144, 4);
ctx.font = "10px NDS10";
ctx.fillStyle = "#000000";
ctx.fillText(props.okLabel, 144 + 35, 4 + 13);

View File

@@ -1,15 +1,13 @@
<script setup lang="ts">
import BUTTONS_IMAGE from "/assets/images/contact/bottom-screen/buttons.webp";
const store = useContactStore();
const [buttonsImage] = useImages(BUTTONS_IMAGE);
const { assets } = useAssets();
useRender((ctx) => {
ctx.globalAlpha = store.isIntro
? store.intro.stage3Opacity
: store.outro.stage1Opacity;
ctx.drawImage(buttonsImage!, 31, 32);
ctx.drawImage(assets.contact.bottomScreen.buttons, 31, 32);
});
defineOptions({

View File

@@ -1,21 +1,15 @@
<script setup lang="ts">
import HOME_BACKGROUND_IMAGE from "/assets/images/home/top-screen/background.webp";
import CONTACT_BACKGROUND_IMAGE from "/assets/images/contact/top-screen/background.webp";
const store = useContactStore();
const [homeBackgroundImage, contactBackgroundImage] = useImages(
HOME_BACKGROUND_IMAGE,
CONTACT_BACKGROUND_IMAGE,
);
const { assets } = useAssets();
useRender((ctx) => {
ctx.drawImage(homeBackgroundImage!, 0, 0);
ctx.drawImage(assets.home.topScreen.background, 0, 0);
ctx.globalAlpha = store.isIntro
? store.intro.stage2Opacity
: store.outro.stage3Opacity;
ctx.drawImage(contactBackgroundImage!, 0, 0);
ctx.drawImage(assets.contact.topScreen.background, 0, 0);
});
defineOptions({

View File

@@ -1,24 +1,18 @@
<script setup lang="ts">
import BACKGROUND_IMAGE from "/assets/images/contact/top-screen/left-bar.webp";
import THINGS_IMAGE from "/assets/images/contact/top-screen/left-bar-things.webp";
const store = useContactStore();
const [backgroundImage, thingsImage] = useImages(
BACKGROUND_IMAGE,
THINGS_IMAGE,
);
const { assets } = useAssets();
useRender((ctx) => {
ctx.globalAlpha = store.isIntro
? store.intro.stage1Opacity
: store.outro.stage2Opacity;
ctx.drawImage(backgroundImage!, 0, 0);
ctx.drawImage(assets.contact.topScreen.leftBar, 0, 0);
ctx.globalAlpha = store.isIntro
? store.intro.stage3Opacity
: store.outro.stage1Opacity;
ctx.drawImage(thingsImage!, 0, 0);
ctx.drawImage(assets.contact.topScreen.leftBarThings, 0, 0);
});
defineOptions({

View File

@@ -1,14 +1,8 @@
<script setup lang="ts">
import NOTIFICATION_IMAGE from "/assets/images/contact/bottom-screen/notification.webp";
import TITLE_IMAGE from "/assets/images/contact/top-screen/title.webp";
// text color:
const store = useContactStore();
const [notificationImage, titleImage] = useImages(
NOTIFICATION_IMAGE,
TITLE_IMAGE,
);
const { assets } = useAssets();
useRender((ctx) => {
ctx.globalAlpha = store.outro.stage2Opacity;
@@ -20,7 +14,7 @@ useRender((ctx) => {
const y = 169 - 24 * index + store.notificationsYOffset;
if (y < -24) break;
ctx.drawImage(notificationImage!, 21, y);
ctx.drawImage(assets.contact.bottomScreen.notification, 21, y);
const content = store.notifications[i]!;
ctx.fillStyle = content.includes("opened") ? "#00fbba" : "#e3f300";
@@ -32,7 +26,7 @@ useRender((ctx) => {
? store.intro.stage1Opacity
: store.outro.stage2Opacity;
ctx.drawImage(
titleImage!,
assets.contact.topScreen.title,
21,
store.isIntro
? store.intro.titleY

View File

@@ -1,14 +1,12 @@
<script setup lang="ts">
import BACKGROUND_IMAGE from "/assets/images/home/bottom-screen/background.webp";
const store = useHomeStore();
const app = useAppStore();
const [backgroundImage] = useImages(BACKGROUND_IMAGE);
const { assets } = useAssets();
useRender((ctx) => {
ctx.globalAlpha = app.booted ? 1 : store.intro.stage1Opacity;
ctx.drawImage(backgroundImage!, 0, 0);
ctx.drawImage(assets.home.bottomScreen.background, 0, 0);
});
defineOptions({

View File

@@ -1,17 +1,15 @@
<script setup lang="ts">
import BUTTON_IMAGE from "/assets/images/home/bottom-screen/buttons/contact.webp";
const props = defineProps<{
x: number;
y: number;
opacity: number;
}>();
const [buttonImage] = useImages(BUTTON_IMAGE);
const { assets } = useAssets();
useRender((ctx) => {
ctx.globalAlpha = props.opacity;
ctx.drawImage(buttonImage!, props.x, props.y);
ctx.drawImage(assets.home.bottomScreen.buttons.contact, props.x, props.y);
});
defineOptions({

View File

@@ -1,17 +1,19 @@
<script setup lang="ts">
import BUTTON_IMAGE from "/assets/images/home/bottom-screen/buttons/downloadPlay.webp";
const props = defineProps<{
x: number;
y: number;
opacity: number;
}>();
const [buttonImage] = useImages(BUTTON_IMAGE);
const { assets } = useAssets();
useRender((ctx) => {
ctx.globalAlpha = props.opacity;
ctx.drawImage(buttonImage!, props.x, props.y);
ctx.drawImage(
assets.home.bottomScreen.buttons.downloadPlay,
props.x,
props.y,
);
});
defineOptions({

View File

@@ -1,17 +1,15 @@
<script setup lang="ts">
import BUTTON_IMAGE from "/assets/images/home/bottom-screen/buttons/game.webp";
const props = defineProps<{
x: number;
y: number;
opacity: number;
}>();
const [buttonImage] = useImages(BUTTON_IMAGE);
const { assets } = useAssets();
useRender((ctx) => {
ctx.globalAlpha = props.opacity;
ctx.drawImage(buttonImage!, props.x, props.y);
ctx.drawImage(assets.home.bottomScreen.buttons.game, props.x, props.y);
});
defineOptions({

View File

@@ -1,17 +1,15 @@
<script setup lang="ts">
import BUTTON_IMAGE from "/assets/images/home/bottom-screen/buttons/settings.webp";
const props = defineProps<{
x: number;
y: number;
opacity: number;
}>();
const [buttonImage] = useImages(BUTTON_IMAGE);
const { assets } = useAssets();
useRender((ctx) => {
ctx.globalAlpha = props.opacity;
ctx.drawImage(buttonImage!, props.x, props.y);
ctx.drawImage(assets.home.bottomScreen.buttons.settings, props.x, props.y);
});
defineOptions({

View File

@@ -1,14 +1,12 @@
<script setup lang="ts">
import BACKGROUND_IMAGE from "/assets/images/home/top-screen/background.webp";
const store = useHomeStore();
const app = useAppStore();
const [backgroundImage] = useImages(BACKGROUND_IMAGE);
const { assets } = useAssets();
useRender((ctx) => {
ctx.globalAlpha = app.booted ? 1 : store.intro.stage1Opacity;
ctx.drawImage(backgroundImage!, 0, 0);
ctx.drawImage(assets.home.topScreen.background, 0, 0);
});
defineOptions({

View File

@@ -1,16 +1,8 @@
<script setup lang="ts">
import CALENDAR_IMAGE from "/assets/images/home/top-screen/calendar/calendar.webp";
import LAST_ROW_IMAGE from "/assets/images/home/top-screen/calendar/last-row.webp";
import DAY_SELECTOR_IMAGE from "/assets/images/home/top-screen/calendar/day-selector.webp";
// NOTE: calendar background is handled by TopScreenBackground
const store = useHomeStore();
const [calendarImage, lastRowImage, daySelectorImage] = useImages(
CALENDAR_IMAGE,
LAST_ROW_IMAGE,
DAY_SELECTOR_IMAGE,
);
const { assets } = useAssets();
useRender((ctx) => {
ctx.fillStyle = "black";
@@ -35,11 +27,19 @@ useRender((ctx) => {
: store.isOutro && store.outro.animateTop
? store.outro.stage1Opacity
: 1;
ctx.drawImage(calendarImage!, CALENDAR_LEFT - 3, CALENDAR_TOP - 33);
ctx.drawImage(
assets.home.topScreen.calendar.calendar,
CALENDAR_LEFT - 3,
CALENDAR_TOP - 33,
);
const extraRow = CALENDAR_COLS * CALENDAR_ROWS - daysInMonth - firstDay < 0;
if (extraRow) {
ctx.drawImage(lastRowImage!, CALENDAR_LEFT - 3, CALENDAR_TOP + 79);
ctx.drawImage(
assets.home.topScreen.calendar.lastRow,
CALENDAR_LEFT - 3,
CALENDAR_TOP + 79,
);
}
ctx.globalAlpha = store.isIntro
@@ -60,7 +60,11 @@ useRender((ctx) => {
const cellTop = CALENDAR_TOP + col * 16;
if (now.getDate() === day) {
ctx.drawImage(daySelectorImage!, cellLeft, cellTop);
ctx.drawImage(
assets.home.topScreen.calendar.daySelector,
cellLeft,
cellTop,
);
}
ctx.fillText(

View File

@@ -1,12 +1,10 @@
<script setup lang="ts">
import CLOCK_IMAGE from "/assets/images/home/top-screen/clock.webp";
const CENTER_X = 63;
const CENTER_Y = 95;
const store = useHomeStore();
const [clockImage] = useImages(CLOCK_IMAGE);
const { assets } = useAssets();
function drawLine(
ctx: CanvasRenderingContext2D,
@@ -59,7 +57,7 @@ useRender((ctx) => {
: store.isOutro && store.outro.animateTop
? store.outro.stage1Opacity
: 1;
ctx.drawImage(clockImage!, 13, 45);
ctx.drawImage(assets.home.topScreen.clock, 13, 45);
ctx.globalAlpha = store.isIntro
? store.intro.stage1Opacity

View File

@@ -1,18 +1,7 @@
<script setup lang="ts">
import STATUS_BAR_IMAGE from "/assets/images/home/top-screen/status-bar/status-bar.webp";
import GBA_DISPLAY_IMAGE from "/assets/images/home/top-screen/status-bar/gba-display.webp";
import STARTUP_MODE_IMAGE from "/assets/images/home/top-screen/status-bar/startup-mode.webp";
import BATTERY_IMAGE from "/assets/images/home/top-screen/status-bar/battery.webp";
const store = useHomeStore();
const [statusBarImage, gbaDisplayImage, startupModeImage, batteryImage] =
useImages(
STATUS_BAR_IMAGE,
GBA_DISPLAY_IMAGE,
STARTUP_MODE_IMAGE,
BATTERY_IMAGE,
);
const { assets } = useAssets();
useRender((ctx) => {
const TEXT_Y = 11;
@@ -21,7 +10,7 @@ useRender((ctx) => {
ctx.globalAlpha =
store.isOutro && store.outro.animateTop ? store.outro.stage2Opacity : 1;
ctx.drawImage(statusBarImage!, 0, 0);
ctx.drawImage(assets.home.topScreen.statusBar.statusBar, 0, 0);
ctx.fillStyle = "#ffffff";
ctx.font = "7px NDS7";
@@ -51,9 +40,9 @@ useRender((ctx) => {
fillNumberCell(now.getMonth() + 1, 12, -1);
// icons
ctx.drawImage(gbaDisplayImage!, 210, 2);
ctx.drawImage(startupModeImage!, 226, 2);
ctx.drawImage(batteryImage!, 242, 4);
ctx.drawImage(assets.home.topScreen.statusBar.gbaDisplay, 210, 2);
ctx.drawImage(assets.home.topScreen.statusBar.startupMode, 226, 2);
ctx.drawImage(assets.home.topScreen.statusBar.battery, 242, 4);
});
defineOptions({

View File

@@ -1,10 +1,8 @@
<script setup lang="ts">
import BACKGROUND_IMAGE from "~/assets/images/projects/bottom-screen/background.webp";
const [backgroundImage] = useImages(BACKGROUND_IMAGE);
const { assets } = useAssets();
useRender((ctx) => {
ctx.drawImage(backgroundImage!, 0, 0);
ctx.drawImage(assets.projects.bottomScreen.background, 0, 0);
});
defineOptions({
render: () => null,

View File

@@ -1,37 +1,29 @@
<script setup lang="ts">
import PREV_PRESSED_IMAGE from "~/assets/images/projects/bottom-screen/prev-pressed.webp";
import QUIT_PRESSED_IMAGE from "~/assets/images/projects/bottom-screen/quit-pressed.webp";
import LINK_PRESSED_IMAGE from "~/assets/images/projects/bottom-screen/link-pressed.webp";
import NEXT_PRESSED_IMAGE from "~/assets/images/projects/bottom-screen/next-pressed.webp";
import CIRCLE_SMALL_IMAGE from "~/assets/images/projects/bottom-screen/circle_small.webp";
import CIRCLE_BIG_IMAGE from "~/assets/images/projects/bottom-screen/circle_big.webp";
import gsap from "gsap";
const store = useProjectsStore();
const [
prevPressedImage,
quitPressedImage,
linkPressedImage,
nextPressedImage,
circleSmallImagee,
circleBigImage,
] = useImages(
PREV_PRESSED_IMAGE,
QUIT_PRESSED_IMAGE,
LINK_PRESSED_IMAGE,
NEXT_PRESSED_IMAGE,
CIRCLE_SMALL_IMAGE,
CIRCLE_BIG_IMAGE,
);
const { assets } = useAssets();
const CLICK_RADIUS = 22;
const BUTTONS = {
prev: { position: [36, 100], image: prevPressedImage! },
quit: { position: [88, 156], image: quitPressedImage! },
link: { position: [168, 156], image: linkPressedImage! },
next: { position: [220, 100], image: nextPressedImage! },
prev: {
position: [36, 100],
image: assets.projects.bottomScreen.prevPressed,
},
quit: {
position: [88, 156],
image: assets.projects.bottomScreen.quitPressed,
},
link: {
position: [168, 156],
image: assets.projects.bottomScreen.linkPressed,
},
next: {
position: [220, 100],
image: assets.projects.bottomScreen.nextPressed,
},
} as const satisfies Record<
string,
{ position: Point; image: HTMLImageElement }
@@ -123,7 +115,7 @@ useRender((ctx) => {
if (currentAnimation.showSmallCircle) {
ctx.drawImage(
circleSmallImagee!,
assets.projects.bottomScreen.circleSmall,
currentAnimation.position[0] - 28,
currentAnimation.position[1] - 28,
);
@@ -131,7 +123,7 @@ useRender((ctx) => {
if (currentAnimation.showBigCircle) {
ctx.drawImage(
circleBigImage!,
assets.projects.bottomScreen.circleBig,
currentAnimation.position[0] - 44,
currentAnimation.position[1] - 44,
);

View File

@@ -1,10 +1,8 @@
<script setup lang="ts">
import BACKGROUND_IMAGE from "/assets/images/projects/top-screen/background.webp";
const [backgroundImage] = useImages(BACKGROUND_IMAGE);
const { assets } = useAssets();
useRender((ctx) => {
ctx.drawImage(backgroundImage!, 0, 0);
ctx.drawImage(assets.projects.topScreen.background, 0, 0);
});
defineOptions({

View File

@@ -1,12 +1,7 @@
<script setup lang="ts">
import BACKGROUND_IMAGE from "~/assets/images/projects/top-screen/background.webp";
const store = useProjectsStore();
const [backgroundImage, ...projectImages] = useImages(
BACKGROUND_IMAGE,
...store.projects.map((project) => `/images/projects/${project.id}.webp`),
);
const { assets } = useAssets();
const drawTextWithShadow = (
ctx: CanvasRenderingContext2D,
@@ -60,7 +55,7 @@ const drawTextWithShadow2Lines = (
};
useRender((ctx) => {
ctx.drawImage(backgroundImage!, 0, 0);
ctx.drawImage(assets.projects.topScreen.background, 0, 0);
ctx.textBaseline = "hanging";
ctx.font = "16px Pokemon DP Pro";
@@ -69,7 +64,10 @@ useRender((ctx) => {
if (!project) return;
// image
const projectImage = projectImages[store.currentProject]!;
const projectImage =
assets.projects.pokemons[
project.id as keyof typeof assets.projects.pokemons
];
ctx.drawImage(
projectImage,
Math.floor(52 - projectImage.width / 2),

View File

@@ -1,18 +1,10 @@
<script setup lang="ts">
import BACKGROUND_IMAGE from "/assets/images/home/bottom-screen/background.webp";
import TOP_BAR_IMAGE from "/assets/images/settings/bottom-screen/top-bar.webp";
import BOTTOM_BAR_IMAGE from "/assets/images/settings/bottom-screen/bottom-bar.webp";
const [backgroundImage, topBarImage, bottomBarImage] = useImages(
BACKGROUND_IMAGE,
TOP_BAR_IMAGE,
BOTTOM_BAR_IMAGE,
);
const { assets } = useAssets();
useRender((ctx) => {
ctx.drawImage(backgroundImage!, 0, 0);
ctx.drawImage(topBarImage!, 0, 0);
ctx.drawImage(bottomBarImage!, 0, 168);
ctx.drawImage(assets.home.bottomScreen.background, 0, 0);
ctx.drawImage(assets.settings.bottomScreen.topBar, 0, 0);
ctx.drawImage(assets.settings.bottomScreen.bottomBar, 0, 168);
});
defineOptions({

View File

@@ -1,11 +1,4 @@
<script setup lang="ts">
import MENU_IMAGE from "/assets/images/settings/top-screen/clock/clock.webp";
import MENU_ACTIVE_IMAGE from "/assets/images/settings/top-screen/clock/clock-active.webp";
import MENU_DISABLED_IMAGE from "/assets/images/settings/top-screen/clock/clock-disabled.png";
import ALARM_IMAGE from "/assets/images/settings/top-screen/clock/alarm.webp";
import TIME_IMAGE from "/assets/images/settings/top-screen/clock/time.webp";
import DATE_IMAGE from "/assets/images/settings/top-screen/clock/date.webp";
const props = defineProps<{
x: number;
y: number;
@@ -13,21 +6,7 @@ const props = defineProps<{
const settingsStore = useSettingsStore();
const [
menuImage,
menuActiveImage,
menuDisabledImage,
alarmImage,
timeImage,
dateImage,
] = useImages(
MENU_IMAGE,
MENU_ACTIVE_IMAGE,
MENU_DISABLED_IMAGE,
ALARM_IMAGE,
TIME_IMAGE,
DATE_IMAGE,
);
const { assets } = useAssets();
const isOpen = computed(() => settingsStore.isMenuOpen("clock"));
const isAnyOtherMenuOpen = computed(() =>
@@ -41,22 +20,26 @@ useRender((ctx) => {
if (isOpen.value || animation.playing) {
ctx.drawImage(
timeImage!,
assets.settings.topScreen.clock.time,
48 - animation.stage2Offset,
-48 + animation.stage1Offset,
);
ctx.drawImage(
dateImage!,
assets.settings.topScreen.clock.date,
0,
-96 + animation.stage2Offset + animation.stage1Offset,
);
ctx.drawImage(alarmImage!, 0, -48 + animation.stage1Offset);
ctx.drawImage(
assets.settings.topScreen.clock.alarm,
0,
-48 + animation.stage1Offset,
);
ctx.drawImage(menuActiveImage!, 0, 0);
ctx.drawImage(assets.settings.topScreen.clock.clockActive, 0, 0);
} else if (isAnyOtherMenuOpen.value) {
ctx.drawImage(menuDisabledImage!, 0, 0);
ctx.drawImage(assets.settings.topScreen.clock.clockDisabled, 0, 0);
} else {
ctx.drawImage(menuImage!, 0, 0);
ctx.drawImage(assets.settings.topScreen.clock.clock, 0, 0);
}
});

View File

@@ -1,11 +1,4 @@
<script setup lang="ts">
import MENU_IMAGE from "/assets/images/settings/top-screen/options/options.webp";
import MENU_ACTIVE_IMAGE from "/assets/images/settings/top-screen/options/options-active.png";
import MENU_DISABLED_IMAGE from "/assets/images/settings/top-screen/options/options-disabled.png";
import GBA_MODE_IMAGE from "/assets/images/settings/top-screen/options/gba-mode.webp";
import LANGUAGE_IMAGE from "/assets/images/settings/top-screen/options/language.webp";
import START_UP_IMAGE from "/assets/images/settings/top-screen/options/start-up.webp";
const props = defineProps<{
x: number;
y: number;
@@ -13,21 +6,7 @@ const props = defineProps<{
const settingsStore = useSettingsStore();
const [
menuImage,
menuActiveImage,
menuDisabledImage,
gbaModeImage,
languageImage,
startUpImage,
] = useImages(
MENU_IMAGE,
MENU_ACTIVE_IMAGE,
MENU_DISABLED_IMAGE,
GBA_MODE_IMAGE,
LANGUAGE_IMAGE,
START_UP_IMAGE,
);
const { assets } = useAssets();
const isOpen = computed(() => settingsStore.isMenuOpen("options"));
const isAnyOtherMenuOpen = computed(() =>
@@ -40,23 +19,27 @@ useRender((ctx) => {
ctx.translate(props.x, props.y);
if (isOpen.value || animation.playing) {
ctx.drawImage(languageImage!, 0, -48 + animation.stage1Offset);
ctx.drawImage(
gbaModeImage!,
assets.settings.topScreen.options.language,
0,
-48 + animation.stage1Offset,
);
ctx.drawImage(
assets.settings.topScreen.options.gbaMode,
48 - animation.stage2Offset,
-48 + animation.stage1Offset,
);
ctx.drawImage(
startUpImage!,
assets.settings.topScreen.options.startUp,
0,
-96 + animation.stage2Offset + animation.stage1Offset,
);
ctx.drawImage(menuActiveImage!, 0, 0);
ctx.drawImage(assets.settings.topScreen.options.optionsActive, 0, 0);
} else if (isAnyOtherMenuOpen.value) {
ctx.drawImage(menuDisabledImage!, 0, 0);
ctx.drawImage(assets.settings.topScreen.options.optionsDisabled, 0, 0);
} else {
ctx.drawImage(menuImage!, 0, 0);
ctx.drawImage(assets.settings.topScreen.options.options, 0, 0);
}
});

View File

@@ -1,7 +1,4 @@
<script setup lang="ts">
import MENU_IMAGE from "/assets/images/settings/top-screen/touch_screen/touch-screen.webp";
import MENU_DISABLED_IMAGE from "/assets/images/settings/top-screen/touch_screen/touch-screen-disabled.png";
const props = defineProps<{
x: number;
y: number;
@@ -9,10 +6,7 @@ const props = defineProps<{
const settingsStore = useSettingsStore();
const [menuImage, menuDisabledImage] = useImages(
MENU_IMAGE,
MENU_DISABLED_IMAGE,
);
const { assets } = useAssets();
const isAnyOtherMenuOpen = computed(() =>
settingsStore.isAnyOtherMenuOpen("touchScreen"),
@@ -20,9 +14,17 @@ const isAnyOtherMenuOpen = computed(() =>
useRender((ctx) => {
if (isAnyOtherMenuOpen.value) {
ctx.drawImage(menuDisabledImage!, props.x, props.y);
ctx.drawImage(
assets.settings.topScreen.touchScreen.touchScreenDisabled,
props.x,
props.y,
);
} else {
ctx.drawImage(menuImage!, props.x, props.y);
ctx.drawImage(
assets.settings.topScreen.touchScreen.touchScreen,
props.x,
props.y,
);
}
});

View File

@@ -1,12 +1,4 @@
<script setup lang="ts">
import MENU_IMAGE from "/assets/images/settings/top-screen/user/user.webp";
import MENU_ACTIVE_IMAGE from "/assets/images/settings/top-screen/user/user-active.webp";
import MENU_DISABLED_IMAGE from "/assets/images/settings/top-screen/user/user-disabled.png";
import BIRTHDAY_IMAGE from "/assets/images/settings/top-screen/user/birthday.webp";
import COLOR_IMAGE from "/assets/images/settings/top-screen/user/color.webp";
import MESSAGE_IMAGE from "/assets/images/settings/top-screen/user/message.webp";
import USER_NAME_IMAGE from "/assets/images/settings/top-screen/user/user-name.webp";
const props = defineProps<{
x: number;
y: number;
@@ -14,23 +6,7 @@ const props = defineProps<{
const settingsStore = useSettingsStore();
const [
menuImage,
menuActiveImage,
menuDisabledImage,
birthdayImage,
colorImage,
messageImage,
userNameImage,
] = useImages(
MENU_IMAGE,
MENU_ACTIVE_IMAGE,
MENU_DISABLED_IMAGE,
BIRTHDAY_IMAGE,
COLOR_IMAGE,
MESSAGE_IMAGE,
USER_NAME_IMAGE,
);
const { assets } = useAssets();
const isOpen = computed(() => settingsStore.isMenuOpen("user"));
const isAnyOtherMenuOpen = computed(() =>
@@ -44,27 +20,31 @@ useRender((ctx) => {
if (isOpen.value || animation.playing) {
ctx.drawImage(
birthdayImage!,
assets.settings.topScreen.user.birthday,
-48 + animation.stage2Offset,
-48 + animation.stage1Offset,
);
ctx.drawImage(userNameImage!, 0, -48 + animation.stage1Offset);
ctx.drawImage(
messageImage!,
assets.settings.topScreen.user.userName,
0,
-48 + animation.stage1Offset,
);
ctx.drawImage(
assets.settings.topScreen.user.message,
48 - animation.stage2Offset,
-48 + animation.stage1Offset,
);
ctx.drawImage(
colorImage!,
assets.settings.topScreen.user.color,
0,
-96 + animation.stage2Offset + animation.stage1Offset,
);
ctx.drawImage(menuActiveImage!, 0, 0);
ctx.drawImage(assets.settings.topScreen.user.userActive, 0, 0);
} else if (isAnyOtherMenuOpen.value) {
ctx.drawImage(menuDisabledImage!, 0, 0);
ctx.drawImage(assets.settings.topScreen.user.userDisabled, 0, 0);
} else {
ctx.drawImage(menuImage!, 0, 0);
ctx.drawImage(assets.settings.topScreen.user.user, 0, 0);
}
});

View File

@@ -1,10 +1,8 @@
<script setup lang="ts">
import BACKGROUND_IMAGE from "/assets/images/home/top-screen/background.webp";
const [backgroundImage] = useImages(BACKGROUND_IMAGE);
const { assets } = useAssets();
useRender((ctx) => {
ctx.drawImage(backgroundImage!, 0, 0);
ctx.drawImage(assets.home.topScreen.background, 0, 0);
});
defineOptions({

View File

@@ -1,13 +1,5 @@
<script setup lang="ts">
import CALENDAR_IMAGE from "/assets/images/home/top-screen/calendar/calendar.webp";
import LAST_ROW_IMAGE from "/assets/images/home/top-screen/calendar/last-row.webp";
import DAY_SELECTOR_IMAGE from "/assets/images/home/top-screen/calendar/day-selector.webp";
const [calendarImage, lastRowImage, daySelectorImage] = useImages(
CALENDAR_IMAGE,
LAST_ROW_IMAGE,
DAY_SELECTOR_IMAGE,
);
const { assets } = useAssets();
useRender((ctx) => {
ctx.fillStyle = "black";
@@ -29,11 +21,19 @@ useRender((ctx) => {
const firstDay = new Date(year, month, 1).getDay();
const daysInMonth = new Date(year, month + 1, 0).getDate();
ctx.drawImage(calendarImage!, CALENDAR_LEFT - 3, CALENDAR_TOP - 33);
ctx.drawImage(
assets.home.topScreen.calendar.calendar,
CALENDAR_LEFT - 3,
CALENDAR_TOP - 33,
);
const extraRow = CALENDAR_COLS * CALENDAR_ROWS - daysInMonth - firstDay < 0;
if (extraRow) {
ctx.drawImage(lastRowImage!, CALENDAR_LEFT - 3, CALENDAR_TOP + 79);
ctx.drawImage(
assets.home.topScreen.calendar.lastRow,
CALENDAR_LEFT - 3,
CALENDAR_TOP + 79,
);
}
for (let col = 0; col < CALENDAR_ROWS + (extraRow ? 1 : 0); col += 1) {
@@ -49,7 +49,11 @@ useRender((ctx) => {
const cellTop = CALENDAR_TOP + col * 16;
if (now.getDate() === day) {
ctx.drawImage(daySelectorImage!, cellLeft, cellTop);
ctx.drawImage(
assets.home.topScreen.calendar.daySelector,
cellLeft,
cellTop,
);
}
ctx.fillText(

View File

@@ -1,10 +1,8 @@
<script setup lang="ts">
import CLOCK_IMAGE from "/assets/images/home/top-screen/clock.webp";
const CENTER_X = 63;
const CENTER_Y = 95;
const [clockImage] = useImages(CLOCK_IMAGE);
const { assets } = useAssets();
function drawLine(
ctx: CanvasRenderingContext2D,
@@ -54,7 +52,7 @@ function drawLine(
useRender((ctx) => {
ctx.translate(0, -16);
ctx.drawImage(clockImage!, 13, 45);
ctx.drawImage(assets.home.topScreen.clock, 13, 45);
const now = new Date();

View File

@@ -1,37 +1,7 @@
<script setup lang="ts">
import NOTIFICATION_IMAGE from "/assets/images/settings/top-screen/notification.webp";
import SETTINGS_IMAGE from "/assets/images/settings/top-screen/settings.webp";
import OPTIONS_IMAGE from "/assets/images/settings/top-screen/options/options.webp";
import CLOCK_IMAGE from "/assets/images/settings/top-screen/clock/clock.webp";
import USER_IMAGE from "/assets/images/settings/top-screen/user/user.webp";
import TOUCH_SCREEN_IMAGE from "/assets/images/settings/top-screen/touch_screen/touch-screen.webp";
import START_UP_IMAGE from "/assets/images/settings/top-screen/options/start-up.webp";
import LANGUAGE_IMAGE from "/assets/images/settings/top-screen/options/language.webp";
import GBA_MODE_IMAGE from "/assets/images/settings/top-screen/options/gba-mode.webp";
const store = useSettingsStore();
const [
notificationImage,
settingsImage,
optionsImage,
clockImage,
userImage,
touchScreenImage,
startUpImage,
languageImage,
gbaModeImage,
] = useImages(
NOTIFICATION_IMAGE,
SETTINGS_IMAGE,
OPTIONS_IMAGE,
CLOCK_IMAGE,
USER_IMAGE,
TOUCH_SCREEN_IMAGE,
START_UP_IMAGE,
LANGUAGE_IMAGE,
GBA_MODE_IMAGE,
);
const { assets } = useAssets();
const renderNotification = (
ctx: CanvasRenderingContext2D,
@@ -39,7 +9,7 @@ const renderNotification = (
title: string,
description: string,
) => {
ctx.drawImage(notificationImage!, 0, 0);
ctx.drawImage(assets.settings.topScreen.notification, 0, 0);
ctx.drawImage(image, 2, 2);
ctx.font = "10px NDS10";
@@ -55,7 +25,7 @@ const renderNotification = (
};
const mainNotification = computed(() => ({
image: settingsImage!,
image: assets.settings.topScreen.settings,
title: $t("settings.title"),
description: $t("settings.description"),
}));
@@ -67,16 +37,16 @@ const menuNotification = computed(() => {
let id = "";
if (/^options[A-Z]/.test(store.currentMenu)) {
image = optionsImage!;
image = assets.settings.topScreen.options.options;
id = "options";
} else if (/^clock[A-Z]/.test(store.currentMenu)) {
image = clockImage!;
image = assets.settings.topScreen.clock.clock;
id = "clock";
} else if (/^user[A-Z]/.test(store.currentMenu)) {
image = userImage!;
image = assets.settings.topScreen.user.user;
id = "user";
} else if (/^touchScreen[A-Z]/.test(store.currentMenu)) {
image = touchScreenImage!;
image = assets.settings.topScreen.touchScreen.touchScreen;
id = "touchScreen";
}
@@ -90,9 +60,9 @@ const menuNotification = computed(() => {
});
const IMAGES_MAP: Record<string, HTMLImageElement> = {
optionsStartUp: startUpImage!,
optionsLanguage: languageImage!,
optionsGbaMode: gbaModeImage!,
optionsStartUp: assets.settings.topScreen.options.startUp,
optionsLanguage: assets.settings.topScreen.options.language,
optionsGbaMode: assets.settings.topScreen.options.gbaMode,
};
const submenuNotification = computed(() => {

View File

@@ -1,21 +1,10 @@
<script setup lang="ts">
import STATUS_BAR_IMAGE from "/assets/images/home/top-screen/status-bar/status-bar.webp";
import GBA_DISPLAY_IMAGE from "/assets/images/home/top-screen/status-bar/gba-display.webp";
import STARTUP_MODE_IMAGE from "/assets/images/home/top-screen/status-bar/startup-mode.webp";
import BATTERY_IMAGE from "/assets/images/home/top-screen/status-bar/battery.webp";
const [statusBarImage, gbaDisplayImage, startupModeImage, batteryImage] =
useImages(
STATUS_BAR_IMAGE,
GBA_DISPLAY_IMAGE,
STARTUP_MODE_IMAGE,
BATTERY_IMAGE,
);
const { assets } = useAssets();
useRender((ctx) => {
const TEXT_Y = 11;
ctx.drawImage(statusBarImage!, 0, 0);
ctx.drawImage(assets.home.topScreen.statusBar.statusBar, 0, 0);
ctx.fillStyle = "#ffffff";
ctx.font = "7px NDS7";
@@ -45,9 +34,9 @@ useRender((ctx) => {
fillNumberCell(now.getMonth() + 1, 12, -1);
// icons
ctx.drawImage(gbaDisplayImage!, 210, 2);
ctx.drawImage(startupModeImage!, 226, 2);
ctx.drawImage(batteryImage!, 242, 4);
ctx.drawImage(assets.home.topScreen.statusBar.gbaDisplay, 210, 2);
ctx.drawImage(assets.home.topScreen.statusBar.startupMode, 226, 2);
ctx.drawImage(assets.home.topScreen.statusBar.battery, 242, 4);
});
defineOptions({

View File

@@ -0,0 +1,34 @@
const imageCache = new Map<string, HTMLImageElement>();
const loaded = ref(0);
const total = ref({{TOTAL}});
const isReady = computed(() => loaded.value === total.value);
const createImage = (path: string) => {
if (imageCache.has(path)) {
return imageCache.get(path)!;
}
const img = document.createElement('img');
img.src = path;
imageCache.set(path, img);
if (img.complete) {
loaded.value += 1;
} else {
img.onload = () => { loaded.value += 1 };
}
return img;
};
const assets = {{ASSETS}};
export const useAssets = () => {
return {
assets,
loaded,
total,
isReady,
};
};

View File

@@ -1,17 +0,0 @@
const imageCache = new Map<string, HTMLImageElement>();
export const useImages = (...paths: string[]) => {
const images = paths.map((path) => {
if (imageCache.has(path)) {
return imageCache.get(path)!;
}
const img = document.createElement("img");
img.src = path;
imageCache.set(path, img);
return img;
});
return images;
};

8
app/pages/test.vue Normal file
View File

@@ -0,0 +1,8 @@
<script setup lang="ts">
const { isReady } = useAssets();
</script>
<template>
<LoadingScreen v-if="!isReady" />
<p v-else>ok</p>
</template>

View File

@@ -38,7 +38,9 @@ export const useProjectsStore = defineStore("projects", {
if (!projects.value) throw "Cannot load projects";
this.projects = projects.value.map((project) => ({
...project,
id: project.id.split("/")[2]!,
id: project.id
.split("/")[2]!
.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase()),
}));
console.log(this.projects);