import type { AgentAvatarProfile } from "./profile"; const AVATAR_BG = "#070b16"; const EYE_COLOR = "#111827"; const HEADSET_BAND = "#94a3b8"; const HEADSET_PAD = "#475569"; const MOUTH_COLOR = "#9c4a4a"; const escapeXml = (value: string) => value .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); const normalizeHex = (value: string): string | null => { const trimmed = value.trim(); if (/^#[0-9a-f]{6}$/i.test(trimmed)) return trimmed.toLowerCase(); if (/^#[0-9a-f]{3}$/i.test(trimmed)) { const [, r, g, b] = trimmed; return `#${r}${r}${g}${g}${b}${b}`.toLowerCase(); } return null; }; const blendHex = (source: string, target: string, weight: number): string => { const sourceHex = normalizeHex(source); const targetHex = normalizeHex(target); if (!sourceHex || !targetHex) return source; const ratio = Math.max(0, Math.min(1, weight)); const sourceChannels = [ Number.parseInt(sourceHex.slice(1, 3), 16), Number.parseInt(sourceHex.slice(3, 5), 16), Number.parseInt(sourceHex.slice(5, 7), 16), ]; const targetChannels = [ Number.parseInt(targetHex.slice(1, 3), 16), Number.parseInt(targetHex.slice(3, 5), 16), Number.parseInt(targetHex.slice(5, 7), 16), ]; const mixed = sourceChannels.map((channel, index) => Math.round(channel * (1 - ratio) + targetChannels[index] * ratio) ); return `#${mixed.map((channel) => channel.toString(16).padStart(2, "0")).join("")}`; }; const buildHairSvg = (profile: AgentAvatarProfile, hairColor: string) => { if (profile.accessories.hatStyle !== "none") return ""; switch (profile.hair.style) { case "short": return ``; case "parted": return [ ``, ``, ].join(""); case "spiky": return [ ``, ``, ``, ``, ].join(""); case "bun": return [ ``, ``, ].join(""); default: return ""; } }; const buildHatSvg = (profile: AgentAvatarProfile, accessoryColor: string) => { switch (profile.accessories.hatStyle) { case "cap": return [ ``, ``, ].join(""); case "beanie": return ``; default: return ""; } }; const buildHeadsetSvg = (enabled: boolean) => { if (!enabled) return ""; return [ ``, ``, ``, ].join(""); }; const buildGlassesSvg = (enabled: boolean) => { if (!enabled) return ""; return [ ``, ``, ``, ].join(""); }; export const buildAgentAvatarPortraitSvg = (profile: AgentAvatarProfile): string => { const skinTone = profile.body.skinTone; const hairColor = profile.hair.color; const topColor = profile.clothing.topColor; const accessoryColor = blendHex(topColor, "#ffffff", 0.08); const shirtShadow = blendHex(topColor, "#000000", 0.18); const faceShadow = blendHex(skinTone, "#000000", 0.12); const faceHighlight = blendHex(skinTone, "#ffffff", 0.16); return [ ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, buildHairSvg(profile, hairColor), buildHatSvg(profile, accessoryColor), buildHeadsetSvg(profile.accessories.headset), ``, ``, buildGlassesSvg(profile.accessories.glasses), ``, ``, ].join(""); }; export const buildAgentAvatarPortraitDataUrl = (profile: AgentAvatarProfile): string => `data:image/svg+xml;utf8,${encodeURIComponent(buildAgentAvatarPortraitSvg(profile))}`;