Lay the theme-relative foundation: tokens, control themes, icons, system font - #14
Merged
chrisuthe merged 6 commits intoSep 1, 2026
Conversation
…colour reports Plasma serves its highlight colour as the accent, which in a light scheme is a light derivative of the user's pick; GNOME and Windows serve the saturated pick. Fluent's text-on-accent brush is white for both. The contrast helper decides from WCAG relative luminance with a threshold set between the measured saturated picks (Windows blue at 0.18, GNOME blue at 0.23) and the measured light highlights (0.37 and up), so neither kind of desktop gets an unreadable glyph. The filter is for Windows, where one accent change raised about twenty ColorValuesChanged events in 600 ms and each variant flip raised two; everything hung off that event goes through one filter so the work happens once per real change.
$Default is fontconfig's answer to an empty pattern, which inside the Flatpak is DejaVu Sans rather than the desktop's font. The portal's org.gnome.desktop.interface/font-name is the real setting, the KDE backend serves it as well as the GNOME one, and it is reachable from the sandbox without a permission. Read once, synchronously and bounded, before the app builder runs, because FontManagerOptions is fixed there. The Pango description is reduced to a family name first: fontconfig turns a family it does not know back into its default, so a trailing size or style word would undo the whole point.
…tem font Phase 1 of the reskin: everything visual expressed once as resources, so later phases only lay controls out. The shell belongs to the OS — native decorations, the system light/dark variant and accent followed live, the platform's UI font — and the content area belongs to the music; its composition will come from Sendspin for Windows, its colours will not. - Tokens.axaml: the few brushes Fluent lacks (veil, translucent surface, art placeholder, glow default, on-accent), each derived from a Fluent colour by DynamicResource so nothing here is a literal. Fluent in Avalonia 12.1.1 carries the SystemControl* resource set only; the caution brush the old warning class named did not exist, so it now uses Fluent's error-text brush. - PlayerStyles.axaml: a PathIcon theme that strokes its geometry at 1.7 units on a 24 box, iconButton / playButton / primary, and one text scale with the old classes as aliases on the same selectors. - Icons.axaml: the stroke set, lifted from Sendspin for Windows and Feather (both MIT), replacing every emoji glyph in the views; play/pause is an icon choice on IsPlaying. - OnAccentBrush is recomputed from the accent's luminance behind one deduplicated subscription to the platform's colour-changed event. - The UI font is the platform's: Fluent's font resource is overridden to $Default, the Linux head names the desktop font from the Settings portal, Inter stays as the glyph fallback and the app logs what it resolved. Windows measured Segoe UI and stays unset; macOS measured Helvetica, and the SF override is a follow-up once the resolvable name is known. - Icons: the green disc from the reference app at 256 px, for the app, the tray, the AppImage and the Flatpak. - Tests pin the tokens under both variants, the icon box, the no-colour-literal and no-glyph-character rules, and the on-accent brush.
…' font too A best-effort read at start-up, before a logger exists, must not be able to stop the app starting; the earlier list of exception types was a guess at what the bus can throw. The font log line now also resolves ContentControlThemeFontFamily, which is the resource controls actually draw with, rather than only $Default.
chrisuthe
marked this pull request as ready for review
September 1, 2026 22:18
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 1 of the UI reskin: everything visual expressed once as resources, so the later phases only lay controls out. The shell belongs to the OS — native decorations, the system light/dark variant and accent followed live, the platform's UI font — and the content area belongs to the music. The layout inside the window will come from Sendspin for Windows; the colours do not. No layout changes here.
What changed
Styles/Tokens.axaml):VeilBrush,TranslucentSurfaceBrush,ArtPlaceholderBrush,GlowDefaultBrushin Light and Dark dictionaries, plusOnAccentBrush. Every colour is a DynamicResource into Fluent, so nothing is a literal. Fluent in Avalonia 12.1.1 turned out to carry only theSystemControl*resource set; theSystemFillColorCautionBrushthe oldwarningclass named did not exist, so it now uses Fluent's error-text brush.Styles/PlayerStyles.axaml): aPathIcontheme that strokes at 1.7 units on a 24 box;iconButton,playButton,primary; one text scale with the old class names as aliases on the same selectors.Styles/Icons.axaml): shuffle, repeat and switch-group from Sendspin for Windows, the rest from Feather (both MIT, named in the header). Every emoji glyph in the views is gone; play/pause is an icon choice onIsPlaying, repeat shows repeat-one when the server says so.OnAccentBrushis black or white from the accent's WCAG luminance (Core/Theme/AccentContrast.cs), recomputed behind one deduplicated subscription to the platform's colour-changed event (SystemColorChangeFilter, for the ~20-event storm measured on Windows). The threshold is set between the saturated picks Windows and GNOME serve and the light highlights Plasma serves.$Default, Inter stays as glyph fallback. On Linux the desktop font comes from the Settings portal'sfont-namekey, which the KDE backend serves too — and it is reachable from the Flatpak, where fontconfig's own default is DejaVu Sans; measured in the runtime sandbox. Windows measured plain Segoe UI and stays unset; macOS measured Helvetica, and the SF override is a follow-up once the resolvable family name is known. The app now logs what it resolved at start-up.App.axaml,MainWindow.axamland the styles header state the principle; the "not copied" wording is gone.docs/ARCHITECTURE.mdrecords the font decision and the Windows and macOS measurements.Before / after
Both taken on the Wayland head under Plasma 6.7, switching live with
plasma-apply-colorscheme. Start-up log on this box:Checks
make testgreen in Debug and Release (258 + 22).dotnet format --verify-no-changesclean on every project touched. One whitespace-only commit re-indents the MPRISGetAllblock thatdotnet formatalready objected to on master.Left for later phases
DefaultFamilyNamefor SF, once the resolvable name is measured.