# ES-DE Frontend (development version) - Themes **Note:** This document is only relevant for the current ES-DE development version, if you would like to see the documentation for the latest stable release, refer to [THEMES.md](THEMES.md) instead. If creating themes for ES-DE, please add `-es-de` to the repository/directory name to clearly indicate that it's a theme for this frontend. Two examples would be `linear-es-de` and `modern-es-de`. The actual theme name as defined using the `themeName` tag in capabilities.xml does of course not need to include the `-es-de` extension as that's the actual theme name that will be displayed when selecting themes from the _UI Settings_ menu. For example linear-es-de will be listed simply as _Linear_ in this menu. Before your start, make sure to download the _Theme engine examples_ theme that contains a number of example variants for things like vertical and horizontal carousels, wheel carousels, system view text lists, grids etc: https://gitlab.com/es-de/themes/theme-engine-examples-es-de More themes to use as a starting point can be found on the official themes list: https://gitlab.com/es-de/themes/themes-list There is also some documentation written by lilbud covering general tips and tricks as well as how to port themes from the legacy RetroPie theme engine to ES-DE: https://github.com/lilbud/es-de-theme-stuff To test whether your theme includes support for all ES-DE systems, download one of the following archives which contain ROM directory trees fully populated with dummy files: [ROMs_ALL_Linux.zip](tools/system-dirs-dummy-files/ROMs_ALL_Linux.zip)\ [ROMs_ALL_macOS.zip](tools/system-dirs-dummy-files/ROMs_ALL_macOS.zip)\ [ROMs_ALL_Windows.zip](tools/system-dirs-dummy-files/ROMs_ALL_Windows.zip) If you unzip and temporarily replace your ROMs directory with one of these, every system will be enabled on startup. Just make sure to use 7-Zip if you are using Windows as there is a bug in the built-in compression utility which leads to extensionless files not getting unpacked. It's recommended to use a proper code editor for theme development, such as [VSCode](https://code.visualstudio.com) with the [Red Hat XML extension](https://github.com/redhat-developer/vscode-xml). A general comment regarding SVG graphic files is that fonts are not supported by the LunaSVG library so these need to be converted to paths in order for them to get rendered inside ES-DE. In Inkscape the relevant command is named _Object to Path_ but there should be equivalent functionality in other vector graphics editors. Embedded bitmaps are also not supported but this is generally a good thing as it's sometimes abused by simply embedding a raster image inside an SVG file, which is very misleading. Another general remark is that Linux almost always uses case-sensitive file systems (that's sometimes true for macOS as well). Therefore it's a good idea to always name files with lowercase characters only. Also make sure to regularly test on Linux if that's not your primary operating system. Table of contents: [[_TOC_]] ## Introduction An ES-DE theme is a collection of assets like images, videos and fonts as well as XML configuration files which contain various **elements**, each with their own **properties** that define the way the theme looks and behaves. These elements include things like text, images, videos, animations, carousels, grids etc. Internally ES-DE uses the concept of **components** to actually implement the necessary building blocks to parse and render the elements, and although this is normally beyond the scope of what a theme author needs to consider, it's still good to be aware of the term as it's sometimes used in the documentation. Every game system may have its own subdirectory within the theme directory tree, and these directory names are defined in the systems configuration file `es_systems.xml` either via the optional `` tag, or otherwise via the mandatory `` tag. When ES-DE populates a system on startup it will look for a file named `theme.xml` in each such directory. By placing a theme.xml file directly in the root of the theme directory, that file will be processed as a default if there is no system-specific theme.xml file available. This means that the structure of having a separate directory per supported game system is entirely optional. In the example below, we have a theme named `mytheme-es-de` which includes the `snes` and `nes` systems. Assuming you have some games installed for these systems, the files `mytheme-es-de/nes/theme.xml` and `mytheme-es-de/snes/theme.xml` will be processed on startup. If there are no games available for a system, its theme.xml file will be skipped. The directory structure for our example theme could look something like the following: ``` ... themes/ mytheme-es-de/ core/ font.ttf font_bold.ttf frame.png nes/ background.jpg logo.svg theme.xml snes/ background.jpg logo.svg theme.xml fonts.xml theme.xml ``` An alternative approach would be to instead rely on variables for populating system-specific information and media files, and this way it's not necessary to setup separate directories per system: ``` ... themes/ mytheme-es-de/ core/ font.ttf font_bold.ttf frame.png systems/ backgrounds/ nes.jpg snes.jpg logos/ nes.svg snes.svg metadata/ nes.xml snes.xml fonts.xml theme.xml ``` The ES-DE theme functionality makes it easy for users to install different themes and to choose between them from the _UI Settings_ menu. There are two places that ES-DE can load themes from: * `[HOME]/ES-DE/themes/` * `[INSTALLATION PATH]/themes/` An installation path could be something like this: ``` /usr/share/emulationstation/themes/slate-es-de/ /Applications/EmulationStation Desktop Edition.app/Contents/Resources/themes/ C:\Program Files\EmulationStation-DE\themes\ ``` If a theme with the same name exists in both locations, the one in the home directory will be loaded and the other one will be skipped. ## Differences to legacy RetroPie themes If you are not familiar with theming for RetroPie or similar forks of EmulationStation then you can skip this section as it only describes the key differences between the updated ES-DE themes and these legacy themes. The term _legacy_ is used throughout this document to refer to this older style of themes. ES-DE as of 2.2.0 can no longer load legacy themes, so if you need to view them when porting them to ES-DE, either use a legacy EmulationStation fork or ES-DE 2.1.1. With ES-DE 2.0.0 a new theme engine was introduced that fundamentally changed some aspects of how theming works. The previous design used specific view styles (basic, detailed, video and grid) and this was dropped completely and replaced with _variants_ that can accomplish the same thing while being much more powerful and flexible. In the past EmulationStation basically had hardcoded view styles with certain elements always being present and only a limited ability to manipulate these via positioning, resizing, coloring etc. As well so-called _extras_ were provided to expand theming support somehow but even this was quite limited. With the new theme engine the view presets were removed and the only views now available, _system_ and _gamelist_, were rewritten to be much more flexible. Essentially the element selection and placement is now unlimited; any number of elements of any type can be used, although with a few notable exceptions as explained throughout this document. In addition to _variants_, support for _color schemes_ and _aspect ratios_ was introduced. The former makes it possible to provide different color profiles via variable declarations, and the latter makes it possible to define different theme configurations for different display aspect ratios. That could for example be a choice between a 16:9 and a 4:3 layout, and perhaps also a vertical screen orientation layout. All these options are selectable via the _UI Settings_ menu. New theming abilities like GIF and Lottie animations were also added to the new theme engine. The NanoSVG rendering library has been replaced with [LunaSVG](https://github.com/sammycage/lunasvg) which greatly improves SVG file support as NanoSVG had issues with rendering quite some files. There might be some slight regressions with LunaSVG, but most of these are probably due to issues in NanoSVG that caused some non-conformant files to render seemingly correct. Make sure to compare any SVG files that don't seem to render correctly in ES-DE with what they look like if opened in for example Firefox or Chrome/Chromium. As for more specific changes, the following are the most important ones compared to legacy themes: * View styles are now limited to only _system_ and _gamelist_ (there is a special _all_ view style as well but that is only used for navigation sounds as explained later in this document) * The hardcoded metadata attributes like _md_image_ and _md_developer_ are gone, but a new `` property is available for populating views with metadata information * The concept of _extras_ is gone as all element can now be used however the theme author wishes * The concept of _features_ is gone * The `` tag is gone as tracking theme versions doesn't make much sense after all * The `video` element properties `showSnapshotNoVideo` and `showSnapshotDelay` have been removed * The ambiguous `alignment` property has been replaced with the `horizontalAlignment` and `verticalAlignment` properties (the same is true for `logoAlignment` for the `carousel` element) * The `forceUppercase` property has been replaced with the more versatile `letterCase` property * Many property names for the carousel have been renamed, with _logo_ being replaced by _item_ as this element can now be used in both the gamelist and system views. As well, setting the alignment will not automatically add any margins as is the case for legacy themes. These can still be set manually using the `horizontalOffset` and `verticalOffset` properties if needed. The way that alignment works in general for both carousel items and the overall carousel has also changed * The rating elements were previously not sized and overlaid consistently, this has now been fixed and rating images should now be centered on the image canvas in order for this element to render correctly rather than being left-adjusted as has previously been done by some theme authors (likely as a workaround for the previous buggy implementation). Images of any aspect ratios are now also supported where previously only square images could be used * The carousel text element hacks `systemInfo` and `logoText` have been removed and replaced with proper carousel properties * The carousel property `maxItemCount` (formerly named maxLogoCount) is now in float format for more granular control of logo placement compared to integer format for legacy themes. However some legacy theme authors thought this property supported floats (as the theme documentation incorrectly stated this) and have therefore set it to fractional values such as 3.5. This was actually rounded up when loading the theme configuration, and this logic is retained for legacy themes for backward compatibility. But for current themes the float value is correctly interpreted which means a manual rounding of the value is required in order to retain an identical layout when porting themes to the new theme engine. As well carousels of the wheel type now have the amount of entries controlled by the two new properties `itemsBeforeCenter` and `itemsAfterCenter`. This provides more exact control, including the ability to setup asymmetric wheels. * The full names of unthemed systems (or systems where the defined staticImage file is missing) will now be displayed in the system carousel instead of the short names shown for legacy themes. So for instance, instead of "cps" the full name "Capcom Play System" (as defined in es_systems.xml) will be displayed. * The carousel now has a zIndex value of 50 instead of 40. This means it's aligned with the textlist element which already had a zIndex value of 50. * The textlist property `selectorOffsetY` has been renamed to `selectorVerticalOffset` and a `selectorHorizontalOffset` property has been added as well. * The helpsystem `textColorDimmed` and `iconColorDimmed` properties (which apply when opening a menu) were always defined under the system view configuration which meant these properties could not be separately set for the gamelist views. Now these properties work as expected with the possibility to configure separate values for the system and gamelist views * When right-aligning the helpsystem using an X origin value of 1, the element is now aligned correctly to the defined position instead of being offset by the entrySpacing width (in RetroPie ES the offset was instead the hardcoded element entry padding) * Correct theme structure is enforced more strictly than before, and deviations will generate error log messages and make the theme loading fail * Many additional elements and properties have been added, refer to the [Reference](THEMES-DEV.md#reference) section for more information Attempting to use any of the legacy logic in the new theme structure will make the theme loading fail, for example adding the _extra="true"_ attribute to any element. Except the points mentioned above, theme configuration looks pretty similar to the legacy theme structure, so anyone having experience with these older themes should hopefully feel quite at home with the new theme engine. Probably the most important thing to keep in mind is that as there are no longer any view presets available, some more effort is needed from the theme developer to define values for some elements. This is especially true for zIndex values as elements could now be hidden by other elements if care is not taken to explicitly set the zIndex for each of them. This additional work is however a small price to pay for the much more powerful and flexible theming functionality provided by the new theme engine. Note that the legacy theme engine had quite inaccurate text sizing and font rendering and while this has been greatly improved in the new engine, for legacy themes most old bugs are retained for maximum backward compatibility. This means that you may need to revise font sizes and text placements when porting a legacy theme to the new engine. Here are some examples: * Line spacing for the textlist element was not consistently applied across different screen resolutions * Carousel text entries did not multiply the font size by the itemScale (logoScale) property value * The defined line spacing was not always applied for automatically sized text elements * Font sizes were rounded to integers, leading to imprecise text sizing across different resolutions (the rounding was also done incorrectly) ## Theme assets repositories There are several useful repositories hosted by the ES-DE project that provide system metadata and system graphics files. Using these greatly simplifies the work of adding support for all ES-DE systems to your theme. Make sure to regularly check for updates in these repositories as corrections, improvements and additions of new systems are made continuously. ### Metadata The metadata repository provides descriptions, release dates, per-system color palettes etc. and it can be found here: https://gitlab.com/es-de/themes/system-metadata By adding this to your theme, either via manually downloading and including it, or by adding it as a Git subtree, you'll be able to access its defined variables. Check the README.md file in the repository for details on how to actually use the variables. Here's how to add this repository as a subtree inside your theme's Git repository: ``` git remote add system-metadata https://gitlab.com/es-de/themes/system-metadata.git git subtree add --prefix=system-metadata --squash system-metadata master ``` To later pull in repository updates you'll run the following: ``` git subtree pull --prefix=system-metadata --squash system-metadata master ``` The directory name can be changed to whatever you like using the --prefix flag. ### Controller outline graphics This repository provides controller graphics files for each system in an outline style and it can be found here: https://gitlab.com/es-de/themes/system-controllers-outline Here's how to add this repository as a subtree inside your theme's Git repository: ``` git remote add system-controllers-outline https://gitlab.com/es-de/themes/system-controllers-outline.git git subtree add --prefix=system-controllers-outline --squash system-controllers-outline master ``` To later pull in repository updates you'll run the following: ``` git subtree pull --prefix=system-controllers-outline --squash system-controllers-outline master ``` The directory name can be changed to whatever you like using the --prefix flag. ### Mini system graphics This repository provides graphics files for each system in a "mini" style and it can be found here: https://gitlab.com/es-de/themes/system-graphics-mini Here's how to add this repository as a subtree inside your theme's Git repository: ``` git remote add system-graphics-mini https://gitlab.com/es-de/themes/system-graphics-mini.git git subtree add --prefix=system-graphics-mini --squash system-graphics-mini master ``` To later pull in repository updates you'll run the following: ``` git subtree pull --prefix=system-graphics-mini --squash system-graphics-mini master ``` The directory name can be changed to whatever you like using the --prefix flag. ### Logos This repository provides logos for each system in color and white (the latter for use with color shifting) and it can be found here: https://gitlab.com/es-de/themes/system-logos Here's how to add this repository as a subtree inside your theme's Git repository: ``` git remote add system-logos https://gitlab.com/es-de/themes/system-logos.git git subtree add --prefix=system-logos --squash system-logos master ``` To later pull in repository updates you'll run the following: ``` git subtree pull --prefix=system-logos --squash system-logos master ``` The directory name can be changed to whatever you like using the --prefix flag. ### Adding remotes Note that the remotes are only setup for your local repository, so if you clone a theme you'll need to manually add the repository remotes to be able to pull from these subtrees. That means you'll need to run one or more of the following commands on a freshly cloned theme repository: ``` git remote add system-metadata https://gitlab.com/es-de/themes/system-metadata.git git remote add system-controllers-outline https://gitlab.com/es-de/themes/system-controllers-outline.git git remote add system-graphics-mini https://gitlab.com/es-de/themes/system-graphics-mini.git git remote add system-logos https://gitlab.com/es-de/themes/system-logos.git ``` After doing this you'll be able to pull repository updates as described above. ## Simple example theme Here is a very simple theme that changes the color of the game name text: ```xml 00FF00 0.5 0.5 0.5 0.5 0.8 0.8 ./core/frame.png 10 ``` ## How it works All configuration must be contained within a `` tag pair. That is true for each separate .xml file used to build the completely theme. The `` tag pair refers to the available views within ES-DE, which is either _system_ or _gamelist_. There is a special _all_ view available as well, but that is only used for defining the navigation sounds as these are always applied globally to both view types. Views are defined like this: ```xml ... define elements here ... ``` An element is a particular visual component such as an image, an animation or a piece of text. It has a mandatory _name_ attribute which is used by ES-DE to track each element entry. By using this name attribute it's possible to split up the definition of an element to different locations. For example you may want to define the color properties separately from where the size and position are configured (see the example below). The name attribute can be set to any string value. This is the element structure: ```xml ... define properties here ... ``` Finally _properties_ control how a particular element looks and behaves, for example its position, size, image path, animation controls etc. The property type determines what kinds of values you can use. You can read about each type below in the [Reference](THEMES-DEV.md#reference) section. Properties are defined like this: ```xml valueHere ``` Let's now put it all together. The following is a simple example of a text element which has its definition split across two separate XML files. `themes.xml`: ```xml 0.27 0.32 0.5 0.5 0.12 0.41 40 ``` `colors.xml`: ```xml 707070 ``` As long as the name attribute is identical, the element configuration will be combined automatically. But that is only true for elements of the same type, so for instance an image element could be defined that also uses _systemName_ for its name attribute without colliding with the text element: ```xml 0.27 0.32 0.5 0.5 0.12 0.41 40 0.49 0.8 0.4 0.28 35 ``` Whether this is a good idea is another question, it would probably be better to set the name attribute for the image to _systemLogo_ or similar for this example. In addition to this, if the name is used for the same element type but for different views, then there will also not be any collision: ```xml 0.04 0.73 0.5 0.5 0.12 0.22 40 0.27 0.32 0.5 0.5 0.12 0.41 40 ``` ## Debugging during theme development If you are writing a theme it's recommended to enable the _Debug mode_ setting from the _Other settings_ menu or to launch ES-DE with the `--debug` flag from a terminal window. You can also pass the `--resolution` flag to avoid having the application window fill the entire screen. By doing so you can read error messages directly in the terminal window without having to open the es_log.txt file. With debug mode enabled you can also reload the current gamelist or system view with `Ctrl + r` and you can highlight the size and position of each image and animation element by using the `Ctrl + i` key combination. Likewise you can highlight each text element via `Ctrl + t`. Here's an example of launching ES-DE in debug mode at a limited resolution, which will make it run in a window: ``` emulationstation --debug --resolution 1280 720 ``` Enforcement of a correct theme configuration is quite strict, and most errors will abort the theme loading, leading to an unthemed system. In each such situation the log output will be very clear of what happened, for instance: ``` Jan 28 17:17:30 Error: ThemeData::parseElement(): "/home/myusername/ES-DE/themes/mytheme-es-de/theme.xml": Property "origin" for element "image" has no value defined (system "collections", theme "custom-collections") ``` Note that an unthemed system means precisely that, the specific system where the error occured will be unthemed but not necessarily the entire theme. The latter can still happen if the error is global such as a missing variable used by all XML files or an error in a file included by all XML files. The approach is to only untheme relevant sections of the theme to be able to pinpoint precisely where the problem lies. Sanitization for valid data format and structure is done in this manner, but verification that property values are actually correct (or reasonable) is handled by the individual component that takes care of creating and rendering the specific theme element. What happens in many instances is that a warning log entry is created and the invalid property is reset to its default value. So for these situations, the system will not become unthemed. Here's an example where a badges element accidentally had its horizontalAlignment property set to _leftr_ instead of _left_: ``` Jan 28 17:25:27 Warn: BadgeComponent: Invalid theme configuration, property "horizontalAlignment" for element "gamelistBadges" defined as "leftr" ``` Note however that warnings are not printed for all invalid properties as that would lead to an excessive amount of logging code. This is especially true for numeric values which are commonly just clamped to the allowable range without notifying the theme author. So make sure to check the [Reference](THEMES-DEV.md#reference) section of this document for valid values for each property. For more serious issues where it does not make sense to assign a default value or auto-adjust the configuration, an error log entry is generated and the element will in most instances not get rendered at all. Here's such an example where the imageType property for a video element was accidentally set to _covr_ instead of _cover_: ``` Jan 28 17:29:11 Error: VideoComponent: Invalid theme configuration, property "imageType" for element "gamelistVideo" defined as "covr" ``` Error handling for missing files is handled a bit differently depending on whether the paths have been defined explicitly or via a variable. For explicitly defined paths a warning will be logged for element properties and an error will be triggered for include files. Here's an example of the latter case: ``` Jan 28 17:32:29 Error: ThemeData::parseIncludes(): "/home/myusername/ES-DE/themes/mytheme-es-de/theme.xml" -> "./colors_dark.xml" not found (resolved to "/home/myusername/ES-DE/themes/mytheme-es-de/colors_dark.xml") ``` However, if a variable has been used to define the include file, only a debug message will be generated if the file is not found: ``` Jan 28 17:34:03 Debug: ThemeData::parseIncludes(): "/home/myusername/ES-DE/themes/mytheme-es-de/theme.xml": Couldn't find file "./${system.theme}/colors.xml" which resolves to "/home/myusername/ES-DE/themes/mytheme-es-de/amiga/colors.xml" ``` It works essentially the same way for element path properties as for include files. This distinction between explicit values and variables makes it possible to create a theme configuration where both include files and files for fonts, images, videos etc. will be used if found, and if not found a fallback configuration can still be applied so the system will be themed. By default all debug messages regarding missing files will be logged for regular systems and automatic collections and suppressed for custom collections. This behavior can be changed by modifying the _DebugSkipMissingThemeFiles_ and _DebugSkipMissingThemeFilesCustomCollections_ settings in es_settings.xml. You can read more about those settings [here](INSTALL-DEV.md#settings-not-configurable-via-the-gui). ## Variants A core concept of ES-DE is the use of theme _variants_ to provide different theme profiles. These are not fixed presets and a theme author can instead name and define whatever variants he wants for his theme (or possibly use no variants at all as they are optional). The variants could be purely cosmetic, such as providing different designs for a theme, or they could provide distinctive functionality by for instance using different primary elements like a carousel or a text list. Before a variant can be used it needs to be declared, which is done in the `capabilities.xml` file that must be located in the root of the theme directory tree. How to setup this file is described in detail later in this document. The use of variants is straightforward, a section of the configuration that should be included for a certain variant is enclosed inside the `` tag pair. This has to be placed inside the `` tag pair, and it can only be used at this level of the hierarchy and not inside a `` tag pair for example. The mandatory _name_ attribute is used to specificy which variants to use, and multiple variants can be specified at the same time by separating them by commas or by whitespace characters (tabs, spaces or line breaks). It's also possible to use the special _all_ variant that will apply the configuration to all defined variants (although this is only a convenient shortcut and you can explicitly define every variant individually if you prefer that). Note that _all_ is a reserved name and attempting to use it in the capabilities.xml file will trigger a warning on application startup. It could sometimes be a good idea to separate the variant configuration into separate files that are then included from the main theme file as this could improve the structure and readability of the theme configuration. It's also possible to apply only portions of the theme configuration to the variants and keep a common set of elements that are shared between all variants. This is accomplished by simply adding the shared configuration without specifying a variant, as is shown in the first example below for the `infoText01` text element. Just be aware that the variant-specific configuration will always be loaded after the general configuration even if it's located above the general configuration in the XML file. As this is potentially confusing and error-prone it's instead generally recommended to use the special _all_ variant to define common configuration used by all variants in the theme rather than mixing variants configuration with non-variants configuration. Here are some example uses of the `` functionality: ```xml ./gamelist_textlist.xml ./gamelist_carousel.xml ./${system.theme}/systeminfo.xml ./core/font.ttf 0.035 0.3 0.56 ``` ```xml titlescreen true 42 ``` ```xml titlescreen true 42 ``` ## Variant triggers (overrides) Variant triggers is an optional feature which can be used to replicate the automatic view style switching functionality of the legacy theme engine. This can be used to automatically override the selected variant based on two triggers, either when there are no game videos found for a system, or if there are no game media files of some specified types found for a system. These two trigger types are named `noVideos` and `noMedia` respectively. For the `noMedia` trigger there's an optional `mediaType` tag that can be used to specify precisely which media files should be checked for to determine whether to switch to the override variant. Valid values are `miximage`, `marquee`, `screenshot`, `titlescreen`, `cover`, `backcover`, `3dbox`, `physicalmedia`, `fanart` and `video`. Multiple values can be defined, in which case they are separated by a comma, or by a whitespace character (tab, space or line break). If no value is defined, it will be set to `miximage`. The `useVariant` tag specifies which variant to use to override the selected variant. You'll probably rarely need to use the `noVideos` trigger as `video` can be defined also when using the `noMedia` trigger. The reason for including both trigger types is that it makes it possible to apply a specific variant only when videos are missing and another variant when no media files at all are present. The following example (from the `capabilities.xml` file) defines a `noGameMedia` variant which is used as the override for the `withVideos` variant if no miximages, screenshots, covers and videos are found for any game in a system. For this example the `noGameMedia` variant has been set as non-selectable from the _UI Settings_ menu by defining the `selectable` property as `false`. As can be seen here, the overall variant trigger configuration needs to be enclosed within an `override` tag pair. And you can only define a single trigger type inside an `override` tag pair. ```xml true noMedia miximage, screenshot, cover, video noGameMedia false ``` It's also possible to define both the `noVideos` and `noMedia` triggers for the same variant like the following example: ```xml true noVideos withoutVideos noMedia miximage, screenshot, cover noGameMedia false false ``` In this case the `withoutVideos` variant will be selected if there are no videos but if there is other media available. If there is however no media matching the `mediaType` property then the `noGameMedia` variant will be selected instead. Note that `noMedia` always takes precedence over `noVideos`. If you would like to trigger the `withoutVideos` variant if there are videos but no other media, then you'll need to add _video_ to the `mediaType` property for the `noMedia` trigger. It's however not possible to define multi-step variant triggers like this: ```xml true noVideos withoutVideos false noMedia miximage, screenshot, cover noGameMedia false ``` If the above configuration is used, then the trigger will work correctly if there are no videos, i.e. the `withoutVideos` variant will be selected, but the `override` tag in the `withoutVideos` variant will be ignored so the `noGameMedia` variant will never be triggered even if there is no media whatsoever. Note that variant triggers will only apply to the gamelist view and not the system view. Also be aware that it will add a potentially noticeable application slowdown as game media files need to be scanned for at various points when using the application, as well as during startup. The impact of the performance penalty depends on multiple factors such as the game collection size, how many games have been scraped, as well as disk I/O and filesystem performance. So only use variant triggers if really necessary for your theme design. As well, specifying many values for the `mediaType` tag will lead to more files potentially being scanned which could introduce further lag and latency. As a final note, variant triggers can also be globally disabled by the user via the _Enable theme variant triggers_ option in the _UI Settings menu_. Not everyone may want the variant auto-switching to take place, and if all systems contain scraped media then disabling the functionality will eliminate the performance penalty described above. ## Color schemes Color schemes are essentially a collection of variables that can be selected between from the _UI Settings_ menu. This makes it possible to define different values that will be applied to the overall theme configuration based on this menu selection. Only variables can be used for the color schemes, but since variables can be used for almost everything this makes the functionality very flexible. In most cases you'll probably want to apply different color values to `` properties and similar, but it's also possible to apply different images, animations, fonts etc. per color scheme. To understand the basics on how to use variables, make sure to read the _Theme variables_ section elsewhere in this document. Before a color scheme can be used it needs to be declared, which is done in the `capabilities.xml` file that must be located in the root of the theme directory tree. How to setup this file is described in detail later in this document. The `` tag pair can be placed directly inside the `` tags, inside the `` tags or inside the `` tags. The mandatory name attribute is used to specificy which color scheme to use, and multiple values can be specified at the same time by separating them by commas or by whitespace characters (tabs, spaces or line breaks). Note that the use of color schemes for a theme is entirely optional. Here's an example configuration: ```xml 404040 F0F0F0 707070 262626 74747488 0 0 1 1 ./core/images/background.png true ${backgroundColor} 0.5 0.6437 1 0.056 ${defaultTextColor} ``` ## Font sizes The optional font sizes functionality makes it possible to use a set of predefined size options and connect these to theme variables that can be used to apply different text sizes and related design changes. The font sizes declared for the theme can be selected via the _Theme font size_ setting in the _UI Settings_ menu. To understand the basics on how to use variables, make sure to read the _Theme variables_ section elsewhere in this document. To use the font size entries you first need to declare them using `` tag pairs in the `capabilities.xml` file. The following sizes are available: | capabilities.xml name | UI Settings label | | :-------------------- | :--------------- | | medium | medium | | large | large | | small | small | | x-large | extra large | | x-small | extra small | The options will always be listed in the above order in the _UI Settings_ menu. Here's an example of a theme that implements three of these sizes: ```xml My theme medium small x-small ``` In the theme configuration you'll also use a `` tag pair combined with a `` tag pair to define the variables you want to apply per font size. These `` tag pairs can be placed directly inside the `` tags, inside the `` tags or inside the `` tags. The mandatory name attribute is used to specificy which font size to use, and multiple values can be specified at the same time by separating them by commas or by whitespace characters (tabs, spaces or line breaks). Here's an example configuration: ```xml 0.025 0.5 0.6437 0.022 0.016 0.015 0.45 0.6437 0.013 0.008 0.4 0.6437 0.006 0.011 ${gameCounterPos} 1 0.056 ${gameCounterFontSize} 0.2 0.3412 0.2 0.040 ${gameNameFontSize} 0.33 0.3412 0.18 0.040 ${publisherFontSize} ``` ## Languages Multilingual support works very similarly to color schemes and font sizes in that it's a variable-based configuration. Due to this you can set any arbitrary property values you want for a certain language, such as different texts or different images and so on. The supported languages for use in themes are the same as for the overall application. Note that the word _language_ is not technically the correct term as it's rather _locales_ that are used within ES-DE. For instance the en_US and en_GB locales are both for the English language but rather variations for different countries (United States and United Kingdom). Still, as the term _language_ is colloquially used to describe locales in many applications and operating systems this is also used in ES-DE even if it's not entirely correct. The term _language_ is as such also used throughout this document. While it's possible to use the theme engine language support to set language-specific date formats this is generally discouraged as it's better to use the ISO 8601 (YYYY-MM-DD) standard instead. This is an international standard that makes sense to use in all countries in the world. The following languages are supported: | Language | English name | Native name | | :------------ | :----------------------- | :----------------------- | | en_US | English (United States) | English (United States) | | en_GB | English (United Kingdom) | English (United Kingdom) | | es_ES | Spanish (Spain) | Español (España) | | fr_FR | French | Français | | it_IT | Italian | Italiano | | pl_PL | Polish | Polski | | pt_BR | Portuguese (Brazil) | Português (Brasil) | | ro_RO | Romanian | Română | | ru_RU | Russian | Русский | | sv_SE | Swedish | Svenska | | ja_JP | Japanese | 日本語 | | zh_CN | Simplified Chinese | 简体中文 | These languages are currently getting translated and may be supported in the near future: | Language | English name | Native name | | :------------ | :----------------------- | :----------------------- | | de_DE | German | Deutsch | | el_GR | Greek | Ελληνικά | | nl_NL | Dutch | Nederlands | | ar_EG | Arabic | العربية | Note that the native name is what is shown inside the _UI Settings_ menu for the _Theme Language_ and _Application Language_ settings. You can find more information about locales/languages here:\ https://simplelocalize.io/data/locales The languages a theme supports need to be declared in the `capabilities.xml` file using `` tag pairs, such as the following example: ```xml My theme en_US es_ES pt_PR sv_SE zh_CN ``` Although language support is optional for a theme, if you have declared at least one language then you have to include support for en_US as well. Attempting to skip an entry for this language will output an error message and the language configuration will not get loaded. The reason for this is that en_US is the default language for the ES-DE application so all themes have to support it, either implicitly (by not having any multilingual support) or explicitly by declaring it and providing localization for it. It's also possible to provide label translations for variants, color schemes and transitions, as displayed in the _UI Settings_ menu. This is done using the `language` attribute for these `label` entries, as in this example `capabilities.xml` file: ```xml My theme en_US sv_SE true noMedia miximage, screenshot, cover, video noGameMedia true instant slide instant slide slide slide ``` Leaving out the `language` property will make ES-DE set the language to en_US. The actual language-specific values in the theme configuration are defined using variables, like the following example: ```xml logo.svg Developer Publisher logo-sv-se.svg Utvecklare Utgivare 0.38 0.1781 0.158 0.12 ./assets/${langLogo} 0.88 0.511 0.165 0.03 ${langLabelDeveloper} 0.88 0.5935 0.165 0.03 ${langLabelPublisher} ``` It could also be a good idea to include the translations from a separate file: ```xml ./languages.xml 0.38 0.1781 0.158 0.12 ./assets/${langLogo} 0.88 0.511 0.165 0.03 ${langLabelDeveloper} 0.88 0.5935 0.165 0.03 ${langLabelPublisher} ``` Including separate files per language is also supported but it's probably not a good idea as it will add a lot of unnecessary files to the theme: ```xml ./lang-en-us.xml ./lang-sv-se.xml 0.38 0.1781 0.158 0.12 ./assets/${langLogo} 0.88 0.511 0.165 0.03 ${langLabelDeveloper} 0.88 0.5935 0.165 0.03 ${langLabelPublisher} ``` Note the naming convention when using localized versions of files such as images. These should include the locale/language in their name and they should be in lowercase characters, using only dashes as separators. For the default language the locale could be omitted from the filename (as language-specific images and similar will likely be exceptions with most files rather shared across all locales). Here are some examples: ``` logo.svg logo-fr-fr.svg logo-pt-br.svg logo-sv-se.svg auto-allgames.webp auto-allgames-fr-fr.webp auto-allgames-pt-br.webp auto-allgames-sv-se.webp ``` ## Aspect ratios The aspect ratio support works almost identically to the variants and color schemes with the main difference that the available aspect ratios are hardcoded into ES-DE. The theme can still decide which of the aspect ratios to support (or none at all in which case the theme aspect ratio is left undefined) but it can't create entirely new aspect ratio entries. In the same manner as for the variants and color schemes, the aspect ratios that the theme provides need to be declared in the `capabilities.xml` file that must be located in the root of the theme directory tree. How to setup this file is described in detailed later in this document. The `` tag pair can be placed directly inside the `` tags or inside the `` tags. Once the aspect ratios have been defined, they are applied to the theme configuration like the following examples: ```xml ./../layout_narrow.xml ./../layout_wide.xml ./../layout_ultrawide.xml ./core/font.ttf 0.035 ``` ```xml 0.3 0.56 0.42 0.31 ``` ```xml 0.3 0.56 ``` ```xml 0.3 0.56 ``` ## Transitions (animation profiles) Using the `capabilities.xml` file it's possible to define granular transition animation profiles. Prior to ES-DE 2.0 there was only a user-selectable option for _Instant_, _Slide_ or _Fade_ animations that was applied globally. It's now possible to select each of these animation types individually for the following transitions: * System to system * System to gamelist * Gamelist to gamelist * Gamelist to system * Startup to system * Startup to gamelist This is a brief overview of the supported animations: * Instant - as the name implies, transitions are immediate * Slide - pans the camera to move between views which may look broken with some elements like textlists and grids when used in the system view * Fade - fades to black when transitioning between views Here's an example configuration: ```xml true instant slide instant slide fade fade true instant instant instant instant ``` The `name` attribute is mandatory and it must be set to a unique value for each profile. Any string can be used except the three reserved values `builtin-instant`, `builtin-slide` and `builtin-fade`. The `selectable` property which is set to `true` by default defines whether the transitions profile can be selected from the _Theme transitions_ entry on the _UI Settings_ menu. The `label` defines the label to show there. If no label value is set then a default _Theme profile_ label will be applied. At least one of the six transition types must be defined or the `transitions` entry is not considered valid. Any non-defined types will be set to `instant` with the exception of `startupToSystem` which will be set to the same value as `systemToSystem` and `startupToGamelist` which will be set to the same value as `gamelistToGamelist`. The profiles will be listed in the _UI Settings_ menu in the order that they have been defined, and the first profile (regardless of whether it's set as user-selectable or not), will be used if the _Automatic_ entry has been selected, unless a per-variant configuration is defined in the theme configuration. In addition to defining custom transition profiles it's possible to suppress the built-in profiles. For example slide transitions will look very broken with some theme designs so in such cases it could make sense to disable this animation type altogether. Suppressing a profile simply means its entry will not show up under _Theme transitions_ in the _UI Settings_ menu, making it impossible to select and use it. Here's an example where all the built-in transition profiles have been disabled: ```xml builtin-instant builtin-slide builtin-fade ``` Regardless of whether any custom profiles have been created or whether the built-in profiles have been disabled there will always be an `Automatic` entry added to the _Theme transition animations_ menu. If no theme profiles have been defined and all built-in profiles have been suppressed, then the `Automatic` entry will be the only available option. In this case `instant` animations will by applied to all transition types. Finally it's possible to apply theme-defined transition profiles on a per-variant basis. This requires that the user has selected the `Automatic` profile from the _Theme transitions_ menu as selecting any other profile will override whatever is defined in the theme configuration. Note that the built-in transition profiles can't be used in this manner, only profiles defined in `capabilities.xml`. ```xml instantAndSlide instant ``` ## capabilities.xml Variants, variant triggers, color schemes, font sizes, languages, aspect ratios and transition animation profiles need to be declared before they can be used inside the actual theme configuration files and that is done in the `capabilities.xml` file. This file needs to be located in the root of the theme directory, for example: ``` ~/ES-DE/themes/mytheme-es-de/capabilities.xml ``` The capabilities.xml file is mandatory and if it doesn't exist ES-DE will not attempt to load the theme. The structure of the file is simple, as can be seen in this example: ```xml My theme en_US sv_SE 16:9 4:3 4:3_vertical medium large instant slide instant slide true noMedia miximage, screenshot, cover, video noGameMedia true noMedia miximage, screenshot, cover noGameMedia false ``` The file format is hopefully mostly self-explanatory; this example provides two languages, three aspect ratios, two font sizes, two color schemes, one transition animation profile and three variants, one of which is a variant trigger override. The `