Skip to content

feat: support custom fonts in system settings#729

Open
ericreinsmidt wants to merge 4 commits into
LoveRetro:mainfrom
ericreinsmidt:feat/dynamic-custom-fonts
Open

feat: support custom fonts in system settings#729
ericreinsmidt wants to merge 4 commits into
LoveRetro:mainfrom
ericreinsmidt:feat/dynamic-custom-fonts

Conversation

@ericreinsmidt
Copy link
Copy Markdown

@ericreinsmidt ericreinsmidt commented May 19, 2026

Summary

  • Users can drop .ttf/.otf files into .system/res/ and they appear in the Settings font picker
  • Built-in fonts ("Next" and "OG") remain available as always
  • Built-in fonts write integer values to minuisettings.txt (font=0 for OG, font=1 for Next) for backward compatibility with existing paks
  • Custom fonts write the filename (e.g. font=MyFont.ttf)
  • nextval font always returns an integer (default 1 for custom fonts); paks should use nextval fontpath for the full path
  • Backward compatible with existing font=0/font=1 integer values on read
  • Falls back to default font if a selected custom font file is removed

Note: All binaries linking config.c (nextui, minarch, nextval, settings, clock, etc.) must be rebuilt — the settings struct changed from integer to string for the font field internally.

Pak compatibility

Audited all 87 pak store repos + 3 related projects. Only 2 read the font= setting (Apostrophe library and NextUI Updater), both parsing it as an integer. Built-in font selections remain fully compatible. Custom font selections gracefully degrade — Apostrophe-based paks fall back to the default font until updated.

Test plan

  • Verify built-in fonts ("Next", "OG") still work and persist across reboots
  • Drop a .ttf into .system/res/, open Settings — font appears in picker
  • Select custom font, reboot — selection persists
  • Select custom font, launch and quit a game — selection persists
  • Remove the custom font file, reboot — falls back to default "Next"
  • Existing installs with font=0 or font=1 in settings file still work
  • Aesthetics pak works with custom font selected
  • Clock pak does not overwrite custom font selection

Copy link
Copy Markdown
Member

@frysee frysee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, but I'd rather avoid the breaking change for paks.

Comment thread workspace/all/common/config.c Outdated
{
printf("{\n");
printf("\t\"font\": %i,\n", settings.font);
printf("\t\"font\": \"%s\",\n", settings.fontFile);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid breaking paks here? Just return the default (font=1) for this if a custom font is selected, even though it is potentially wrong. Pak developers have an upgrade path via fontpath, which is the more portable way anyway (it has the whole path). We can then later deprecate this one in favour of fontpath

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, that's the smart call. I went through all of the paks on the pak store. The biggest things affected are the OTA updater and Helaas's Apostrophe lib. Overall the standard fonts would have worked, but not intentionally, so fragile.

Here's a summary:

Audited all 87 pak store repos + 3 related projects (Apostrophe, Csthetics, NextUI Theme Manager) for any code that reads the font= setting from minuisettings.txt.

Findings:

84 paks have zero interaction with the font setting
2 projects read font=:
Apostrophe library (used by 20+ paks) — parses as integer via ap__read_nextui_setting_int("font", 1), constructs font%d.ttf
NextUI Updater — uses settings.contains("font=1") substring match
0 paks call nextval font or nextval fontpath
Fix: Built-in fonts now write integer values (font=0 for OG, font=1 for Next) to minuisettings.txt, preserving the original format. Custom fonts write the filename string. This applies to CFG_sync, CFG_get, and CFG_print — so both the settings file and nextval output maintain backward compat.

Existing paks continue working unchanged. Apostrophe-based paks with a custom font selected will gracefully fall back to font1.ttf (the default) until Apostrophe is updated to handle filename strings.

@ericreinsmidt ericreinsmidt requested a review from frysee May 19, 2026 22:50
else if (strcmp(settings.fontFile, "font2.ttf") == 0)
fprintf(file, "font=0\n");
else
fprintf(file, "font=%s\n", settings.fontFile);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Else branch still breaks backwards compatibility.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, nextval font now always returns an integer.

Comment thread workspace/all/common/config.c Outdated
else if (strcmp(settings.fontFile, "font2.ttf") == 0)
printf("\t\"font\": \"0\",\n");
else
printf("\t\"font\": \"%s\",\n", settings.fontFile);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, nextval font now always returns an integer.

Comment thread workspace/all/common/defines.h Outdated
#define ROOT_SYSTEM_PATH SDCARD_PATH "/.system/"
#define SYSTEM_PATH SDCARD_PATH "/.system/" PLATFORM
#define RES_PATH SDCARD_PATH "/.system/res"
#define FONTS_PATH RES_PATH "/fonts"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whats the benefit of the subfolder? It just means having fonts in to separate locations, making the whole theming more confusing. I'd agree if we wouldnt have any fonts yet, but thats not the case here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was to have a convenient place for users to drop fonts and find them easily to remove if they wanted. If they are dropping files in there they likely already understand where to find them later though, so I'll adjust to have them in /res with the shipped fonts.

Users can drop .ttf/.otf files into .system/res/fonts/ and they
appear as options in the Settings font picker alongside the built-in
"Next" and "OG" fonts. Font selection is stored by filename in
minuisettings.txt with backward compatibility for existing font=0/1
integer values. Falls back to the default font if a custom font file
is removed.
Write integer values (font=0, font=1) for built-in fonts so existing
paks that parse the setting as an integer keep working. Custom fonts
write the filename string. Affects CFG_sync, CFG_get, and CFG_print.
- nextval font always returns integer (0 or 1), never filename
- CFG_print outputs font as integer to fix gabagool JSON parsing
- Move custom fonts to .system/res/ alongside built-ins (no subfolder)
- Remove FONTS_PATH define, all fonts use RES_PATH
- Filter BPreplay system fonts from settings font picker
- Move licenses dir to .system/res/licenses/
Users supply their own fonts; licensing is their responsibility.
@ericreinsmidt ericreinsmidt force-pushed the feat/dynamic-custom-fonts branch from ab5e05c to 6adbe9c Compare May 20, 2026 19:14
@ericreinsmidt ericreinsmidt requested a review from frysee May 20, 2026 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants