67 lines
2.4 KiB
TypeScript
67 lines
2.4 KiB
TypeScript
import { z } from "zod";
|
|
|
|
export const BEAM_AVATAR_RENDERER_VERSION = 1 as const;
|
|
|
|
export const beamAvatarPalettes = [
|
|
{ name: "星砂", colors: ["#17324D", "#2D6073", "#D5A45D", "#F2E6CF", "#B9684A"] },
|
|
{ name: "靛夜", colors: ["#202842", "#495B8C", "#93A3D1", "#E4D9C7", "#C58D68"] },
|
|
{ name: "莲火", colors: ["#553640", "#A35D63", "#D99B7A", "#F2D8BA", "#5E7161"] },
|
|
{ name: "松雾", colors: ["#1F3D3A", "#4D746C", "#A7B59A", "#E8DEC8", "#C77B56"] },
|
|
{ name: "晨曦", colors: ["#34405F", "#7484A6", "#E2AF72", "#F4E5C9", "#B75D54"] },
|
|
{ name: "紫藤", colors: ["#3E3555", "#77638F", "#B9A3CA", "#E9DCCB", "#C47B6C"] },
|
|
{ name: "海盐", colors: ["#1D4554", "#4F8090", "#A8C0BD", "#EFE2C8", "#D18A5D"] },
|
|
{ name: "桂影", colors: ["#443B2D", "#7B6848", "#C6A25E", "#EFE0BE", "#8C5B4C"] },
|
|
] as const;
|
|
|
|
export const beamAvatarPaletteSchema = z.number().int().min(0).max(beamAvatarPalettes.length - 1);
|
|
|
|
export const beamAvatarSchema = z.object({
|
|
seed: z.string().uuid(),
|
|
palette: beamAvatarPaletteSchema,
|
|
rendererVersion: z.literal(BEAM_AVATAR_RENDERER_VERSION),
|
|
}).strict();
|
|
|
|
export const beamAvatarPatchSchema = z.discriminatedUnion("action", [
|
|
z.object({
|
|
action: z.literal("set_palette"),
|
|
palette: beamAvatarPaletteSchema,
|
|
}).strict(),
|
|
z.object({
|
|
action: z.literal("randomize"),
|
|
palette: beamAvatarPaletteSchema.optional(),
|
|
}).strict(),
|
|
]);
|
|
|
|
export type BeamAvatar = z.infer<typeof beamAvatarSchema>;
|
|
export type BeamAvatarPatch = z.infer<typeof beamAvatarPatchSchema>;
|
|
|
|
export function createBeamAvatarProfilePatch(
|
|
patch: BeamAvatarPatch,
|
|
createSeed: () => string = () => globalThis.crypto.randomUUID(),
|
|
) {
|
|
return {
|
|
...(patch.palette !== undefined ? { avatar_palette: patch.palette } : {}),
|
|
avatar_renderer_version: BEAM_AVATAR_RENDERER_VERSION,
|
|
...(patch.action === "randomize" ? { avatar_seed: createSeed() } : {}),
|
|
};
|
|
}
|
|
|
|
export function beamAvatarFromProfile(profile: Record<string, unknown>): BeamAvatar {
|
|
return beamAvatarSchema.parse({
|
|
seed: profile.avatar_seed,
|
|
palette: profile.avatar_palette,
|
|
rendererVersion: profile.avatar_renderer_version,
|
|
});
|
|
}
|
|
|
|
export function optionalBeamAvatarFromProfile(
|
|
profile: Record<string, unknown>,
|
|
): BeamAvatar | null {
|
|
const parsed = beamAvatarSchema.safeParse({
|
|
seed: profile.avatar_seed,
|
|
palette: profile.avatar_palette,
|
|
rendererVersion: profile.avatar_renderer_version,
|
|
});
|
|
return parsed.success ? parsed.data : null;
|
|
}
|