feat(credits): add in both nds and repo
This commit is contained in:
19
CREDITS.md
Normal file
19
CREDITS.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Credits
|
||||||
|
|
||||||
|
## 3D Model
|
||||||
|
|
||||||
|
**"Nintendo DS Lite"** by Cianon
|
||||||
|
https://skfb.ly/6ZDvQ
|
||||||
|
Licensed under [Creative Commons Attribution 4.0](http://creativecommons.org/licenses/by/4.0/)
|
||||||
|
Modified from the original.
|
||||||
|
|
||||||
|
## 2D Nintendo DS CSS
|
||||||
|
|
||||||
|
Based on **"CSS Nintendo DS"** by Alexandra Radevich (@aradevich)
|
||||||
|
https://codepen.io/aradevich/pen/mdRYzyJ
|
||||||
|
|
||||||
|
## UI Design & Sound Effects
|
||||||
|
|
||||||
|
**Nintendo DS** — UI design and sound effects are property of Nintendo.
|
||||||
|
https://nintendo.com
|
||||||
|
© Nintendo
|
||||||
99
app/components/Credits/BottomScreen.vue
Normal file
99
app/components/Credits/BottomScreen.vue
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { onRender, onClick, onMouseDown } = useScreen();
|
||||||
|
const store = useCreditsStore();
|
||||||
|
const { assets } = useAssets((a) => a.images.credits);
|
||||||
|
|
||||||
|
const QUIT_SIZE = assets.quit.rect.width;
|
||||||
|
const QUIT_X = Math.floor(LOGICAL_WIDTH / 2 - QUIT_SIZE / 2);
|
||||||
|
const QUIT_Y = 135;
|
||||||
|
|
||||||
|
const quitPressed = ref(false);
|
||||||
|
|
||||||
|
const handleMouseUp = () => {
|
||||||
|
quitPressed.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => document.addEventListener("mouseup", handleMouseUp));
|
||||||
|
onUnmounted(() => document.removeEventListener("mouseup", handleMouseUp));
|
||||||
|
|
||||||
|
onMouseDown((x, y) => {
|
||||||
|
if (store.isIntro || store.isOutro) return;
|
||||||
|
if (rectContains([QUIT_X, QUIT_Y, QUIT_SIZE, QUIT_SIZE], [x, y])) {
|
||||||
|
quitPressed.value = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useKeyDown(({ key, repeated }) => {
|
||||||
|
if (store.isIntro || store.isOutro || repeated) return;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case "NDS_B":
|
||||||
|
case "NDS_A":
|
||||||
|
case "NDS_START": {
|
||||||
|
store.animateOutro();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onClick((x, y) => {
|
||||||
|
if (store.isIntro || store.isOutro) return;
|
||||||
|
|
||||||
|
if (rectContains([QUIT_X, QUIT_Y, QUIT_SIZE, QUIT_SIZE], [x, y])) {
|
||||||
|
store.animateOutro();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onRender((ctx) => {
|
||||||
|
ctx.fillStyle = "#000000";
|
||||||
|
ctx.fillRect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
|
||||||
|
|
||||||
|
// credits list (bottom screen entries)
|
||||||
|
ctx.globalAlpha = store.isIntro
|
||||||
|
? store.intro.stage1Opacity
|
||||||
|
: store.isOutro
|
||||||
|
? store.outro.stage1Opacity
|
||||||
|
: 1;
|
||||||
|
ctx.textBaseline = "top";
|
||||||
|
|
||||||
|
for (let i = CREDITS.length - 1; i >= CREDITS_TOP_SCREEN_COUNT; i--) {
|
||||||
|
const id = CREDITS[i]!;
|
||||||
|
const offset = store.getItemOffset(i);
|
||||||
|
if (offset === -CREDITS_LINE_HEIGHT) continue;
|
||||||
|
|
||||||
|
const baseY =
|
||||||
|
CREDITS_BOTTOM_START_Y +
|
||||||
|
(i - CREDITS_TOP_SCREEN_COUNT) * CREDITS_ENTRY_HEIGHT;
|
||||||
|
const y = baseY + offset;
|
||||||
|
|
||||||
|
ctx.fillStyle = "#000000";
|
||||||
|
ctx.fillRect(0, y, LOGICAL_WIDTH, CREDITS_LINE_HEIGHT * 3);
|
||||||
|
|
||||||
|
ctx.fillStyle = "#aaaaaa";
|
||||||
|
ctx.font = "7px NDS7";
|
||||||
|
fillTextHCentered(ctx, $t(`creditsScreen.${id}.label`), 0, y, LOGICAL_WIDTH);
|
||||||
|
|
||||||
|
ctx.fillStyle = "#ffffff";
|
||||||
|
ctx.font = "10px NDS10";
|
||||||
|
fillTextHCentered(ctx, $t(`creditsScreen.${id}.author`), 0, y + CREDITS_LINE_HEIGHT, LOGICAL_WIDTH);
|
||||||
|
|
||||||
|
ctx.fillStyle = "#888888";
|
||||||
|
ctx.font = "7px NDS7";
|
||||||
|
fillTextHCentered(ctx, $t(`creditsScreen.${id}.url`), 0, y + CREDITS_LINE_HEIGHT * 2, LOGICAL_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.globalAlpha = store.isIntro
|
||||||
|
? store.intro.stage1Opacity
|
||||||
|
: store.isOutro
|
||||||
|
? store.outro.stage2Opacity
|
||||||
|
: 1;
|
||||||
|
(quitPressed.value ? assets.quitPressed : assets.quit).draw(
|
||||||
|
ctx,
|
||||||
|
QUIT_X,
|
||||||
|
QUIT_Y,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
render: () => null,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
17
app/components/Credits/FadeToBlack.vue
Normal file
17
app/components/Credits/FadeToBlack.vue
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { onRender } = useScreen();
|
||||||
|
const store = useCreditsStore();
|
||||||
|
|
||||||
|
onRender((ctx) => {
|
||||||
|
if (!store.fadeToBlack.active) return;
|
||||||
|
if (store.fadeToBlack.isOutro && store.fadeToBlack.opacity === 0) return;
|
||||||
|
|
||||||
|
ctx.globalAlpha = store.fadeToBlack.opacity;
|
||||||
|
ctx.fillStyle = "#000000";
|
||||||
|
ctx.fillRect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
|
||||||
|
}, 9999);
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
render: () => null,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
67
app/components/Credits/TopScreen.vue
Normal file
67
app/components/Credits/TopScreen.vue
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { onRender } = useScreen();
|
||||||
|
const store = useCreditsStore();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
store.$reset();
|
||||||
|
store.animateIntro(CREDITS.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
onRender((ctx) => {
|
||||||
|
ctx.fillStyle = "#000000";
|
||||||
|
ctx.fillRect(0, 0, LOGICAL_WIDTH, LOGICAL_HEIGHT);
|
||||||
|
|
||||||
|
ctx.globalAlpha = store.isIntro
|
||||||
|
? store.intro.stage1Opacity
|
||||||
|
: store.isOutro
|
||||||
|
? store.outro.stage2Opacity
|
||||||
|
: 1;
|
||||||
|
ctx.fillStyle = "#ffffff";
|
||||||
|
ctx.textBaseline = "top";
|
||||||
|
|
||||||
|
// title
|
||||||
|
ctx.font = "10px NDS10";
|
||||||
|
fillTextHCentered(
|
||||||
|
ctx,
|
||||||
|
$t("creditsScreen.title"),
|
||||||
|
0,
|
||||||
|
CREDITS_HEADER_Y,
|
||||||
|
LOGICAL_WIDTH,
|
||||||
|
);
|
||||||
|
|
||||||
|
// credits list (top screen entries only)
|
||||||
|
ctx.globalAlpha = store.isIntro
|
||||||
|
? store.intro.stage1Opacity
|
||||||
|
: store.isOutro
|
||||||
|
? store.outro.stage1Opacity
|
||||||
|
: 1;
|
||||||
|
|
||||||
|
for (let i = CREDITS_TOP_SCREEN_COUNT - 1; i >= 0; i--) {
|
||||||
|
const id = CREDITS[i]!;
|
||||||
|
const offset = store.getItemOffset(i);
|
||||||
|
if (offset === -CREDITS_LINE_HEIGHT) continue;
|
||||||
|
|
||||||
|
const baseY = CREDITS_LIST_START_Y + i * CREDITS_ENTRY_HEIGHT;
|
||||||
|
const y = baseY + offset;
|
||||||
|
|
||||||
|
ctx.fillStyle = "#000000";
|
||||||
|
ctx.fillRect(0, y, LOGICAL_WIDTH, CREDITS_LINE_HEIGHT * 3);
|
||||||
|
|
||||||
|
ctx.fillStyle = "#aaaaaa";
|
||||||
|
ctx.font = "7px NDS7";
|
||||||
|
fillTextHCentered(ctx, $t(`creditsScreen.${id}.label`), 0, y, LOGICAL_WIDTH);
|
||||||
|
|
||||||
|
ctx.fillStyle = "#ffffff";
|
||||||
|
ctx.font = "10px NDS10";
|
||||||
|
fillTextHCentered(ctx, $t(`creditsScreen.${id}.author`), 0, y + CREDITS_LINE_HEIGHT, LOGICAL_WIDTH);
|
||||||
|
|
||||||
|
ctx.fillStyle = "#888888";
|
||||||
|
ctx.font = "7px NDS7";
|
||||||
|
fillTextHCentered(ctx, $t(`creditsScreen.${id}.url`), 0, y + CREDITS_LINE_HEIGHT * 2, LOGICAL_WIDTH);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
render: () => null,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -7,4 +7,5 @@ import Buttons from "./Buttons.vue";
|
|||||||
<Background />
|
<Background />
|
||||||
<Buttons />
|
<Buttons />
|
||||||
<AchievementsFadeToBlack />
|
<AchievementsFadeToBlack />
|
||||||
|
<CreditsFadeToBlack />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -13,13 +13,12 @@ const { selected, pressed, selectorPosition } = useButtonNavigation({
|
|||||||
contact: [31, 71, 97, 49],
|
contact: [31, 71, 97, 49],
|
||||||
gallery: [127, 71, 97, 49],
|
gallery: [127, 71, 97, 49],
|
||||||
|
|
||||||
theme: [0, 167, 31, 26],
|
credits: [0, 167, 31, 26],
|
||||||
settings: [112, 167, 31, 26],
|
settings: [112, 167, 31, 26],
|
||||||
achievements: [225, 167, 31, 26],
|
achievements: [225, 167, 31, 26],
|
||||||
},
|
},
|
||||||
initialButton: store.selectedButton,
|
initialButton: store.selectedButton,
|
||||||
onActivate: (button) => {
|
onActivate: (button) => {
|
||||||
if (button === "theme") throw new Error(`Not implemented: ${button}`);
|
|
||||||
store.animateOutro(button);
|
store.animateOutro(button);
|
||||||
},
|
},
|
||||||
navigation: {
|
navigation: {
|
||||||
@@ -39,11 +38,11 @@ const { selected, pressed, selectorPosition } = useButtonNavigation({
|
|||||||
left: "contact",
|
left: "contact",
|
||||||
down: "settings",
|
down: "settings",
|
||||||
},
|
},
|
||||||
theme: {
|
credits: {
|
||||||
right: "settings",
|
right: "settings",
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
left: "theme",
|
left: "credits",
|
||||||
up: "last",
|
up: "last",
|
||||||
right: "achievements",
|
right: "achievements",
|
||||||
},
|
},
|
||||||
@@ -161,9 +160,9 @@ onRender((ctx) => {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
:x="10"
|
:x="10"
|
||||||
:y="175 + getButtonOffset('theme')"
|
:y="175 + getButtonOffset('credits')"
|
||||||
:opacity="getOpacity('theme')"
|
:opacity="getOpacity('credits')"
|
||||||
:image="getButtonImage('theme')"
|
:image="getButtonImage('credits')"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
:x="117"
|
:x="117"
|
||||||
|
|||||||
@@ -17,4 +17,5 @@ onMounted(() => {
|
|||||||
<Clock />
|
<Clock />
|
||||||
<StatusBar />
|
<StatusBar />
|
||||||
<AchievementsFadeToBlack />
|
<AchievementsFadeToBlack />
|
||||||
|
<CreditsFadeToBlack />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ useKeyDown(async ({ key, repeated }) => {
|
|||||||
<SettingsTopScreen v-else-if="app.screen === 'settings'" />
|
<SettingsTopScreen v-else-if="app.screen === 'settings'" />
|
||||||
<GalleryTopScreen v-else-if="app.screen === 'gallery'" />
|
<GalleryTopScreen v-else-if="app.screen === 'gallery'" />
|
||||||
<AchievementsTopScreen v-else-if="app.screen === 'achievements'" />
|
<AchievementsTopScreen v-else-if="app.screen === 'achievements'" />
|
||||||
|
<CreditsTopScreen v-else-if="app.screen === 'credits'" />
|
||||||
|
|
||||||
<AchievementsNotification />
|
<AchievementsNotification />
|
||||||
<CommonConfetti screen="top" />
|
<CommonConfetti screen="top" />
|
||||||
@@ -201,6 +202,7 @@ useKeyDown(async ({ key, repeated }) => {
|
|||||||
<SettingsBottomScreen v-else-if="app.screen === 'settings'" />
|
<SettingsBottomScreen v-else-if="app.screen === 'settings'" />
|
||||||
<GalleryBottomScreen v-else-if="app.screen === 'gallery'" />
|
<GalleryBottomScreen v-else-if="app.screen === 'gallery'" />
|
||||||
<AchievementsBottomScreen v-else-if="app.screen === 'achievements'" />
|
<AchievementsBottomScreen v-else-if="app.screen === 'achievements'" />
|
||||||
|
<CreditsBottomScreen v-else-if="app.screen === 'credits'" />
|
||||||
|
|
||||||
<CommonConfetti screen="bottom" />
|
<CommonConfetti screen="bottom" />
|
||||||
</Screen>
|
</Screen>
|
||||||
|
|||||||
156
app/stores/credits.ts
Normal file
156
app/stores/credits.ts
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
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;
|
||||||
@@ -4,9 +4,9 @@ export type HomeButton =
|
|||||||
| "projects"
|
| "projects"
|
||||||
| "contact"
|
| "contact"
|
||||||
| "gallery"
|
| "gallery"
|
||||||
| "theme"
|
|
||||||
| "settings"
|
| "settings"
|
||||||
| "achievements";
|
| "achievements"
|
||||||
|
| "credits";
|
||||||
|
|
||||||
export const useHomeStore = defineStore("home", {
|
export const useHomeStore = defineStore("home", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
@@ -32,7 +32,10 @@ export const useHomeStore = defineStore("home", {
|
|||||||
actions: {
|
actions: {
|
||||||
reset() {
|
reset() {
|
||||||
const app = useAppStore();
|
const app = useAppStore();
|
||||||
if (app.previousScreen === "achievements") {
|
if (
|
||||||
|
app.previousScreen === "achievements" ||
|
||||||
|
app.previousScreen === "credits"
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +108,12 @@ export const useHomeStore = defineStore("home", {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (to === "credits") {
|
||||||
|
const creditsScreen = useCreditsStore();
|
||||||
|
creditsScreen.animateFadeToBlackIntro();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.isOutro = true;
|
this.isOutro = true;
|
||||||
this.outro.animateTop = to !== "settings";
|
this.outro.animateTop = to !== "settings";
|
||||||
|
|
||||||
|
|||||||
3
app/types/app.d.ts
vendored
3
app/types/app.d.ts
vendored
@@ -4,4 +4,5 @@ type AppScreen =
|
|||||||
| "projects"
|
| "projects"
|
||||||
| "settings"
|
| "settings"
|
||||||
| "gallery"
|
| "gallery"
|
||||||
| "achievements";
|
| "achievements"
|
||||||
|
| "credits";
|
||||||
|
|||||||
@@ -14,6 +14,24 @@
|
|||||||
"achievementsScreen": {
|
"achievementsScreen": {
|
||||||
"title": "Achievements"
|
"title": "Achievements"
|
||||||
},
|
},
|
||||||
|
"creditsScreen": {
|
||||||
|
"title": "Credits",
|
||||||
|
"model3d": {
|
||||||
|
"label": "3D Model",
|
||||||
|
"author": "Nintendo DS Lite by Cianon",
|
||||||
|
"url": "skfb.ly/6ZDvQ - CC BY 4.0"
|
||||||
|
},
|
||||||
|
"css2d": {
|
||||||
|
"label": "2D CSS",
|
||||||
|
"author": "CSS Nintendo DS by A. Radevich",
|
||||||
|
"url": "codepen.io/aradevich/pen/mdRYzyJ"
|
||||||
|
},
|
||||||
|
"nintendo": {
|
||||||
|
"label": "UI Design & Sound Effects",
|
||||||
|
"author": "Nintendo DS",
|
||||||
|
"url": "nintendo.com - © Nintendo"
|
||||||
|
}
|
||||||
|
},
|
||||||
"achievements": {
|
"achievements": {
|
||||||
"boot": "Boot up the system",
|
"boot": "Boot up the system",
|
||||||
"projects_visit": "Visit the projects\nsection",
|
"projects_visit": "Visit the projects\nsection",
|
||||||
|
|||||||
BIN
public/nds/images/credits/quit-pressed.webp
Normal file
BIN
public/nds/images/credits/quit-pressed.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 236 B |
BIN
public/nds/images/credits/quit.webp
Normal file
BIN
public/nds/images/credits/quit.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 172 B |
Binary file not shown.
|
After Width: | Height: | Size: 84 B |
BIN
public/nds/images/home/bottom-screen/buttons/credits.webp
Normal file
BIN
public/nds/images/home/bottom-screen/buttons/credits.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 B |
Reference in New Issue
Block a user