Fix logo generator: remove decorative fonts and fix missing char spacing

This commit is contained in:
openhands committed 2026-07-07 16:50:58 +02:00
1 parent 9a7b40eae6
commit 0272da09c1
3 files changed
+28 -57

No files matched your search

+4 -51
View File
@@ -25,7 +25,6 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
{ name: "Habjoy light", styleName: "habjoy_light" },
{ name: "Paradise", styleName: "paradise" },
{ name: "Paradise 2", styleName: "paradise_rounded" },
{ name: "Habbnew", styleName: "habbnew" },
{ name: "Habbo Clicker", styleName: "habbo_clicker" },
{ name: "Reception", styleName: "reception" },
],
@@ -35,7 +34,6 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
fonts: [
{ name: "Accessoires", styleName: "accessoires" },
{ name: "Africa", styleName: "africa" },
{ name: "Alhambra", styleName: "alhambra" },
{ name: "Arctic", styleName: "arctic", hasNumbers: true },
{ name: "Asian", styleName: "asian" },
{ name: "Asian small", styleName: "asian_small" },
@@ -44,11 +42,9 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
{ name: "Bathroom", styleName: "bathroom", hasNumbers: true },
{ name: "Battle Banzai", styleName: "battlebanzai" },
{ name: "Bensalem", styleName: "bensalem", hasNumbers: true },
{ name: "Bensalem sea", styleName: "bensalem_sea" },
{ name: "Bling", styleName: "bling", hasNumbers: true },
{ name: "Bling Gold", styleName: "bling_gold" },
{ name: "Bones", styleName: "bones" },
{ name: "Books", styleName: "books", hasNumbers: true },
{ name: "Bots", styleName: "bots" },
{ name: "Bubble", styleName: "bubble" },
{ name: "Bubble blue", styleName: "bubble_blue" },
@@ -58,14 +54,11 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
{ name: "Buttons", styleName: "buttons" },
{ name: "Candy", styleName: "candy" },
{ name: "Collectibles", styleName: "collectibles" },
{ name: "Crystal", styleName: "crystal" },
{ name: "Cubie", styleName: "cubie" },
{ name: "Disco", styleName: "disco" },
{ name: "Dreams", styleName: "dreams" },
{ name: "Dreams flat", styleName: "dreams_flat" },
{ name: "Duckets", styleName: "duckets" },
{ name: "Emo", styleName: "emo" },
{ name: "Exchange", styleName: "exchange" },
{ name: "Executive", styleName: "executive" },
{ name: "Explore", styleName: "explore" },
{ name: "Explore big", styleName: "explore_big" },
@@ -74,12 +67,11 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
{ name: "F.BOMB", styleName: "fbomb" },
{ name: "Festival", styleName: "festival" },
{ name: "Flags", styleName: "flags" },
{ name: "FX", styleName: "fx" },
{ name: "Freehand", styleName: "freehand" },
{ name: "Gaming", styleName: "gaming" },
{ name: "Gallery", styleName: "gallery" },
{ name: "Golden temple", styleName: "goldentemple" },
{ name: "Gravity", styleName: "gravity" },
{ name: "HMA", styleName: "hma" },
{ name: "Habbo gold", styleName: "gold_big" },
{ name: "Habbo news", styleName: "habbo_news" },
@@ -99,8 +91,6 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
{ name: "Love", styleName: "love" },
{ name: "Marketplace red", styleName: "marketplace_red" },
{ name: "Monkey", styleName: "monkey" },
{ name: "Mushroom", styleName: "mushroom" },
{ name: "Mushroom green", styleName: "mushroom_green" },
{ name: "Neon blue", styleName: "neon_blue", hasNumbers: true },
{ name: "Neon green", styleName: "neon_green", hasNumbers: true },
{ name: "Neon pink", styleName: "neon_pink", hasNumbers: true },
@@ -127,8 +117,6 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
{ name: "Spaces", styleName: "spaces" },
{ name: "Special offers", styleName: "special_offers" },
{ name: "StrayPixels", styleName: "straypixels" },
{ name: "Steampunk", styleName: "steampunk" },
{ name: "SCI-FI", styleName: "scifi" },
{ name: "Summer", styleName: "summer" },
{ name: "Teleport", styleName: "teleport", hasNumbers: true },
{ name: "Theater lights", styleName: "theater_lights" },
@@ -136,7 +124,6 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
{ name: "Trophies", styleName: "trophies" },
{ name: "USVA", styleName: "usva" },
{ name: "Unknown blue", styleName: "unknown_blue" },
{ name: "Unknown blue 2", styleName: "unknown_blue_2" },
{ name: "Unknown metal", styleName: "unknown_metal" },
{ name: "Unknown white", styleName: "unknown_white" },
{ name: "Unknown pillow", styleName: "unknown_pillow_1" },
@@ -164,8 +151,6 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
{
groupName: "Group fonts",
fonts: [
{ name: "Bling", styleName: "bling" },
{ name: "Plastic", styleName: "plastic" },
{ name: "Plastic playful", styleName: "plastic_playful" },
{ name: "Dinner blue", styleName: "dinner_blue", hasNumbers: true },
{ name: "Dinner green", styleName: "dinner_green", hasNumbers: true },
@@ -176,10 +161,7 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
groupName: "Games",
fonts: [
{ name: "Battleball", styleName: "battleball" },
{ name: "Battle Banzai", styleName: "battlebanzai" },
{ name: "Lido", styleName: "lido", hasNumbers: true },
{ name: "Soccer", styleName: "soccer" },
{ name: "Soccer big", styleName: "soccer_big" },
],
},
{
@@ -191,9 +173,7 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
{ name: "HC Compact", styleName: "hc_compact", hasNumbers: true },
{ name: "HC gold", styleName: "hc_gold" },
{ name: "Habbo Club 2", styleName: "habboclub", hasNumbers: true },
{ name: "Habbo Club 2", styleName: "habboclub_banner", hasNumbers: true },
{ name: "VIP", styleName: "habbovip", hasNumbers: true },
{ name: "VIP", styleName: "habbovip_banner", hasNumbers: true },
],
},
{
@@ -212,15 +192,12 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
groupName: "Windows",
fonts: [
{ name: "Windows", styleName: "windows" },
{ name: "Lowercase", styleName: "windows_lowercase" },
{ name: "Jungle", styleName: "windows_jungle" },
{ name: "Blue", styleName: "windows_blue", hasNumbers: true },
{ name: "Green", styleName: "windows_green", hasNumbers: true },
{ name: "Pink", styleName: "windows_pink", hasNumbers: true },
{ name: "Red", styleName: "windows_red", hasNumbers: true },
{ name: "Dark red", styleName: "windows_red_dark", hasNumbers: true },
{ name: "Yellow", styleName: "windows_yellow" },
{ name: "Purple", styleName: "windows_purple" },
],
},
{
@@ -235,37 +212,13 @@ export const HABBO_FONT_GROUPS: HabboFontGroup[] = [
{
groupName: "Special fonts",
fonts: [
{ name: "Duckets", styleName: "duckets" },
{ name: "Habbo club", styleName: "habboclub_complete" },
{ name: "FX", styleName: "fx" },
{ name: "Gift", styleName: "gift" },
{ name: "HC silver", styleName: "habboclub_silver" },
{ name: "Love full", styleName: "love_full" },
{ name: "Marketplace", styleName: "marketplace_full" },
{ name: "RELAX", styleName: "relax" },
{ name: "Ribbon", styleName: "habbo_ribbon" },
{ name: "Scifi", styleName: "scifi" },
{ name: "Steampunk", styleName: "steampunk" },
{ name: "USVA", styleName: "usva" },
{ name: "Valentine", styleName: "valentine" },
],
},
{
groupName: "Unknown fonts",
fonts: [
{ name: "Unknown blue", styleName: "unknown_blue" },
{ name: "Unknown blue 2", styleName: "unknown_blue_2" },
{ name: "Unknown metal", styleName: "unknown_metal" },
{ name: "Unknown white", styleName: "unknown_white" },
{ name: "Unknown pillow", styleName: "unknown_pillow_1" },
{ name: "Unknown pillow", styleName: "unknown_pillow_2" },
{ name: "Relax", styleName: "relax" },
],
},
];
export function buildFontUrl(styleName: string, text: string): string {
const t = text.toLowerCase().replace(/\s/g, "+");
return `/api/font/${styleName}/${t}`;
}
+11 -2
View File
@@ -4,7 +4,7 @@ import { useCallback, useEffect, useMemo, useRef, useState, useTransition } from
import { ContentCard } from "@/components/public/ui";
import { saveLogo } from "@/actions/save-logo";
import { HABBO_FONT_GROUPS } from "@/components/public/habbo-fonts";
import { getFontInfo, measureText, renderToCanvas } from "@/components/public/sprite-font";
import { getFontInfo, getMissingChars, renderToCanvas } from "@/components/public/sprite-font";
export default function LogoGenerator() {
const [text, setText] = useState("Atom");
@@ -13,6 +13,7 @@ export default function LogoGenerator() {
const [saveStatus, setSaveStatus] = useState<"idle" | "saving" | "done" | "error">("idle");
const [fontLoaded, setFontLoaded] = useState(false);
const [fontError, setFontError] = useState(false);
const [missingChars, setMissingChars] = useState<Set<string>>(new Set());
const [, startTransition] = useTransition();
const canvasRef = useRef<HTMLCanvasElement>(null);
@@ -54,6 +55,7 @@ export default function LogoGenerator() {
const ctx = canvasRef.current.getContext("2d");
ctx?.drawImage(canvas, 0, 0);
}
setMissingChars(getMissingChars(info.chars, safeText));
setFontLoaded(true);
})
.catch(() => {
@@ -224,7 +226,14 @@ export default function LogoGenerator() {
{fontError ? (
<p className="muted">Failed to load font sprite.</p>
) : fontLoaded ? (
<canvas ref={canvasRef} style={{ maxWidth: "100%", height: "auto" }} />
<>
<canvas ref={canvasRef} style={{ maxWidth: "100%", height: "auto" }} />
{missingChars.size > 0 && (
<p className="muted" style={{ marginTop: 8, fontSize: "0.8rem" }}>
Note: this font does not have characters: {[...missingChars].join(", ")}
</p>
)}
</>
) : (
<p className="muted">Loading font…</p>
)}
+13 -4
View File
@@ -98,12 +98,23 @@ export function measureText(chars: CharInfo[], text: string, avgW: number): { to
totalW += avgW;
} else {
const info = map.get(ch);
totalW += info?.w ?? avgW;
totalW += info?.w ?? 0;
}
}
return { totalW };
}
export function getMissingChars(chars: CharInfo[], text: string): Set<string> {
const available = new Set(chars.map((c) => c.char));
const missing = new Set<string>();
for (const ch of text.toLowerCase()) {
if (ch !== " " && !available.has(ch)) {
missing.add(ch);
}
}
return missing;
}
export function renderToCanvas(
chars: CharInfo[],
h: number,
@@ -118,7 +129,7 @@ export function renderToCanvas(
let totalW = 0;
for (const ch of safeText) {
totalW += ch === " " ? avgW : (map.get(ch)?.w ?? avgW);
totalW += ch === " " ? avgW : (map.get(ch)?.w ?? 0);
}
if (totalW === 0) return null;
@@ -139,8 +150,6 @@ export function renderToCanvas(
if (info) {
ctx.drawImage(sheet, info.x, top, info.w, h, x, 0, info.w, h);
x += info.w;
} else {
x += avgW;
}
}
}