feat: full visuals
This commit is contained in:
+51
-32
@@ -11,10 +11,13 @@ import {
|
||||
} from "enka.ts";
|
||||
import { twj } from "tw-to-css";
|
||||
import type { App } from "@";
|
||||
import { generateBackground } from "@/assets/background";
|
||||
import { ConstsSvg } from "@/assets/consts";
|
||||
import { featherImage } from "@/assets/feather";
|
||||
import shadeSvg from "@/assets/shade.svg" with { type: "file" };
|
||||
import fontFile from "@/assets/shinshin.woff2" with { type: "file" };
|
||||
import { TalentSvg } from "@/assets/talent";
|
||||
import { mockData } from "@/lib/mock";
|
||||
import { AvatarStore } from "@/type/enka";
|
||||
|
||||
const cache = new TTLCache();
|
||||
@@ -39,8 +42,8 @@ export function card(app: App) {
|
||||
try {
|
||||
const avatarStore = await getEnkaAvatarStore();
|
||||
console.log(`${Date.now() - start}ms - Avatar store loaded`);
|
||||
// const data = mockData;
|
||||
const data = await fetchEnka(uid, false);
|
||||
// const data = await fetchEnka(uid, false);
|
||||
const data = mockData;
|
||||
console.log(`${Date.now() - start}ms - Enka data loaded`);
|
||||
if (typeof data.avatarInfoList === "undefined")
|
||||
return status(400, "The showcase for this UID is private");
|
||||
@@ -55,38 +58,54 @@ export function card(app: App) {
|
||||
500,
|
||||
"Unsupported character, avatar store doesn't have this character",
|
||||
);
|
||||
const resources = await Promise.all(
|
||||
[
|
||||
...avatar.Consts,
|
||||
...Object.values(avatar.Skills),
|
||||
...Object.values(avatar.Costumes ?? {})
|
||||
.map((c) => c.Art)
|
||||
.slice(0, 1),
|
||||
avatar.SideIconName.replace(
|
||||
"AvatarIcon_Side",
|
||||
"Gacha_AvatarImg",
|
||||
),
|
||||
].map(async (path) => ({
|
||||
src: path,
|
||||
data: await fetch(new URL(path, "https://enka.network")).then(
|
||||
(res) => res.arrayBuffer(),
|
||||
const resources = await Promise.all([
|
||||
...[...avatar.Consts, ...Object.values(avatar.Skills)].map(
|
||||
async (path) => ({
|
||||
src: path,
|
||||
data: await fetch(
|
||||
new URL(path, "https://enka.network"),
|
||||
).then((res) => res.arrayBuffer()),
|
||||
}),
|
||||
),
|
||||
fetch(
|
||||
new URL(
|
||||
avatar.SideIconName.replace(
|
||||
"AvatarIcon_Side",
|
||||
"Gacha_AvatarImg",
|
||||
),
|
||||
"https://enka.network",
|
||||
),
|
||||
)
|
||||
.then((res) => res.arrayBuffer())
|
||||
.then(async (buf) => ({
|
||||
src: "/avatar",
|
||||
data: await featherImage(buf, [0, 0.3, 0, 0]),
|
||||
})),
|
||||
generateBackground({
|
||||
element: avatar.Element,
|
||||
width: 1218,
|
||||
height: 508,
|
||||
}).then((r) => ({
|
||||
src: "/bg",
|
||||
data: r.canvas.toBuffer("image/webp"),
|
||||
})),
|
||||
]);
|
||||
console.log(
|
||||
`${Date.now() - start}ms - Image resources loaded\n${resources.map((r) => `- ${r.src} ${(r.data.byteLength / 1000).toFixed(2)}Kb`).join("\n")}`,
|
||||
);
|
||||
console.log(`${Date.now() - start}ms - Image resources loaded`);
|
||||
|
||||
return new ImageResponse(
|
||||
<div tw="relative text-[14.8667px] text-white">
|
||||
<div tw="aspect-[1218/508] h-full"></div>
|
||||
<div tw="relative text-[32.25px] text-white rounded-xl overflow-hidden">
|
||||
<div tw="aspect-[1218/508] h-full">
|
||||
<img
|
||||
src="/bg"
|
||||
alt="background"
|
||||
tw="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
{/* avatar */}
|
||||
<img
|
||||
src={
|
||||
avatar.Costumes?.[0]?.Art ||
|
||||
avatar.SideIconName.replace(
|
||||
"AvatarIcon_Side",
|
||||
"Gacha_AvatarImg",
|
||||
)
|
||||
}
|
||||
src="/avatar"
|
||||
alt="char"
|
||||
tw="object-cover h-full aspect-[1024/1124] absolute top-0 -left-[2.5em] scale-x-[1.1] scale-y-[1.15]"
|
||||
/>
|
||||
@@ -106,7 +125,7 @@ export function card(app: App) {
|
||||
{/* char and username */}
|
||||
<div tw="text-[130%] pb-[.5%] flex items-center gap-[.5em]">
|
||||
{char.avatar.name}
|
||||
<div tw="text-[11.596px] opacity-80">
|
||||
<div tw="text-[0.75em] opacity-80">
|
||||
▴ {data.playerInfo.nickname}
|
||||
</div>
|
||||
</div>
|
||||
@@ -175,7 +194,7 @@ export function card(app: App) {
|
||||
{Object.entries(avatar.Skills).map(([key, src]) => {
|
||||
const talentLevel = char.skillLevelMap?.[key] ?? 0;
|
||||
return (
|
||||
<div tw="mt-[.3em] relative">
|
||||
<div tw="mt-[.6em] relative">
|
||||
<TalentSvg
|
||||
tw={`Talents ${char.avatar.element} w-[3.6em] opacity-80 text-black`}
|
||||
/>
|
||||
@@ -199,13 +218,13 @@ export function card(app: App) {
|
||||
</div>
|
||||
</div>
|
||||
{/* middle section */}
|
||||
<div tw="absolute top-0 bottom-0 right-[23.1em] w-[21.5em] p-[1.4em_.7em_.7em] bg-green-500/50"></div>
|
||||
<div tw="absolute top-0 bottom-0 right-[23.1em] w-[21.5em] p-[1.4em_.7em_.7em]"></div>
|
||||
{/* right section */}
|
||||
<div tw="absolute top-0 bottom-0 right-0 w-[23.1em] p-[.7em] bg-blue-500/50"></div>
|
||||
<div tw="absolute top-0 bottom-0 right-0 w-[23.1em] p-[.7em]"></div>
|
||||
</div>,
|
||||
{
|
||||
fonts: [await font.arrayBuffer()],
|
||||
height: 508,
|
||||
height: 1024,
|
||||
persistentImages: [
|
||||
{ data: await shade.arrayBuffer(), src: "shade" },
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user