Development¶
This page covers building Xenia Manager from source and navigating the codebase. For full coding standards, naming conventions, theme authoring, and translation steps, see the canonical docs in the main repository: docs/CONTRIBUTING.md and docs/TRANSLATIONS.md.
Prerequisites¶
- .NET 10 SDK (SDK, not just the Desktop Runtime - you need
dotnet build/test). - Python 3.x (for
scripts/lint.pyand translation tooling). - Git. Clone the main repo (not this wiki):
Building and Testing¶
From the repository root (where Xenia Manager.sln lives):
- Solution:
Xenia Manager.sln(version is stamped via rootDirectory.Build.props). - CI produces release ZIPs automatically; experimental builds are tracked on a separate board/channel from stable (see Manager Settings).
- Tests live in
tests/next tosource/, one area per project where applicable.
Project Structure¶
The solution follows a multi-project layout under source/. Business logic lives in the libraries so both UI surfaces (desktop + BigScreen) share it:
| Project | Role |
|---|---|
XeniaManager |
Main desktop app: Views, ViewModels, UI services (Avalonia + FluentAvalonia). Pages: Library, Manage, XeniaSettings, Settings, About. Keep code-behind minimal; logic goes in ViewModels/core |
XeniaManager.BigScreen |
Fullscreen TV launcher sharing the core libraries (see BigScreen) |
XeniaManager.Core |
Business logic: Manage/ (Game, Config, Patch, Content, Profile, Save, Shortcut, Artwork, Launcher managers), Models/, Settings/, Installation/, Utilities/ |
XeniaManager.Database |
Online database clients + models: Xbox marketplace (x360db), compatibility (Canary/Mousehook/Netplay), patches (Canary/Netplay), optimized settings |
XeniaManager.Files |
File-format parsers + models for Xbox/Xenia types (ISO, XEX, STFS, SVOD, GPD, ZAR, etc.) |
XeniaManager.Logging |
NLog-based logging infrastructure (Logger class with Trace → Fatal levels) |
Key runtime files (next to the built exe): Config/config.json + games.json, Emulators/<Variant>/, Cache/Database/ + Cache/Images/, Logs/, Backup/, Downloads/. Constants live in XeniaManager.Core/Constants/ (AppPaths.cs, XeniaPaths.cs, Urls.cs).
Coding Standards (Summary)¶
Full rules are in CONTRIBUTING.md (and encoded in root .editorconfig, enforced by python scripts/lint.py with ReSharper cleanupcode):
- MVVM with CommunityToolkit.Mvvm (
[ObservableProperty],On<Property>Changedpartials). Views stay lightweight. - Naming:
PascalCasemethods/properties;_camelCaseprivate fields;camelCaselocals; Hungarian prefixes for AXAML elements (Cmb,Txt,Btn,Tbl,Sp,Grd,Sv,Exp) with the prescribed attribute order. - Formatting: 4 spaces, braces on new lines, file-scoped namespaces, explicit types (no
var, no target-typednew()), lines under 160 chars, alphabetizedusings (system first). - Docs: XML doc comments on public/internal types and members; sparse inline comments.
- Logging:
try/catch+Logger.Error<T>/Logger.LogExceptionDetails<T>; never swallow exceptions silently.
Lint¶
python scripts/lint.py # format everything
python scripts/lint.py --check # verify only (what CI runs)
python scripts/lint.py --include "source/XeniaManager.Core/**/*.cs" # scoped (repeatable)
python scripts/lint.py --changed # staged + unstaged + untracked
python scripts/lint.py --staged # staged only
Commits and PRs¶
- Branches:
feature/...,bugfix/...,refactor/...,docs/.... - Commits: conventional prefix style, e.g.
[Feature] Add game details editor dialog,[Bugfix] Fix crash on corrupted library file. Keep commits atomic. - PRs target the
devbranch with what/why/testing described, related issues linked, and screenshots for UI changes.
Translations¶
Summary of TRANSLATIONS.md (read the full file before starting):
- Fork + branch
translation/<code>(codes are .NET culture codes, e.g.es,fr,de). - Copy
source/XeniaManager/Resources/Language/en.axaml→<code>.axaml. - Translate only the text between
<sys:String>tags. Keep everyx:Key, every placeholder ({0},{1}), and escapes like intact. - Optionally build locally and preview (do not commit changes to the
SupportedLanguagesarray - maintainers wire that at release). - Commit (
Add <Language> translation (<code>)), push, open a PR with language + proficiency notes.
Progress is tracked by the translation chart tooling (scripts/generate_translation_progress.py, check_localization.py, sync_localization.py).
Themes¶
Summary of the CONTRIBUTING.md theme section:
- Copy
source/XeniaManager/Resources/Themes/Template.axaml→MyCustomTheme.axaml. - Recolor values, keeping all
x:Keynames unchanged (dark themes: dark backgrounds + light text; light themes: inverse; keep WCAG AA contrast; pick accents that work on both). - Register in
source/XeniaManager.Core/Models/Theme.cs(enum) and the theme dictionary inThemeService.cs(ResourcePath,BaseTheme, optionalFallbackTheme). - Build, load every control type, and verify.
Built-in themes are System, Light, Dark, Amoled, Steam (see Theme.cs - the source of truth if the guide ever disagrees).
This Wiki (Docs Tooling)¶
This wiki lives in a separate repo (xenia-manager/wiki) and is built with Zensical from Markdown in docs/, deployed to GitHub Pages (gh-pages branch). Navigation is declared in zensical.toml (nav = [...]).
Preview locally with uv¶
The project uses uv for the docs virtualenv (mirroring the DualSenseClient docs setup):
git clone https://github.com/xenia-manager/wiki.git
cd wiki
uv venv
uv pip install -r requirements.txt # installs `zensical`
uv run zensical serve # preview at http://127.0.0.1:8000
Build¶
Output goes to site/ (git-ignored). --strict fails on warnings - fix broken links and missing pages before pushing.
Contributing to docs¶
- Edit Markdown under
docs/; add new pages to thenavarray inzensical.toml. - Screenshots live in
docs/assets/split by surface:desktop/for the desktop app,bigscreen/for BigScreen. Use BigScreen naming style (Pascal_Case_With_Underscores.png, e.g.Manage_Profiles.png). Reference them asassets/desktop/<Name>.pngorassets/bigscreen/<Name>.pngfromindex.md, or with a../prefix from any subfolder page. - Screenshot placeholders use this convention (greppable, renders as an info box):
- Run the strict build locally, then open a PR against
main-gh-pagesupdates automatically on merge.