Ein Recalbox-Theme erstellen

45 Seiten · 8 Abschnitte
FRENESDE Alles anzeigen Seite für Seite Mein Theme erstellen

Was ist ein Theme?

Was ein Theme ändert — und was nicht.

Ein Recalbox-Theme kleidet die Oberfläche ein: die Liste deiner Systeme beim Start, die deiner Spiele, die Menüs, den Bildschirmschoner.

Was ein Theme entscheidet

Was ein Theme nicht entscheidet

Das Prinzip, in einem Satz

Recalbox liest XML-Dateien, die Komponenten deklarieren — ein Bild, einen Text, eine Liste — jede mit ihrer Position, ihrer Größe und ihrem Aussehen.

<image name="fond">
  <pos>0 0</pos>
  <size>1 1</size>
  <path>./data/fond.jpg</path>
</image>

Das Studio schreibt diese Dateien für dich. Diese Dokumentation erklärt die vollständige Syntax: Sie soll dir erlauben, ein Theme ganz von Hand zu schreiben, wenn du möchtest.


Das minimale funktionierende Theme

Die vier Ansichten, in einer einzigen Datei.

Ein Theme fügt sich immer auf dieselbe Weise zusammen, und das ist der Plan dieser ganzen Dokumentation:

ein Theme enthält Ansichten — je ein Bildschirm; eine Ansicht enthält Komponenten — ein Bild, einen Text, eine Liste; eine Komponente trägt Eigenschaften — ihre Position, ihre Größe, ihre Farbe.

Hier ist ein vollständiges, funktionierendes Theme: alle vier Ansichten sind da. Lege einen Ordner mon-theme/ in /recalbox/share/themes/ an, lege dieses theme.xml hinein, und es erscheint in der Theme-Liste.

<?xml version="1.0" encoding="UTF-8"?>
<theme name="Mein Theme" version="1.0" author="Ich"
       recalbox="10.0" compatibility="hdmi,crt" resolutions="hd,fhd">

  <!-- ── 1. DIE SYSTEMLISTE ──────────────────────────────────── -->
  <view name="system">
    <box name="fond" extra="true">
      <pos>0 0</pos><size>1 1</size>
      <color>101820</color><zIndex>1</zIndex>
    </box>

    <carousel name="systemcarousel">
      <type>horizontal</type>
      <pos>0 0.35</pos><size>1 0.3</size>
      <logoSize>0.2 0.12</logoSize>
      <maxLogoCount>5</maxLogoCount>
    </carousel>

    <image name="logo"/>

    <text name="systemInfo">
      <pos>0.5 0.75</pos><origin>0.5 0.5</origin>
      <fontSize>0.03</fontSize><color>8A92A6</color>
      <alignment>center</alignment>
      <backgroundColor>00000000</backgroundColor>
    </text>
  </view>

  <!-- ── 2. DIE SPIELELISTE ──────────────────────────────────── -->
  <view name="detailed">
    <box name="fond" extra="true">
      <pos>0 0</pos><size>1 1</size>
      <color>101820</color><zIndex>1</zIndex>
    </box>

    <textlist name="gamelist">
      <pos>0.05 0.15</pos><size>0.42 0.75</size>
      <primaryColor>C6CBD8</primaryColor>
      <secondaryColor>8A92A6</secondaryColor>
      <selectedColor>101820</selectedColor>
      <selectorColor>4FE3C1</selectorColor>
      <fontSize>0.035</fontSize>
    </textlist>

    <image name="md_image">
      <pos>0.74 0.4</pos><origin>0.5 0.5</origin>
      <maxSize>0.4 0.45</maxSize>
    </image>

    <text name="md_description">
      <pos>0.54 0.68</pos><size>0.4 0.22</size>
      <fontSize>0.024</fontSize><color>A0A8BA</color>
    </text>
  </view>

  <!-- ── 3. DIE MENÜGESTALTUNG ───────────────────────────────── -->
  <view name="menu">
    <menuBackground>
      <color>101820F0</color>
    </menuBackground>
    <menuText>
      <fontSize>0.038</fontSize>
      <color>C6CBD8</color>
      <selectedColor>101820</selectedColor>
      <selectorColor>4FE3C1</selectorColor>
    </menuText>
  </view>

  <!-- ── 4. DER BILDSCHIRMSCHONER ────────────────────────────── -->
  <view name="gameclip">
    <extras>
      <text name="titre">
        <pos>0.06 0.86</pos>
        <text>${game.name}</text>
        <fontSize>0.05</fontSize><color>FFFFFF</color>
      </text>
    </extras>
  </view>
</theme>

Was daran auffallen soll

Hier passt alles in eine Datei, damit es auf einen Blick lesbar ist. Sobald das Theme wächst, teilt man es auf — siehe Das Theme aufteilen.


Dein erstes Theme erstellen

Der Weg — mit dem Studio, oder von Hand.

Das Ergebnis ist dasselbe: ein Theme-Ordner. Zwei Wege führen dorthin.

Mit dem Studio

  1. Starte von einer Vorlage. Die leere Seite ist der schlechteste Anfang. Eine Vorlage kommt mit fertig platzierten Komponenten: Du ersetzt sie.
  2. Wähle deine Bildschirmauflösungen — HD 16:9, CRT 4:3, vertikaler Bildschirm (TATE). Was auf einen Breitbildschirm passt, passt nicht auf einen Röhrenfernseher. Beginne mit einer, ergänze die anderen später.
  3. Platziere deine Komponenten: Ziehe sie aus der linken Spalte, stelle sie in der rechten ein.
  4. Wechsle das System in Ansichtsoptionen und schau hin: Der häufigste Fehler ist ein Theme, das auf einer einzigen Maschine eingestellt wurde und überall sonst zerbricht. Nicht alle Logos haben dieselbe Form, nicht alle Namen dieselbe Länge.
  5. Exportiere, kopiere den Ordner auf deine Maschine, probiere es aus — siehe Das Theme ausprobieren.

Von Hand

  1. Starte von einem bestehenden Theme. Öffne eines, lies es: Das ist der schnellste Weg zu verstehen, wie es gemacht wird. Das offizielle Recalbox-Theme ist ein guter Anfang.
  2. Lege den Ordner und sein theme.xml an — die einzige Pflichtdatei. Siehe Ordner und Dateien.
  3. Kündige an, was du abdeckst, im <theme>-Tag: compatibility für die Bildschirmtypen, resolutions für die Auflösungen. Diese beiden Attribute schalten die Piktogramme des Theme-Managers ein — sie falsch anzugeben heißt versprechen, was das Theme nicht hält. Siehe Der Kopf.
  4. Schreibe deine Ansichten, eine pro Bildschirm, und teile in mehrere Dateien auf, sobald es wächst — siehe Das minimale funktionierende Theme, dann Das Theme aufteilen.
  5. Bediene die anderen Bildschirme mit Bedingungen statt alles zu kopieren: <include if="crt">.
  6. Kopiere den Ordner auf deine Maschine und probiere es aus — und lies themes.log bei der ersten unsichtbaren Komponente.

In beiden Fällen lauert derselbe Fehler: nur auf DEINEM Bildschirm und DEINEM System zu prüfen.


Ordner und Dateien

Eine einzige Regel, und viel Freiheit.

Ein Theme ist ein Ordner in /recalbox/share/themes/.

📁 mon-theme/ 📄 theme.xml 📁 views/ 📁 data/ 📁 data/fonts/ …beliebig angeordnet PFLICHT ohne sie existiert das Theme nicht frei kein Name, kein vorgegebener Aufbau die einzige Regel: ein Ordner, und eine theme.xml in seiner Wurzel

Die einzige Regel

Dieser Ordner muss eine Datei theme.xml enthalten.

Das ist alles. theme.xml ist der Einstiegspunkt: Recalbox sucht sie in der Wurzel des Ordners, und wenn sie fehlt, existiert das Theme nicht.

Nichts anderes ist vorgeschrieben. Keine Unterordnernamen, keine Aufteilung, keine Organisation. Du kannst ein ganzes Theme in dieser einen Datei schreiben.

Aufteilen, weil es praktischer ist

Ein ernsthaftes Theme kommt schnell auf Tausende Zeilen. Man teilt es daher in mehrere XML-Dateien auf, geordnet wie man will, die theme.xml einbindet:

mon-theme/
  theme.xml            ← der einzige vorgeschriebene Name
  variables.xml
  views/
    system.xml
    detailed.xml
    menu.xml
  data/
    fonts/
    images/

Diese Namen gehören dir: Nenne sie, wie du willst. Üblich ist, in veröffentlichten Themes wie in den Exporten des Studios, sie auf Englisch zu schreiben — views/, data/, fonts/ — weil das die Sprache der Tags ist, die sie enthalten.

Der Einbindungsmechanismus wird in Das Theme aufteilen erklärt.

Die Pfade

Ein in einer Datei geschriebener Pfad ist relativ zu dieser Datei. Sobald man in Unterordner aufteilt, wird das zur Fehlerquelle.

Geh über ${root}, das immer die Wurzel des Themes bezeichnet:

<path>${root}/data/images/fond.jpg</path>   <!-- ✅ funktioniert aus jeder Datei -->
<path>../data/images/fond.jpg</path>        <!-- fragil: hängt davon ab, wo die Zeile steht -->

Der Kopf: das <theme>-Tag

Was dein Theme identifiziert — und NUR in theme.xml gehört.

<theme> ist die Wurzel jeder XML-Datei eines Themes. Aber seine Identitätsattribute haben nur in theme.xml einen Sinn: Diese Datei liest der Theme-Manager, um zu wissen, worum es geht.

Merken In theme.xml füllst du sie alle aus: Ohne sie erscheint dein Theme ohne Namen, ohne Version, und der Manager weiß nicht, auf welchen Bildschirmen es funktioniert. In den anderen Dateien schreibst du ein nacktes <theme>: Sie zu wiederholen bringt nichts und kann verwirren.

Die Attribute

AttributRolleBeispielWenn es fehlt
nameName in der Theme-Listename="Mein Theme"der Ordnername
versionVersion des Themesversion="1.2"nicht angezeigt
authorDer Autorauthor="Benoît"nicht angezeigt
recalboxMindestversion von Recalboxrecalbox="10.0"alle Versionen
compatibilityUnterstützte Bildschirmtypen: hdmi, crt, jamma, tatecompatibility="hdmi,crt"hdmi
resolutionsUnterstützte Auflösungen: qvga, vga, hd, fhdresolutions="hd,fhd"fhd,hd

compatibility und resolutions sind genau die Piktogramme, die der Theme-Manager zeigt: HDMI / CRT / JAMMA / TATE auf der einen Seite, SD 240p / SD+ 480p / HD 720p / FULLHD 1080p auf der anderen. Sie falsch anzugeben heißt versprechen, was das Theme nicht hält.

⚠️ Ohne sie kann dein Theme nicht veröffentlicht werden im Theme-Manager: Das offizielle Repository verlangt einen Namen, eine Version und einen Autor. Siehe Das Theme teilen.

Die zwei Fälle

In theme.xmldas vollständige Tag:

<theme name="Mein Theme" version="1.2" author="Benoît"
       recalbox="10.0" compatibility="hdmi,crt" resolutions="hd,fhd">
  …
</theme>

In allen anderen Dateien des Themes — das nackte Tag:

<theme>
  <view name="system"> … </view>
</theme>

Das Theme aufteilen: <include>

Ein ernsthaftes Theme passt nicht in eine einzige Datei.

<include> lädt eine andere Datei an genau dieser Stelle, als wäre ihr Inhalt dorthin kopiert.

<include>${root}/views/system.xml</include>
<include path="${root}/views/detailed.xml" />

Beide Schreibweisen funktionieren: der Pfad als Inhalt des Tags, oder als Attribut path.

Die Reihenfolge zählt

Recalbox liest von oben nach unten, und zwei Komponenten mit demselben Namen ersetzen einander: die letzte gewinnt.

base.xml Hintergrund = blau rouge.xml Hintergrund = rot der Hintergrund ist ROT von oben nach unten gelesen: zwei Komponenten gleichen Namens ersetzen einander, die LETZTE gewinnt das ist der ganze Überlagerungsmechanismus — und damit der Optionen

Das ist der ganze Overlay-Mechanismus — und so sind die Theme-Optionen gebaut: Jede Wahl ist eine obendrauf geladene Datei, die nur neu definiert, was sich ändert. Siehe Was eine Option ist.

<include>${root}/views/base.xml</include>       <!-- malt den Hintergrund blau -->
<include>${root}/options/rouge.xml</include>     <!-- malt ihn rot um -->

Bedingt einbinden

Ein <include> akzeptiert if=, wie eine Komponente: Die Datei wird nur geladen, wenn die Bedingung wahr ist.

<include if="crt">${root}/views/system-crt.xml</include>

So bedient man je Bildschirm ein anderes Layout, ohne alles andere zu duplizieren. Die Liste der Bedingungen steht in Bedingt anzeigen.


Freie Komponenten: extra="true" und <extras>

Warum eine hinzugefügte Komponente nicht erscheint — und die zwei Arten, sie zu deklarieren.

Zwei Familien von Komponenten

Innerhalb einer Ansicht unterscheidet Recalbox:

Eine freie Komponente muss als solche deklariert werden

Eine freie Komponente direkt in der Ansicht wird nicht gezeichnet: Die Maschine baut nur die mit extra markierten Elemente. Zwei mögliche Schreibweisen, die genau dasselbe tun:

<image name="monLogo" extra="true">…</image>
<extras>
    <image name="monLogo">…</image>
    <text name="maMention">…</text>
</extras>

<extras> ist ein Container: Jedes seiner Kinder erhält extra="true", auf einen Schlag. Kürzer und lesbarer, sobald es mehrere Komponenten gibt — das schreibt auch das Studio.

Was man sich merken muss

Im Studio musst du nichts tun: Die Komponenten, die du hinzufügst, werden automatisch in <extras> geschrieben, die reservierten Elemente außerhalb.


Deine eigenen Variablen: <variables>

Was in die Datei kommt: das Tag, die Namensregeln, der Geltungsbereich.

Diese Seite beschreibt, was in die Datei kommt. Um sie ohne eine Zeile XML anzulegen, siehe Deine maßgeschneiderten Variablen unter „Dynamische Daten“.

Es ist der nützlichste Mechanismus eines ernsthaften Themes — und doch der unbekannteste.

<variables>
  <variable name="CouleurPrincipale" value="2E447C" />
  <variable name="PoliceTitre"       value="${root}/data/fonts/Exo2.otf" />
  <variable name="Alpha50"           value="80" />
</variables>

Dann, überall im Theme:

<box name="fond">
  <color>${CouleurPrincipale}</color>
</box>
<text name="titre">
  <fontPath>${PoliceTitre}</fontPath>
  <color>${CouleurPrincipale}${Alpha50}</color>
</text>

Ändere den Wert an einer Stelle, das ganze Theme folgt. Das macht Farboptionen möglich: Eine Overlay-Datei definiert die Variable neu, und sonst nichts.

Die Regeln

  <variable name="CheminLogo" value="${root}/data/logos/${system.name}.svg" />
  <variables if="crt">
    <variable name="TailleTitre" value="0.09" />
  </variables>

⚠️ Der Block steht ganz oben

<variables> gilt für alles, was NACH ihm gelesen wird.

Recalbox ersetzt jedes ${nom} beim Lesen der Dateien. Eine oben im Theme deklarierte Variable gilt also überall; in der Mitte deklariert, gilt sie nur für den Rest.

Daher die Regel, gültig für alle Themes: der Variablenblock zuerst, vor den Ansichten, vor allem anderen.

Eine später neu definierte Variable ersetzt die vorige für den Rest des Lesens — das erlaubt einer Optionswahl, ein ganzes Theme umzufärben, sofern sie vor den Ansichten geladen wird. Siehe Eine Option deklarieren.

Wo sie deklarieren

In theme.xml, vor den <include>-Tags, die sie benutzen: Die Engine liest die Variablen einer Datei, bevor sie ihre Einbindungen verarbeitet.

Üblich, vom offiziellen Theme übernommen, ist eine eigene Dateivariables.xml — als allererstes eingebunden:

<include>${root}/variables.xml</include>

Die drei Schreibweisen einer Eigenschaft

Tag, Tag mit Wert, oder Attribut — und warum das alles ändert.

Dieselbe Eigenschaft kann auf drei Arten geschrieben werden. Sie sind gleichwertig… außer in einem entscheidenden Punkt.

1. Als Kind-Tag

<image name="fond">
  <path>./data/fond.jpg</path>
</image>

Die historische Form. Am lesbarsten, sobald eine Komponente mehrere Eigenschaften hat.

2. Als Kind-Tag mit value-Attribut

<image name="fond">
  <path value="./data/fond.jpg" />
</image>

Streng gleichwertig zur ersten.

3. Als Attribut der Komponente

<image name="fond" path="./data/fond.jpg" pos="0 0" size="1 1" />

Alles passt in eine Zeile. Sehr praktisch für einfache Komponenten.

Der Unterschied, der zählt

Nur die Formen 1 und 2 akzeptieren eine Bedingung auf EINER Eigenschaft.

<image name="fond">
  <path if="crt">./data/fond-crt.jpg</path>
  <path if="!crt">./data/fond-hd.jpg</path>
</image>

In Form 3 unmöglich: if= auf dem Eltern-Tag würde die ganze Komponente bedingen, nicht eine ihrer Eigenschaften.

Sie mischen sich frei

Das ist der wichtige Punkt: Du musst dich nicht für eine Art entscheiden und dabei bleiben. Recalbox' Leser akzeptiert alle drei, auch in derselben Komponente.

<image name="fond" pos="0 0" size="1 1" zIndex="1">
  <path if="crt">${root}/images/fond-crt.jpg</path>
  <path if="!crt">${root}/images/fond-hd.jpg</path>
  <color value="FFFFFFC0" />
</image>

Drei Schreibweisen in derselben Komponente: die einfachen Werte als Attribute in der ersten Zeile, die mit Varianten als bedingte Tags, und eine letzte als Tag mit value. Vollkommen gültig — und genau das schreibt man in der Praxis.

➡️ Einfache Regel: ein einziger Wert → Attribut; Varianten → Kind-Tag.


Ratio, Prozent oder Pixel

Die drei akzeptierten Schreibweisen für eine Position oder eine Größe.

Mehrere Eigenschaften werden mit zwei durch ein Leerzeichen getrennten Zahlen geschrieben: x y. Das gilt für pos, size, maxSize, origin, rotationOrigin, logoSize und reflection.

Jede Zahl akzeptiert drei Schreibweisen, und man darf sie im selben Paar mischen.

SchreibweiseBeispielBedeutung
Ratio (Standard)0.5 0.25ein Anteil des Bildschirms, von 0 bis 1
Prozent50% 25%dasselbe, anders geschrieben
Pixel960p 270pechte Pixel, Suffix p
<pos>0.5 0.5</pos>      <!-- die Mitte -->
<pos>50% 50%</pos>      <!-- genau dasselbe -->
<pos>960p 540p</pos>    <!-- die Mitte… nur eines 1920×1080-Bildschirms -->

Ratio oder Prozent: vorzuziehen

x ist ein Anteil der Breite, y der Höhe. Eine Komponente bei 0.5 0.5 ist auf einem 1920×1080 wie auf einem 640×480 in der Mitte. Das lässt ein Theme auf mehrere Bildschirme passen.

Pixel: eine feste Position

Ein Pixel ist ein Pixel. 960p sind 960 Pixel vom linken Rand, Punkt.

Das passt sich an nichts an: Auf einem Bildschirm mit weniger als 960 Pixeln Breite liegt die Komponente außerhalb des Bildschirms. Eine absolute Position, das Gegenteil des Ratios.

Pixel rechtfertigen sich nur für das, was unabhängig von der Auflösung fest bleiben muss: die Dicke einer Linie, ein Versatz von wenigen Punkten. Für alles andere nimm das Ratio.

Der Sonderfall fontSize

fontSize nimmt nur eine Zahl, und ihre Einheit hängt vom Wert ab:

WertBedeutung
< 1ein Anteil der kurzen Seite des Bildschirms — 0.05 = 5 % der Höhe in 16:9
>= 1eine 240p-Referenzgröße, die Recalbox je nach Bildschirm multipliziert

Über 1 ist der Wert keine Pixel. Es ist eine Größe für einen Bildschirm mit 240 Zeilen, bei jedem Auflösungsschritt eine Stufe multipliziert: ×1 bis 288 Pixel kurze Seite, ×2 bis 576, ×4 bei 1080p. <fontSize>8</fontSize> ergibt also 16 Pixel auf einem 480p-Bildschirm und 32 Pixel bei 1080p. Dieselbe Regel gilt überall — Menütexte eingeschlossen.

<fontSize>0.045</fontSize>   <!-- 4,5 % der kurzen Seite: passt sich überall an, vorzuziehen -->
<fontSize>8</fontSize>       <!-- „240p“-Größe: 16 px bei 480p, 32 px bei 1080p -->

Position, Größe, Ursprung, Rotation

Eine Komponente genau dort platzieren, wo man sie will.

pos und origin gehören immer zusammen

Das ist der Punkt, den man vor allem anderen verstanden haben muss, denn die beiden sprechen nicht über dasselbe:

poswo, auf dem BILDSCHIRM, die Komponente platziert wird. originwelcher Punkt DER KOMPONENTE dort platziert wird.

Das eine ist eine Position auf dem Bildschirm, das andere ein Punkt der Komponente. Das Zusammentreffen beider entscheidet, wo die Komponente erscheint.


pos — eine Position auf dem Bildschirm

<pos>0.1 0.2</pos>

Diese zwei Zahlen messen sich von der oberen linken Ecke des Bildschirms: 0 0 ist diese Ecke, 1 1 die untere rechte.

Am einfachsten liest man sie als Prozentwerte — es ist genau dasselbe: 0.1 = 10 %, 0.2 = 20 %, 0.5 = 50 %. pos 0.1 0.2 heißt also 10 % der Breite und 20 % der Höhe.

der Bildschirm, unabhängig von seiner Auflösung 00 10 01 11 pos 0.1 0.2 0.1 → 10 % de la largeur 0.2 → 20 % de la hauteur alles wird von der oberen linken Ecke des BILDSCHIRMS aus gemessen

pos sagt nichts über die Komponente selbst: Es ist ein bloßer Punkt auf dem Bildschirm. Was entscheidet, welcher Teil der Komponente dort landet, ist origin.


origin — welcher Punkt DER KOMPONENTE

origin beantwortet die andere Hälfte der Frage: Jetzt, da wir wissen wo auf dem Bildschirm — welcher Teil der Komponente legt sich dorthin?

Diese neun Werte sind die gebräuchlichsten, aber jedes Paar zwischen 0 und 1 funktioniert:

deine Komponente000.501000.50.50.510.5010.5111die neun möglichen Werte von origin

Standardmäßig ist origin 0 0 — die obere linke Ecke der Komponente. Deshalb erstreckt sich eine Komponente ohne origin von ihrer pos aus nach rechts und nach unten.

Das Beispiel, das alles erklärt

Nehmen wir ein Querformat-Bild auf einem 16:9-Bildschirm:

<pos>0.5 0.5</pos>
<origin>1 1</origin>

pos 0.5 0.5 ist die Bildschirmmitte. Man könnte glauben, das Bild werde dort zentriert. Ist es nicht: origin 1 1 bezeichnet die untere rechte Ecke des Bildes, und diese Ecke wird in die Mitte gelegt.

der Bildschirm (16:9) dein Bild (quer) origin 1 1 die untere rechte Ecke des Bildes… pos 0.5 0.5 …in der Mitte platziert des Bildschirms ➜ das Bild ist NICHT zentriert: es liegt oberhalb und links der Mitte.

Das Bild landet also vollständig oben links von der Mitte.

Um wirklich zu zentrieren

<pos>0.5 0.5</pos>
<origin>0.5 0.5</origin>

Diesmal wird die Bildmitte in die Bildschirmmitte gelegt.

Die vollständige Tabelle

originDer auf pos gelegte Punkt der Komponente
0 0obere linke Ecke — der Standardwert
0.5 0Mitte der Oberkante
1 0obere rechte Ecke
0 0.5Mitte der linken Kante
0.5 0.5die Mitte
1 0.5Mitte der rechten Kante
0 1untere linke Ecke
0.5 1Mitte der Unterkante
1 1untere rechte Ecke

Wofür das wirklich gut ist

Ohne origin wird jede Komponente an ihrer oberen linken Ecke platziert: Um etwas zu zentrieren, müsste man 0.5 − Breite/2 rechnen — und jedes Mal neu rechnen, wenn sich die Breite ändert.

Mit origin rechnet man gar nichts mehr:

Was man willposorigin
auf dem Bildschirm zentriert0.5 0.50.5 0.5
am rechten Rand angedockt1 …1 …
am unteren Rand angedockt… 1… 1
unten zentriert0.5 10.5 1

Besonders nützlich für ein System-Logo, dessen Breite von Maschine zu Maschine wechselt: Mit origin bleibt es ausgerichtet, egal was kommt.


size — die vorgegebene Größe

<size>0.3 0.2</size>

Die Komponente hat genau diese Größe. Für ein Bild heißt das: Es wird verzerrt, um die Box zu füllen.

Nur eine angeben

Setze die andere auf 0: Die fehlende Dimension wird berechnet, um die Proportionen zu erhalten.

<size>0.3 0</size>   <!-- 30 % breit, proportionale Höhe -->

⚠️ Das ist nicht dasselbe wie keepratio oder maxSize, auch wenn beide die Proportionen erhalten:

SchreibweiseWas garantiert ist
size 0.3 0die Breite beträgt genau 30 %; die Höhe folgt, wie auch immer — sie kann überlaufen
maxSize 0.3 0.2das Bild passt in die Box: die einschränkendere Dimension gewinnt, die Breite kann also schrumpfen

Anders gesagt: size mit einer Null setzt eine Schranke, maxSize setzt zwei.

maxSize — die Maximalgröße, ohne Verzerrung

<maxSize>0.3 0.2</maxSize>
size 0.3 0.2 das Bild FÜLLT die Box… gestrecktes Bild ➜ verzerrt maxSize 0.3 0.2 …das Bild PASST in die Box ganzes Bild ➜ Proportionen bewahrt oben und unten bleibt Leerraum der gelbe gepunktete Rahmen = die verlangte Box, in beiden Fällen

Das Bild wird unter Erhalt seiner Proportionen vergrößert oder verkleinert, um in die Box zu passen. Es füllt sie daher selten ganz aus.

Für ein System-Logo ist fast immer maxSize richtig. Logos haben nicht von Maschine zu Maschine dieselbe Form: Mit size würden manche plattgedrückt.

size zusammen mit keepratio ergibt dasselbe wie maxSize — und ist oft die bevorzugte Schreibweise, weil sie die gewollte Größe nennt statt einer Grenze:

<size>0.3 0.2</size>
<keepratio>true</keepratio>   <!-- ⚠️ alles klein geschrieben -->

maxSize existiert nur auf image und video.

rotation und rotationOrigin

<rotation>90</rotation>
<rotationOrigin>0.5 0.5</rotationOrigin>

rotation ist in Grad, im Uhrzeigersinn. rotationOrigin bezeichnet den Punkt, um den die Komponente dreht, in ihren eigenen Proportionen. Ohne rotationOrigin ist der Drehpunkt die obere linke Ecke (0 0) — schreibe 0.5 0.5, um um die Mitte zu drehen.

Die Rotation gilt für Bilder, Farbblöcke, Videos und Markdown-Blöcke. Ein gedrehter Text zeichnet sich bei kleinen Neigungen, verschwindet aber bei 90°; ein gedrehter Lauftext zeichnet nur seinen Hintergrund, nie seinen Text. Für einen vertikalen Titel nimm ein Bild oder einen Markdown-Block.

rotationOrigin 0.5 0.5 sie dreht sich um ihre Mitte rotationOrigin 0 0 sie dreht sich um ihre obere linke Ecke rotation 20 — in Grad, im Uhrzeigersinn

Die Tiefe (zIndex) und das Abschalten (disabled) haben ihre eigene Seite: Tiefe und Sichtbarkeit.


Tiefe und Sichtbarkeit

Was vor was liegt, und wie man eine Komponente abschaltet.

Zwei Eigenschaften, die jede Komponente akzeptiert und die weder von Position noch von Größe sprechen: welche vor der anderen liegt, und welche gar nicht erscheint.

zIndex — die Ebenen

<zIndex>40</zIndex>

Es ist ein Ebenensystem, genau wie in einem Zeichenprogramm: Jede Komponente ist ein Blatt, und zIndex sagt, in welcher Reihenfolge sie gestapelt sind. Je größer die Zahl, desto näher bei dir liegt die Komponente.

Hilfeleiste50Texte und Logos40Lesbarkeitsschleier20Dekor10Hintergrund1zIndex

Reservierte Komponenten haben ihre Standardwerte, freie Komponenten erhalten 10, wenn du nichts sagst. Lass Platz zwischen deinen — 10, 20, 30 — um später eine dazwischenschieben zu können.

disabled — eine Komponente abschalten

<disabled>true</disabled>

Die Komponente wird gelesen, aber nicht angezeigt. Praktisch, um eine reservierte Komponente auszublenden, die man nicht will, ohne sie ganz neu definieren zu müssen.

⚠️ Weder carousel noch textlist akzeptieren es.


Farben und Verläufe

RRGGBB, Transparenz, und die acht Ecken.

Die Schreibweise

Eine Farbe wird hexadezimal geschrieben, ohne Raute:

<color>2E447C</color>       <!-- deckend -->
<color>2E447C80</color>     <!-- halbtransparent -->

Die nützlichsten Transparenzwerte

Den Code einer Farbe kennt man. Die zwei Zeichen der Deckkraft viel weniger:

DeckkraftSchreibenDeckkraftSchreiben
0 % — unsichtbar0060 %99
10 %1A70 %B3
20 %3375 %BF
25 %4080 %CC
30 %4D90 %E6
40 %6695 %F2
50 %80100 % — deckendFF

Die Rechnung, falls dein Wert fehlt: der Prozentsatz × 255, hexadezimal geschrieben.

Die Verläufe

box und image akzeptieren eine Farbe pro Kante oder pro Ecke. Zwei genügen für einen Verlauf.

colorTop colorBottom vertikaler Verlauf colorLeft colorRight horizontaler Verlauf colorTopLeft colorBottomRight Verlauf über die vier Ecken ZWEI Farben genügen für einen Verlauf
EigenschaftWirkung
colorTop + colorBottomvertikaler Verlauf
colorLeft + colorRighthorizontaler Verlauf
colorTopLeft, colorTopRight, colorBottomLeft, colorBottomRightVerlauf über die vier Ecken
<box name="ombre-du-haut">
  <pos>0 0</pos>
  <size>1 0.3</size>
  <colorTop>00000080</colorTop>
  <colorBottom>00000000</colorBottom>
</box>

Ein Verlauf von halbtransparentem Schwarz zu voller Transparenz: der klassische Schleier, unter dem ein Titel lesbar bleibt, egal welches Bild dahinterliegt.

Ein Bild einfärben

Auf einer image-Komponente füllt color nicht: Es multipliziert das Bild. Ein weißes Bild nimmt also genau die angegebene Farbe an — so färbt man ein Icon um, ohne die Datei neu zu machen.

<image name="etoile">
  <path>${root}/data/arts/etoile-blanche.svg</path>
  <color>FFC24B</color>      <!-- der Stern wird golden -->
</image>

Bedingen, übersetzen, regionalisieren

Ein anderer Wert je nach Bildschirm, Maschine oder Sprache.

Eine Bedingung auf einer Eigenschaft

<text name="titre">
  <fontSize if="crt">0.09</fontSize>
  <fontSize if="!crt">0.05</fontSize>
  <color>FFFFFF</color>
</text>

Eine Komponente, zwei Größen je nach Bildschirm. Die Liste der Bedingungen steht auf der Seite Bedingt anzeigen.

Eine Bedingung auf der ganzen Komponente

<image name="filtre" if="crt">
  <path>${root}/data/arts/scanlines.png</path>
</image>

Die Komponente existiert nur, wenn die Bedingung wahr ist. Die vollständige Liste steht in Bedingt anzeigen, und Mehrere Bedingungen kombinieren erklärt und, oder und die Klammern.

ifexists und ifnotexists

Diese beiden prüfen nicht die Maschine, sondern das Vorhandensein einer Datei:

<image name="jaquette">
  <path ifexists="${game.media.imagepath}">${game.media.imagepath}</path>
  <path ifnotexists="${game.media.imagepath}">${root}/images/pas-dimage.png</path>
</image>

Das ist der saubere Weg für Spiele ohne Cover — sonst bleibt das Feld leer.

Einen Text übersetzen

Ein Sprachsuffix auf der Eigenschaft genügt:

<text name="bienvenue">
  <text>Bienvenue</text>
  <text.en>Welcome</text.en>
  <text.es>Bienvenido</text.es>
</text>

Recalbox nimmt die passende Variante — und die suffixlose Version, wenn keine passt.

Was ein Suffix akzeptiert

SuffixWas es anspricht
.fr .es .dedie Sprache der Maschine, in Kleinbuchstaben
.fr_FRdie Sprache und das Land
.US .EU .JPdie Region, in GROSSBUCHSTABEN

Die Region

Damit schreibt man „Genesis“ in den USA und „Mega Drive“ in Europa. Derselbe Mechanismus wie bei der Sprache, mit einem Suffix in Großbuchstaben — genau das nutzt das offizielle Recalbox-Theme:

<box name="fond"
     color.US="2E447C"
     color.EU="7C2E44"
     color.JP="447C2E" />

Die drei Werte sind US, EU und JP. Eine Eigenschaft ohne Suffix gilt für alle Regionen.

⚠️ Es gibt immer eine aktive Region. Auf einer frischen Maschine ist es US: Was du ohne Suffix schreibst, sehen die meisten Leute — .EU oder .JP dienen nur dazu, davon abzuweichen.

Die Region wird auf der Maschine geändert, in den Oberflächeneinstellungen — und Recalbox liest dann das ganze Theme neu, wie bei einer Option. Das Studio bietet dieselbe Wahl, um zu sehen, was jedes Publikum sieht.

Worauf das funktioniert: auf ALLEM

Es gibt keine Liste übersetzbarer Eigenschaften. Das Suffix wird auf jeder Eigenschaft geprüft, bevor die Engine überhaupt weiß, um welche es sich handelt — also akzeptieren es alle:

<text name="titre" text.fr="Bienvenue" text.es="Bienvenido" />
<image name="logo" path.US="genesis.png" path.EU="megadrive.png" />
<text name="mention" fontSize.de="0.03" />        <!-- Deutsch läuft länger -->
<box name="bandeau" color.JP="D62828" />

Beide Schreibweisen unterstützen es — als Attribut (size.fr="…") wie als Unterknoten (<size.fr>…</size.fr>) — und sogar der Tag-Name (<text.fr name="…">). Es gilt auch für title und help einer Option.

⚠️ Die lokalisierte Version gewinnt endgültig. Sobald eine Variante angewendet wurde, wird die suffixlose Version derselben Eigenschaft abgelehnt, auch in einer später gelesenen Datei. Ein Overlay kann eine bereits lokalisierte Eigenschaft also nicht „zurückerobern“: Es muss seine eigene lokalisierte Variante liefern.

Einen Text aus einer Datei laden

text, scrolltext und markdown akzeptieren path anstelle von text: Der Inhalt wird dann aus der Datei gelesen. Praktisch für einen langen Vorstellungstext.

<markdown name="apropos">
  <path>${root}/data/textes/apropos.md</path>
</markdown>

Benennen und wiederverwenden

Der Name einer Komponente, und wie man mehrere auf einmal anlegt.

Zwei Dinge, die man nicht verwechseln darf

<image name="mon-fond">

Zwei Komponenten mit demselben name in derselben Ansicht sind eine: Die zweite ergänzt oder ersetzt die erste. Das ist gewollt — es ist der Overlay-Mechanismus — aber eine Fehlerquelle, wenn man zwei Hintergründe gedankenlos „fond“ nennt.

Mehrere Komponenten auf einmal anlegen

<box name="bande1, bande2, bande3, bande4">
  <size>0.01 1</size>
  <color>FFFFFF20</color>
</box>

Vier Komponenten, dieselben Eigenschaften. Bleibt, jeder weiter unten ihre eigene Position zu geben:

<box name="bande1"><pos>0.90 0</pos></box>
<box name="bande2"><pos>0.92 0</pos></box>

Ändern, ohne alles neu zu schreiben

Da der letzte gewinnt, genügt es, die eine Eigenschaft neu zu deklarieren, die sich ändert:

<include>${root}/views/base.xml</include>

<view name="system">
  <box name="fond"><color>7C2E44</color></box>   <!-- der Rest bleibt erhalten -->
</view>

Alle Komponenten

Was es gibt, und was jede einzelne kann.

Eine Komponente wird über ihren Typ deklariert — den Namen des Tags. Ein Typ, der nicht in dieser Liste steht, wird von Recalbox ignoriert und im Protokoll vermerkt.

Etwas anzeigen

TypWas er macht
textein Text, ein- oder mehrzeilig
scrolltextein Text, der durchläuft, wenn er zu lang ist
markdownein formatierter Text (fett, Überschriften, Listen)
imageein Bild
videoein Video
boxein Farbblock oder ein Verlauf
datetimeein Datum
ratingeine Bewertung, in Sternen
soundein Klang (zeigt nichts an)

Listen und Navigation

TypWas er macht
textlistdie Spieleliste
carouseldas System-Karussell
helpsystemdie Hilfeleiste unten am Bildschirm

Gestaltung der Menüs

Diese neun werden nicht platziert: sie passen das Aussehen der Menüs an, die Recalbox selbst aufbaut.

menuBackground · menuIcons · menuText · menuTextSmall · menuSection · menuSwitch · menuSlider · menuButton · menuSize

Gestaltung der virtuellen Tastatur

keyboard wird ebenfalls nicht platziert: es gibt der Tastatur, die Recalbox für eine Suche oder eine Eingabe öffnet, ihre Farben und ihre Schrift. Eingerichtet wird es unter Globale Komponenten.

Achtung Groß- und Kleinschreibung

Die Namen unterscheiden Groß- und Kleinschreibung. menuswitch funktioniert nicht, es muss menuSwitch heißen. Eine einzige Eigenschaft ist die Ausnahme und wird komplett klein geschrieben: keepratio.


text, scrolltext, markdown

Die drei Arten, Text anzuzeigen.

text — der normale Text (18 Eigenschaften)

<text name="titre">
  <pos>0.06 0.08</pos>
  <size>0.5 0.1</size>
  <text>${system}</text>
  <fontPath>${root}/data/fonts/Exo2.otf</fontPath>
  <fontSize>0.05</fontSize>
  <color>FFFFFF</color>
  <alignment>left</alignment>
  <forceUppercase>true</forceUppercase>
</text>
EigenschaftTypAufgabe
pos size origin rotation rotationOriginPaarPlatzierung — siehe Position, Größe, Ursprung
textTextder Inhalt, Variablen eingeschlossen
pathPfadliest den Inhalt aus einer Datei, statt text
fontPathPfaddie Schrift
fontSizeZahl< 1 = Anteil der Bildschirmhöhe, >= 1 = Pixel
fontStyleTextnormal, bold, italic, bolditalic
colorFarbedie Textfarbe
backgroundColorFarbeein Hintergrund hinter dem Text
alignmentTextsiehe unten
forceUppercaseja/neinalles in Großbuchstaben
lineSpacingZahlder Zeilenabstand, standardmäßig 1.2
multilineja/neinZeilenumbrüche erlauben
zIndexZahldie Tiefe
disabledja/neindie Komponente abschalten

alignment wirkt auf zwei Achsen

Der Wert kombiniert die Horizontale und die Vertikale.

Neun Positionen, dreizehn Schreibweisen — vier Werte sind Synonyme:

PositionSchreibweiseSynonym
oben-linkstopleft
oben-mittigtopcentertop
oben-rechtstopright
mittig-linkscenterleftleft
mittigcenter
mittig-rechtscenterrightright
unten-linksbottomleft
unten-mittigbottomcenterbottom
unten-rechtsbottomright

⚠️ Ein unbekannter Wert behält nicht die vorherige Ausrichtung: er fällt auf mittig-links zurück, den Standardwert.

toplefttopcenter= toptoprightcenterleft= leftcentercenterright= rightbottomleftbottomcenter= bottombottomrightder Text sitzt in seiner `size`-Box — ohne size hat die Ausrichtung nichts, worauf sie wirken kann

Der Text wird innerhalb seiner size-Box ausgerichtet: ohne size hat die Ausrichtung nichts, worauf sie wirken kann.


scrolltext — der durchlaufende Text (16 Eigenschaften)

Dieselben Eigenschaften wie text, ohne multiline und lineSpacing. Der Text läuft horizontal durch, wenn er über seine Box hinausragt.

<scrolltext name="titre-long">
  <size>0.4 0.06</size>
  <text>${game.name}</text>
  <fontSize>0.04</fontSize>
</scrolltext>

Vorbehalten für Werte, deren Länge du nicht kontrollierst — ein Spielname, ein Entwickler.


markdown — der formatierte Text (15 Eigenschaften)

<markdown name="synopsis">
  <pos>0.06 0.5</pos>
  <size>0.4 0.35</size>
  <text>${game.synopsis}</text>
  <fontSize>0.028</fontSize>
  <color>C6CBD8</color>
</markdown>

Dieselben Eigenschaften wie text, ohne fontStyle, backgroundColor und multiline.

Er versteht einfache Formatierung im Text: **fett**, *kursiv*, # Überschrift, Listen mit Bindestrichen. Nützlich für eine Beschreibung oder eine „Über“-Seite.

⚠️ markdown läuft nicht durch: ein Text, der länger ist als seine Box, wird abgeschnitten.


image und video

Ein Bild oder ein Video anzeigen, und sie einfärben.

image (21 Eigenschaften)

<image name="jaquette">
  <pos>0.75 0.4</pos>
  <origin>0.5 0.5</origin>
  <maxSize>0.35 0.4</maxSize>
  <path>${game.media.imagepath}</path>
  <zIndex>30</zIndex>
</image>
EigenschaftTypAufgabe
pos size origin rotation rotationOriginPaarPlatzierung
maxSizePaarMaximalgröße ohne Verzerrung — siehe Position, Größe
keepratioja/neindie Proportionen bewahren (⚠️ komplett klein geschrieben)
pathPfaddie Bilddatei
tileja/neindas Bild als Kacheln wiederholen, statt es zu strecken
colorFarbefärbt das Bild ein (Multiplikation)
colorTop colorBottom colorLeft colorRightFarbeEinfärbung als Verlauf
colorTopLeft colorTopRight colorBottomLeft colorBottomRightFarbeEinfärbung über die vier Ecken
reflectionPaareine Spiegelung unter dem Bild: Anfangs- und Enddeckkraft
zIndex disabledTiefe, Abschalten

Formate

PNG, JPG und SVG. SVG empfohlen für Logos: es bleibt in jeder Größe scharf.

tile — die wiederholte Textur

<image name="grille">
  <size>1 1</size>
  <path>${root}/data/arts/motif.png</path>
  <tile>true</tile>
</image>

Das Bild behält seine Originalgröße und wiederholt sich, bis es die Box füllt.

reflection

<reflection>0.5 0.0</reflection>

Fügt eine umgedrehte Spiegelung unter dem Bild hinzu, von 50 % Deckkraft oben bis 0 % unten.


video (15 Eigenschaften)

<video name="md_video">
  <pos>0.75 0.4</pos>
  <origin>0.5 0.5</origin>
  <maxSize>0.35 0.3</maxSize>
  <delay>1.5</delay>
  <loops>0</loops>
</video>

Dieselben Platzierungseigenschaften wie image, plus:

EigenschaftTypAufgabe
delayZahlSekunden, bevor das Video startet
loopsZahlAnzahl der Wiedergaben; 0 = Endlosschleife
animationsTextder Erscheinungseffekt
linkTextdie Wiedergabe an eine andere Komponente koppeln
reflectionPaardie Spiegelung, wie bei image

video akzeptiert weder tile noch die Einfärbefarben.

Ein delay von ein bis zwei Sekunden verhindert, dass das Video bei jedem Spiel losgeht, an dem man beim Durchblättern der Liste nur vorbeikommt.


box — der Farbblock

Hintergründe, Schleier, Bänder und Verläufe.

Die einfachste Komponente, und eine der nützlichsten: Hintergründe, Schleier, Bänder, Trennlinien. 16 Eigenschaften.

<box name="fond" extra="true">
  <pos>0 0</pos>
  <size>1 1</size>
  <color>101820</color>
  <zIndex>1</zIndex>
</box>
EigenschaftAufgabe
pos size origin rotation rotationOriginPlatzierung
coloreinheitliche Farbe
colorTop colorBottomvertikaler Verlauf
colorLeft colorRighthorizontaler Verlauf
colorTopLeft colorTopRight colorBottomLeft colorBottomRightVerlauf über die vier Ecken
zIndex disabledTiefe, Abschalten

Kein path: eine box zeigt kein Bild an. Für einen Bildhintergrund nimm image.

Der Lesbarkeitsschleier

Der häufigste Anwendungsfall: einen Text über jedem beliebigen Bild lesbar machen.

<box name="voile-du-bas" extra="true">
  <pos>0 0.7</pos>
  <size>1 0.3</size>
  <colorTop>00000000</colorTop>
  <colorBottom>000000C0</colorBottom>
  <zIndex>20</zIndex>
</box>

Von transparent zu 75 % Schwarz: der untere Bildschirmrand verdunkelt sich allmählich, und der Text darüber bleibt lesbar, egal welches Artwork dahinterliegt.

Ein dünnes Band

<box name="filet" extra="true">
  <pos>0.06 0.18</pos>
  <size>0.3 2p</size>
  <color>FFFFFF40</color>
</box>

2p = zwei Pixel hoch, egal bei welcher Auflösung: einer der seltenen Fälle, in denen die Pixeleinheit die richtige Wahl ist.


textlist — die Spieleliste

Die Liste, in der du dein Spiel auswählst: ihre Farben, ihre Markierung, ihre Schrift.

⚠️ Diese Liste wird nicht beliebig platziert. textlist existiert nur in der Spiele-Ansicht, unter dem reservierten Namen gamelist. Anderswo — oder unter einem anderen Namen — wird sie nicht aufgebaut, und eine zweite lässt sich nicht hinzufügen.

Die Eigenschaften (19)

<textlist name="gamelist">
  <pos>0.05 0.2</pos>
  <size>0.4 0.7</size>
  <primaryColor>C6CBD8</primaryColor>
  <secondaryColor>8A92A6</secondaryColor>
  <selectedColor>101820</selectedColor>
  <selectorColor>4FE3C1</selectorColor>
  <selectorHeight>0.055</selectorHeight>
  <fontSize>0.035</fontSize>
  <horizontalMargin>0.01</horizontalMargin>
</textlist>
EigenschaftAufgabe
pos size originPlatzierung
primaryColordie Farbe der Spiele
secondaryColordie Farbe der Ordner
selectedColordie Textfarbe der gewählten Zeile
selectorColordie Farbe der Markierung
selectorImagePathein Markierungs-Bild, statt der Farbe
selectorImageTiledieses Bild als Kacheln wiederholen
selectorHeightdie Höhe der Markierung
selectorOffsetYihr vertikaler Versatz
fontPath fontSizedie Schrift
alignmentdie Ausrichtung der Zeilen
horizontalMarginder linke und rechte Rand
forceUppercasealles in Großbuchstaben
lineSpacingder Zeilenabstand — er ist es, der die Zeilen auseinanderrückt
scrollSoundder Klang beim Durchblättern
zIndexdie Tiefe
Sonic the Hedgehog ▸ Ein Ordner Streets of Rage 2 Golden Axe Gunstar Heroes primaryColor die Spiele secondaryColor die ORDNER (nicht jede zweite Zeile!) selectorColor die Markierung selectedColor der TEXT der gewählten Zeile selectorHeight der klassische Irrtum: zu glauben, secondaryColor wechsle jede zweite Zeile

⚠️ Kein disabled: eine Spieleliste schaltet sich nicht ab.

primaryColor und secondaryColor sind die häufigste Quelle der Verwirrung: die zweite ist nicht die Wechselfarbe jeder zweiten Zeile, sie ist die Farbe der Ordner.


carousel — das System-Karussell

Das Band, das die Systeme vorbeiziehen lässt: Richtung, Logogröße, und der Textmodus.

Das Karussell zeigt die Systeme, Logo für Logo. Es existiert nur in der Systeme-Ansicht, unter dem reservierten Namen systemcarousel, und die Engine baut nur eines. Anderswo, oder unter einem anderen Namen, wird es gar nicht aufgebaut.

type akzeptiert horizontal (Standard), vertical und vertical_wheel — das Rad. Ein horizontales Rad gibt es nicht: jeder andere Wert fällt stillschweigend auf horizontal zurück.

<carousel name="systemcarousel">
  <type>vertical</type>
  <pos>0 0</pos>
  <size>0.25 1</size>
  <color>00000020</color>
  <logoSize>0.12 0.075</logoSize>
  <logoScale>1.5</logoScale>
  <maxLogoCount>7</maxLogoCount>
  <logoAlignment>center</logoAlignment>
  <defaultTransition>instant</defaultTransition>
</carousel>
EigenschaftAufgabe
typehorizontal, vertical, vertical_wheel
pos size originPlatzierung
colorder Hintergrund des Karussells
logoSizedie Größe eines Logos (Paar)
logoScaledie Vergrößerung des gewählten Logos
logoRotation logoRotationOrigindie Rotation der Logos (Räder)
logoAlignmentdie Ausrichtung der Logos in ihrem Feld
maxLogoCountwie viele Logos gleichzeitig sichtbar sind
defaultTransitionfade oder instant; jeder andere Wert ergibt slide
fontPath fontSize fontColordie Schrift des Textmodus
forceUppercasedie Systemnamen in Großbuchstaben
textOnlydie Namen schreiben statt der Logos
primaryColor secondaryColordie Farbe der Namen
selectedColordie Farbe des gewählten Namens
selectorColor selectorHeightdie Markierung des Textmodus
selectorOffsetX selectorOffsetYihr Versatz
textOffsetXder Versatz des Textes
lineSpacing horizontalMarginZeilenabstand und Ränder des Textmodus
zIndexdie Tiefe
color — der Hintergrund des Karussells gewählt logoSize × logoScale maxLogoCount — wie viele sichtbar sind nur das gewählte Logo ist in voller Größe: die anderen sind verkleinert

⚠️ Kein disabled: das Karussell schaltet sich nicht ab.

⚠️ maxLogoCount ist keine Anzahl angezeigter Logos. Es steuert nur Abstand und Zentrierung: die Engine zeichnet mehr davon, die überstehen und abgeschnitten werden. Und der Wert wird auf die ganze Zahl gerundet — eine Dezimalzahl (2.5) ist daher nutzlos.


Im Abschnitt Systemliste wählt „WAS VORBEIZIEHT“ zwischen:

⚠️ Es ist keine vierte Laufrichtung: der Textmodus kombiniert sich mit horizontal, vertikal und Rad. Ein Karussell aus Namen kann also in jede Richtung laufen.

Im Textmodus werden die Schrift, ihre Größe und ihre Farbe im Abschnitt Text eingestellt. Zwei karusselleigene Versätze kommen hinzu:

<carousel name="systemcarousel" type="vertical">
  <textOnly>true</textOnly>
  <textOffsetX>0.02</textOffsetX>
</carousel>

Verfügbar ab Recalbox 10.1. Auf einer älteren Maschine wird textOnly ignoriert und das Karussell zeigt die Logos.


rating — die Sternebewertung

Die Note des Spiels, gezeichnet in Sternen: die zwei Bilder, aus denen sie besteht.

Die Eigenschaften (9)

<rating name="md_rating">
  <pos>0.06 0.72</pos>
  <size>0.12 0.024</size>
  <filledPath>${root}/data/arts/etoile-pleine.svg</filledPath>
  <unfilledPath>${root}/data/arts/etoile-vide.svg</unfilledPath>
</rating>
EigenschaftAufgabe
pos size origin rotation rotationOriginPlatzierung
filledPathdas Bild des vollen Sterns
unfilledPathdas Bild des leeren Sterns
zIndex disabledTiefe, Abschalten

size bezeichnet die Gesamtheit der fünf Sterne. Eine Breite von fünfmal der Höhe ergibt quadratische Sterne.

Keine Farbe: um den Farbton zu ändern, ändere die Bilder — oder liefere weiße Bilder und färbe sie ein… was rating nicht erlaubt. Es braucht also zwei Dateien.


datetime — ein Datum

Das Erscheinungsdatum eines Spiels, oder das der letzten Partie.

Ein datetime zeigt ein Datum, das Recalbox kennt, nie freien Text. Sein Name sagt, welches Datum — md_releasedate das Erscheinen des Spiels, md_lastplayed die letzte Partie — und seine Eigenschaft display sagt, in welcher Form es geschrieben wird.

<datetime name="md_releasedate">
  <pos>0.06 0.66</pos>
  <fontSize>0.028</fontSize>
  <color>C6CBD8</color>
  <display>date</display>
</datetime>

display — die Form des Datums

SchreibweiseWas angezeigt wird
date1991/06/23
dateTime1991/06/23 14:05:30
year1991
time14:05:30
realTimedie aktuelle Uhrzeit — kein Spieldatum
RelativeToNow„vor 3 Tagen“

⚠️ Die Schreibweise zählt. datetime funktioniert nicht, es muss dateTime heißen; relativeToNow auch nicht, es muss RelativeToNow heißen. Ein unbekannter Wert behält die vorherige Form und landet in themes.log.

Die Eigenschaften (12)

EigenschaftAufgabe
pos size originPlatzierung
displaydie Form des Datums
color backgroundColordie Farben
fontPath fontSizedie Schrift
alignment forceUppercasedie Formatierung
zIndex disabledTiefe, Abschalten

⚠️ Ein datetime ohne color ist unsichtbar: es ist die einzige Komponente, die die Farbe auf null setzt, statt die vorherige zu behalten. Und von alignment wird nur der horizontale Teil behalten — vertikal bleibt es immer zentriert.

Ein Spiel ohne Datum zeigt eine leere Zeile: es sind die Daten, die fehlen, nicht das Theme.


sound — die Musik des Themes

Ein Titel, oder ein Ordner voller Titel, abgespielt beim Stöbern.

Ein sound wird nicht gezeichnet: er hat weder Position, noch Größe, noch Tiefe. Er trägt einen Pfad, und sonst nichts.

Zwei Namen, zwei Verhalten:

NameWas die Maschine macht
bgsoundspielt diesen Titel
directorywählt zufällig aus diesem Ordner

⚠️ Die Maschine liest ihn nur in der Systeme-Ansicht. Anderswo platziert, spielt er nie. Dafür kann eine Systemdatei ihn neu definieren: so gibt man eine Musik pro System.

Die eigene Musik des Benutzers, falls vorhanden, hat Vorrang vor der des Themes.


helpsystem — die Hilfeleiste

Die 32 Button-Symbole, eines nach dem anderen.

Die Leiste unten am Bildschirm, die daran erinnert, wozu die Buttons dienen. 38 Eigenschaften: sechs für die Formatierung, und 32 Symbole.

Recalbox entscheidet selbst, was die Leiste ankündigt, Bildschirm für Bildschirm, und übersetzt jede Beschriftung. Dein Theme legt nur die Form fest: die Platzierung, die Schrift, die Farben, und das Bild jedes Piktogramms.

<helpsystem name="help">
  <pos>0.02 0.955</pos>
  <fontPath>${root}/data/fonts/Exo2.otf</fontPath>
  <fontSize>0.025</fontSize>
  <textColor>C6CBD8</textColor>
  <iconColor>FFFFFF</iconColor>
  <iconA>${root}/data/arts/boutons/a.svg</iconA>
  <iconB>${root}/data/arts/boutons/b.svg</iconB>
</helpsystem>

Die Formatierung

EigenschaftAufgabe
pos sizePlatzierung
textColordie Farbe der Beschriftungen
iconColordie Einfärbung der Symbole — liefere sie in Weiß
fontPath fontSizedie Schrift

Die 32 Symbole

Ein Symbol zu ersetzen ist optional: Recalbox bringt seine eigenen mit. Du definierst nur die neu, die du willst.

RichtungeniconUpDown, iconLeftRight, iconUpDownLeftRight

ButtonsiconA, iconB, iconX, iconY

SchultertasteniconL, iconR, iconL2, iconR2, iconL3, iconR3, iconLR, iconL2R2, iconL3R3

SystemiconStart, iconSelect, iconHotkey

Hotkey-KombinationeniconHkA, iconHkB, iconHkX, iconHkY, iconHkL, iconHkR, iconHkLeftRight

JoysticksiconJ1UpDown, iconJ1LeftRight, iconJ1UpDownLeftRight, iconJ2UpDown, iconJ2LeftRight, iconJ2UpDownLeftRight

Eine Kombination sind zwei Piktogramme

Wenn die Hilfe eine Kombination betrifft, zeichnet Recalbox iconHotkey, dann die Taste.

[HK] [A]  Spiel starten

iconHkA ist also das Bild des A-Buttons in einer Kombination — keine Zeichnung von „HK + A“. Setze dort einen schlichten Button hin: das Kürzel steht schon davor.

iconHotkey zählt doppelt: es erscheint vor jeder Kombination der Leiste. Es ist das Symbol, das du zuerst polieren solltest, wenn dein Theme welche zeigt.

Der Name ist vorgegeben: help

Recalbox sucht das Bauteil namens help, und nur dieses. <helpsystem name="barre"> wird in deiner Datei existieren, ohne je etwas zu steuern.

Die Leiste wird Ansicht für Ansicht eingerichtet

Recalbox liest das <helpsystem> der Ansicht bei jedem Bildschirmwechsel neu, und beginnt wieder bei seinen eigenen Symbolen. Was eine Ansicht nicht deklariert, fällt daher auf Recalbox' Standard zurück — nie auf das, was eine andere Ansicht eingestellt hatte.

Zwei Wege:

Liefere weiße Symbole und nutze iconColor: ein einziger Dateisatz genügt dann für alle Farbvarianten deines Themes.

Mehrere Symbolsätze anbieten

Das machen die großen Themes: ein SNES-Satz, ein Xbox-Satz, ein PlayStation-Satz… und der Benutzer wählt in Menü → Oberfläche → Theme.

Jeder Satz ist eine Datei, die nur das <helpsystem> und seine Bilder enthält:

<!-- ./options/icones-snes.xml -->
<theme>
  <view name="system, detailed, menu">
    <helpsystem name="help">
      <iconA>${root}/data/icones/snes/a.svg</iconA>
      <iconB>${root}/data/icones/snes/b.svg</iconB>
    </helpsystem>
  </view>
</theme>

Und angeboten werden sie so, ohne irgendetwas anderes zu deklarieren:

<include subset="iconset" name="1 - SNES">${root}/options/icones-snes.xml</include>
<include subset="iconset" name="2 - Xbox">${root}/options/icones-xbox.xml</include>

iconset ist ein reservierter Name: Recalbox zeigt „SELECT THEME'S ICONSET“, übersetzt in die Sprache der Maschine. Kein <subset>-Tag ist nötig, um ihn zu benennen.


Die Gestaltung der Menüs

Die neun Komponenten, die Recalbox' Menüs anpassen.

Recalbox baut seine Menüs selbst: ihr Inhalt gehört nicht dir. Das Theme passt nur ihr Aussehen an, über neun Komponenten, die nicht platziert werden.

menuBackground (3)

<menuBackground>
  <color>101820F0</color>
  <path>${root}/data/arts/cadre-menu.png</path>
  <fadePath>${root}/data/arts/voile.png</fadePath>
</menuBackground>
EigenschaftAufgabe
colordie Farbe des Rahmens — sie färbt das Bild ein, wenn path angegeben ist
pathdas Bild des Rahmens
fadePathdas Schleierbild, das die Ansicht dahinter verdunkelt

menuText (6) — die Menüzeilen

EigenschaftAufgabe
fontPath fontSizedie Schrift
colorder Text der Zeilen
selectedColorder Text der gewählten Zeile
selectorColordie Markierung
separatorColordie Linien zwischen den Zeilen

menuTextSmall (5) — der kleine Text

fontPath, fontSize, color, selectedColor, selectorColor. Verwendet für Einstellwerte und Auswahllisten.

menuSection (5) — die Abschnittstitel

fontPath, fontSize, color, selectedColor, alignment.

menuSize (1)

<menuSize><height>0.85</height></menuSize>

Die maximale Höhe des Menürahmens, als Anteil des Bildschirms. Es ist das einzige Maß, das ein Theme den Menüs vorschreibt.

menuSwitch (2) — die Schalter

pathOn, pathOff — die zwei Bilder einer Ja/Nein-Einstellung.

menuSlider (1) — die Schieberegler

path — das Bild des Reglers.

menuButton (2) — die Buttons

path, filledPath — der normale und der gedrückte Zustand.

menuIcons (23) — die Abschnittssymbole

Ein Symbol pro Menüabschnitt:

iconSystem · iconUpdates · iconThemes · iconGames · iconUI · iconTate · iconControllers · iconSound · iconNetwork · iconScraper · iconBios · iconDownload · iconLicense · iconAdvanced · iconArcade · iconKodi · iconCardReader · iconRecalboxRGBDual · iconQuit · iconRestart · iconShutdown · iconFastShutdown · iconList

⚠️ iconList steht im Singular, anders als der Abschnitt „Listen“, den es vertritt. Im Plural wird es ignoriert.


Die Gestaltung der virtuellen Tastatur

Die Farben und die Schrift der Tastatur, die sich öffnet, um ein Spiel zu suchen oder einen Text einzugeben.

Wie die Menüs wird sie nicht platziert: die Tastatur bestimmt ihre eigene Geometrie, das Theme wählt nur ihre Farben und ihre Schrift.

Sie öffnet sich über dem Bildschirm, auf dem du bist, egal welcher — eingerichtet wird sie also ein einziges Mal, unter Globale Komponenten.

EigenschaftWas sie färbt
keyColorder Hintergrund jeder Taste in Ruhe
keySelectedColordie Taste, auf der du stehst
keyTextColorder Buchstabe auf der Taste
keyDisabledColorder Buchstabe eines Zeichens, das die Eingabe ablehnt
keyModifierColorUmschalt / Strg / Alt gedrückt für eine einzelne Taste
keyModifierLockedColorUmschalt / Strg / Alt festgestellt
keyTitleColorder Titel über der Tastatur
keyEditTextColorder Text, der gerade getippt wird
fontPathdie Schrift — die Größe bestimmt weiterhin die Tastatur

Drei Tastaturen, und der Benutzer wählt

Das Theme entscheidet nicht, welche erscheint: das ist eine Einstellung der Konsole. Und nicht alle lesen deine Farben.

Stelle also zuerst die vier ein, die alle lesen: deine Gestaltung hält dann, egal welche Tastatur.

Was es schreibt

<view name="system, basic, detailed, menu, gameclip">
    <keyboard name="keyboard">
        <keyColor>1B1D22</keyColor>
        <keySelectedColor>4FE3C1</keySelectedColor>
        <keyTextColor>FFFFFF</keyTextColor>
        <keyTitleColor>FFFFFF</keyTitleColor>
        <keyEditTextColor>FFFFFF</keyEditTextColor>
    </keyboard>
</view>

Der name muss exakt keyboard sein, und es akzeptiert weder pos noch size.

Verfügbar ab Recalbox 10.1. Auf einer älteren Maschine wird der Block ignoriert und die Tastatur behält ihre Werksfarben.


⚠️ Die wichtigste Regel

Warum deine Komponente nicht erscheint.

Das ist die Ursache von „ich habe mein Bild platziert und sehe es nicht“.

Eine Ansicht zeichnet nur zwei Dinge:

  1. ihre reservierten Komponenten, die sie selbst aufbaut;
  2. die mit extra="true" markierten Komponenten.

Eine freie Komponente ohne extra erscheint nie.

extra="true" → gezeichnet deine Komponente ohne extra → unsichtbar nichts die Engine zeichnet nur ihre reservierten Komponenten + die mit extra markierten
<view name="system">
  <image name="mon-decor" extra="true">      <!-- ✅ wird angezeigt -->
    <path>${root}/data/arts/decor.png</path>
  </image>

  <image name="autre-decor">                  <!-- ❌ unsichtbar -->
    <path>${root}/data/arts/decor.png</path>
  </image>
</view>

Die andere, gleichwertige Schreibweise ist, sie zu gruppieren:

<view name="system">
  <extras>
    <image name="mon-decor"> … </image>
    <text name="ma-legende"> … </text>
  </extras>
</view>

Nur SECHS Typen können frei platziert werden

Die Fabrik der freien Komponenten kann nur diese bauen:

✅ Als extra verwendbar❌ Abgelehnt
image · box · video · text · scrolltext · markdowntextlist · carousel · datetime · rating · sound · helpsystem · keyboard · container · ninepatch · alle menu*

Ein abgelehnter Typ schreibt Extra type unknown: Rating ins Protokoll und nichts wird gezeichnet.

➡️ rating, datetime, textlist und carousel werden nur unter ihrem reservierten Namen verwendet, in einer Ansicht, die sie vorsieht. Du kannst keine zweite Bewertung oder eine zweite Liste hinzufügen.

➡️ ninepatch hat nirgends einen reservierten Namen: als freie Komponente abgelehnt, und keine Ansicht baut ihn. Er ist daher in der Praxis unbrauchbar, obwohl er in der Engine vorhanden ist.

➡️ container wird ebenfalls nicht platziert, aber er ist nicht nutzlos: die Engine wendet ihn über einer anderen Komponente an. In der Spieleliste stellt md_description, als <text> deklariert, zugleich den scrollenden Rahmen darum ein — pos, size und zIndex gehen an den Rahmen, der Rest an den Text. Du schreibst ihn nie selbst.

Drei weitere Grenzen

Die Ausnahme

helpsystem funktioniert weiter, selbst in einem <extras>-Block geschrieben: die Ansicht findet es über seinen Namen wieder. Die Warnung im Protokoll ist folgenlos.


Die system-Ansicht — die Maschinen

Das Karussell, das Logo, die Informationszeile.

Der erste Bildschirm: die Liste deiner Maschinen.

Die reservierten Komponenten

NameTypAufgabe
systemcarouselcarouseldas Karussell — nur eines, nicht umbenennbar
logoimagedas Logo des Systems im Karussell
systemInfotextdie Zeile „510 Spiele verfügbar, 13 Favoriten“
bgsoundsounddie Hintergrundmusik des Themes
directorysoundder Musikordner des Themes

bgsound und directory sind die einzigen Namen, die <sound> akzeptiert, und nur in dieser Ansicht.

Zwei Fallen

systemInfo hat standardmäßig einen grauen Hintergrund. Um ihn zu entfernen:

<text name="systemInfo">
  <backgroundColor>00000000</backgroundColor>
</text>

Das Karussell ist einmalig. Ein zweites <carousel> wird ohne Fehler gelesen, aber nie gezeichnet.

Wenn das Theme kein Logo liefert, sucht Recalbox sein eigenes in dieser Reihenfolge:

<system>-<sprache_LAND>.svg   →   <system>-<sprache>.svg
      →   <system>-<region>.svg   →   <system>.svg

Das ermöglicht ein „Genesis“-Logo in den USA und „Mega Drive“ in Europa, ohne irgendetwas zu schreiben.

Das Karussell im Detail

EigenschaftStandardGenauer
typehorizontalhorizontal, vertical, vertical_wheel; jeder andere Wert fällt auf horizontal zurück
logoSizeberechnetVerhältnis zum Bildschirm, nicht zum Karussell
logoScale1.2Vergrößerung des gewählten Logos
maxLogoCount3auf die ganze Zahl gerundet — eine Dezimalzahl bringt nichts
colortransparentder Hintergrund des Karussells

Der Abstand der Logos berechnet sich so:

abstand = (laenge − logoSize × maxLogoCount) / maxLogoCount + logoSize

wobei laenge vertikal size.y ist, horizontal size.x.


Die detailed-Ansicht — die Spiele

Die Liste, die Spielkarte, und ihre dreißig reservierten Komponenten.

Die Spieleliste eines Systems, mit der Karte des markierten Spiels.

Es ist die Ansicht aller Spielelisten: die basic-Ansicht wird von der Engine nie angefordert, und die Arcade-Ansicht verwendet detailed wieder.

Die Liste und die Medien

NameTypAufgabe
gamelisttextlistdie Spieleliste
logoimagedas Logo des Systems
md_imageimagedas Cover
default_image_pathimagedas Ersatzbild, wenn das Spiel kein Cover hat
md_videovideodas Vorschauvideo
md_region1md_region4imagedie vier Regionsflaggen des Spiels

Bei md_image wird der im Theme geschriebene path ignoriert: das Bild kommt vom Spiel. Bei den md_region* werden nur pos, size, zIndex und path gelesen.

Die Informationen des Spiels

NameTyp
md_descriptiontext, markdown oder scrolltext — nach Wahl
md_folder_nametext
md_ratingrating
md_releasedate, md_lastplayeddatetime
md_developer, md_publisher, md_genre, md_players, md_playcount, md_favoritetext

Die Beschriftungen

md_lbl_rating, md_lbl_releasedate, md_lbl_developer, md_lbl_publisher, md_lbl_genre, md_lbl_players, md_lbl_lastplayed, md_lbl_playcount, md_lbl_favorite

⚠️ Ihr Text ist vorgegeben. Recalbox schreibt „Bewertung:“, „Erschienen:“, „Entwickler:“… übersetzt in die Sprache der Maschine, nachdem das Theme angewendet wurde. Ein text= im Theme wird überschrieben. Du stellst ihre Formatierung ein, nie ihren Inhalt.

Ebenso akzeptieren die md_*-Werte alle Eigenschaften außer text: ihr Inhalt kommt vom Spiel.

Die Farben der Liste

gamelist verwendet fünf Farben, von denen drei nicht durch das Theme gestaltbar sind:

ZeileFarbe
ein SpielprimaryColor
ein OrdnersecondaryColor
ein abgeblendetes Spielberechnet: primaryColor mit halbierter Deckkraft
ein abgeblendeter Ordnerebenso berechnet
der Hintergrund einer Sortierüberschriftvorgegeben

Vorhandene, aber wirkungslose Komponenten

template_flag, template_genre und template_players werden von der Engine gelesen, aber nie verwendet: die Farben der Verzierungen sind nicht gestaltbar. Verliere keine Zeit damit.


Die gameclip-Ansicht — der Bildschirmschoner

Was erscheint, wenn die Maschine nichts tut.

Der Bildschirmschoner spielt Spielausschnitte ab. Das Theme kleidet ihn drumherum ein.

Was gestaltbar ist

Diese Ansicht wird fast vollständig aus deinen Extras aufgebaut: platziere deine Komponenten mit extra="true" und sie erscheinen.

Nur eine reservierte Komponente ist hier gestaltbar: das Video. Die Informationskomponenten (md_rating, md_developer, md_genre…) existieren in dieser Ansicht, sind aber themeseitig deaktiviert: anders als in detailed kannst du sie nicht formatieren.

➡️ Um den Namen oder den Entwickler des Spiels im Bildschirmschoner anzuzeigen, platziere deine eigenen text mit den Variablen:

<view name="gameclip">
  <extras>
    <text name="titre">
      <pos>0.06 0.85</pos>
      <text>${game.name}</text>
      <fontSize>0.05</fontSize>
      <color>FFFFFF</color>
    </text>
    <text name="editeur">
      <pos>0.06 0.91</pos>
      <text>${game.developer} · ${game.releasedate}</text>
      <fontSize>0.03</fontSize>
    </text>
  </extras>
</view>

Die Spielvariablen funktionieren hier

Der Kontext dieser Ansicht enthält das System UND das Spiel: alle ${game.*} werden aufgelöst. Das macht den Bildschirmschoner interessant zum Einkleiden.


Die menu-Ansicht — die Menüs

Was ein Theme an den Menüs ändern kann, und was nicht.

Recalbox baut seine Menüs selbst: ihr Inhalt, ihre Reihenfolge und ihre Beschriftungen gehören nicht dir.

Was das Theme liefert, sind Stile — und ein einziges Maß.

<view name="menu">
  <menuBackground>
    <color>101820F0</color>
    <path>${root}/data/arts/cadre.png</path>
  </menuBackground>

  <menuText>
    <fontPath>${root}/data/fonts/Exo2.otf</fontPath>
    <fontSize>0.038</fontSize>
    <color>C6CBD8</color>
    <selectedColor>101820</selectedColor>
    <selectorColor>4FE3C1</selectorColor>
    <separatorColor>FFFFFF20</separatorColor>
  </menuText>

  <menuSize><height>0.85</height></menuSize>
</view>

Die neun verfügbaren Komponenten sind in Die Gestaltung der Menüs beschrieben.

Was du nicht tun kannst

Woran du denken solltest

Die Menüs erscheinen über der aktuellen Ansicht. Der Schleier (fadePath von menuBackground) verdunkelt, was dahinterliegt: ohne ihn wird ein Menü mit transparentem Hintergrund auf einem hellen Theme unlesbar.


Eine Ebene auf allen Ansichten

Ein gemeinsames Dekor, einmal geschrieben, statt in jede Ansicht kopiert.

Das Problem

Ein CRT-Schleier, ein Markenlogo, ein Rahmen: du willst ihn auf der Systemliste und auf der Spieleliste und auf dem Menü. Ihn in jede Ansicht zu kopieren funktioniert… bis zu dem Tag, an dem du nur einen davon änderst. Die anderen bleiben zurück, und nichts weist darauf hin.

Die Lösung

Rechtsklick auf die Ebene (oder das des Inspektors) → „Auf allen Ansichten vorhanden“.

Die Ebene verlässt ihre Ansicht und wechselt zu den gemeinsamen Ebenen: es gibt nur noch eine einzige, geteilte. Sie von irgendwo einzustellen, stellt sie überall ein.

Um zurückzugehen: „Nur auf dieser Ansicht behalten“.

Was das ins Theme schreibt

Ein einziger Block, dessen Name die Ansichten auflistet:

<!-- global.xml -->
<view name="system, basic, detailed, menu, gameclip">
    <extras>
        <image name="voileCRT" extra="true">…</image>
    </extras>
</view>

Die Maschine zerlegt diesen Namen an den Kommas und setzt das Element in jede Ansicht. Die Datei wird vor den Ansichten geladen: was überall gilt, ist ein Sockel, den eine Ansicht noch korrigieren kann.

Nicht zu verwechseln

„In ein anderes Layout duplizieren…“ ist etwas anderes: es kopiert die Ebene in ein anderes Layout derselben Ansicht (zum Beispiel „Vertikal links“ und „Horizontal“), und die zwei Kopien sind danach unabhängig.

⚠️ Der Ansichtsname menu wird geschrieben, weil das Theme es verlangt, aber die Engine liest dort keine freie Komponente: die Ebene ist in den Menüs nicht zu sehen.

Beim Import findet ein Theme, das bereits einen Block über alle Ansichten schreibt, seine gemeinsame Ebene wieder. Ein Block, der nur einen Teil abdeckt, bleibt pro Ansicht aufgeteilt: er gilt nur dort, wo das Theme ihn hingesetzt hat.


Variablen verwenden

Den Namen eines Spiels anzeigen, ein Bild je nach System wählen.

Eine Variable wird ${…} geschrieben und Recalbox ersetzt sie beim Anzeigen.

<text name="titre">
  <text>Bienvenue sur ${system}</text>
</text>

→ „Bienvenue sur Super Nintendo“.

In einem Bildpfad: am nützlichsten

<image name="console" extra="true">
  <path>${root}/data/arts/consoles/${system.name}.png</path>
</image>

Eine einzige Zeile, und jedes System zeigt sein eigenes Bild. Die Dateien müssen nur den internen Namen des Systems tragen: snes.png, megadrive.png

Wo jede Variable funktioniert

Das ist die Regel, die am meisten überrascht, und sie kommt aus der Engine:

FamilieAnsichten, in denen sie aufgelöst wird
${system…}Systeme und Spieleliste — eine Liste gehört immer zu einem System
${game…}Spieleliste und Bildschirmschoner — dort, wo es ein markiertes Spiel gibt
${recalbox…} ${settings…} ${hardware…} ${display…}überall

Eine Variable, die dort verwendet wird, wo sie nicht existiert, wird nicht ersetzt: der rohe Text erscheint unverändert, ${game.name} eingeschlossen. Das Studio bietet nur die an, die auf der aktuellen Ansicht funktionieren.

Wenn die markierte Zeile kein Spiel ist

In der Spieleliste durchläuft der Cursor nicht nur Spiele: Er landet auch auf Ordnern und auf Sortier-Überschriften, jenen Zwischentiteln, die Recalbox einfügt, sobald die Liste anders als alphabetisch sortiert ist. Die ${game…} antworten weiterhin, beschreiben dann aber eine Zeile ohne Spiel:

Markierte Zeile${game.name}${game.releasedate}${game.file.name}
ein Spielsein Namesein Erscheinungsdatumdie Rom-Datei
ein Ordnerder OrdnernameUNBEKANNTder Ordnername
eine Sortier-ÜberschriftnichtsUNBEKANNTnichts

Ein Bauteil, das Spieldaten anzeigt, hat auf diesen Zeilen also nichts mehr zu sagen — und bleibt trotzdem auf dem Bildschirm, über dem Ordnernamen, den Recalbox im selben Moment schreibt. Beschränken Sie es auf Spielzeilen:

<text name="sortie" extra="true" showIf="game">
  <text>Erschienen: ${game.releasedate}</text>
</text>

Das Studio übernimmt das: Sobald ein Bauteil Spieldaten verwendet, wechselt seine Sichtbarkeit auf „ein Spiel“. Über den Reiter Sichtbarkeit des Bauteils lässt sie sich jederzeit wieder für Ordner und Überschriften öffnen.

${root} — nie vergessen

${root} bezeichnet die Wurzel des ausgewählten Themes. Ohne ihn sind die Pfade relativ zur Datei, die sie schreibt, und dein Theme geht kaputt, sobald es anders abgelegt wird.

<path>${root}/data/arts/fond.jpg</path>     <!-- ✅ -->
<path>../data/arts/fond.jpg</path>          <!-- zerbrechlich -->

Die alten $…-Variablen

In alten Themes wirst du Variablen ohne Klammern begegnen:

AltWas sie ergibtAktuelles Äquivalent
$systemder kurze Name — „snes“${system.name}
$themeder Ordner des Themes${root}

⚠️ $system und ${system} ergeben nicht dasselbe: die erste liefert „snes“, die zweite „Super Nintendo“. Sie werden noch akzeptiert, sind aber veraltet: schreibe nur noch die Form mit Klammern.

Die Zufallsauswahl

<path>${random.between(fond1.jpg,fond2.jpg,fond3.jpg)}</path>
<fontSize>${random.range(1,10)}</fontSize>

random.between wählt zufällig einen Wert aus der Liste, random.range eine Zahl zwischen zwei Grenzen. Die Auswahl findet beim Laden des Themes statt, nicht bei jeder Anzeige.


Alle Variablen

Die vollständige Liste, und wo jede funktioniert.

Hier sind alle Variablen, die Recalbox ersetzen kann, erhoben aus der Engine.

Eine Variable wird ${…} geschrieben, und Recalbox ersetzt sie beim Anzeigen.

Das System

SchreibweiseWas es istWas sie liefertWo
${system}Name des SystemsDer vollständige Name — z. B. „Sega Megadrive“Systeme, Spiele
${system.input.keyboard}Tastatur nötig?mandatory · recommended · optional · noSysteme, Spiele
${system.input.mouse}Maus nötig?mandatory · recommended · optional · noSysteme, Spiele
${system.input.pad}Controller nötig?mandatory · recommended · optional · noSysteme, Spiele
${system.logo}Logo des SystemsDer Pfad des von Recalbox gelieferten LogosSysteme, Spiele
${system.manufacturer}HerstellerZ. B. „Sega“, „Nintendo“. Leer, wenn unbekanntSysteme, Spiele
${system.name}Kurzname des SystemsSysteme, Spiele
${system.releasedate}ErscheinungsjahrJahr und Monat — z. B. „1988-10“Systeme, Spiele
${system.type}Maschinentyp (technischer Name)arcade · console · handheld · computer · engine · port · fantasy · virtual · virtual-arcadeSysteme, Spiele
${system.type.name}MaschinentypDerselbe, im Klartext: „Home Console“, „handheld Console“, „Arcade“…Systeme, Spiele

Das Spiel

SchreibweiseWas es istWas sie liefertWo
${game.developer}EntwicklerZ. B. „Konami“. „UNKNOWN“, wenn nicht vorhandenBildschirmschoner, Spiele
${game.file.name}DateinameDer Dateiname, Erweiterung eingeschlossenBildschirmschoner, Spiele
${game.file.path}Vollständiger DateipfadDer vollständige Pfad der DateiBildschirmschoner, Spiele
${game.file.stem}Dateiname (ohne Erweiterung)Der Dateiname, ohne ErweiterungBildschirmschoner, Spiele
${game.genre.normalized}Genre (technischer Name)Das normalisierte Genre, auf Englisch — „Platform“, „Shoot’em Up“, „Racing“…Bildschirmschoner, Spiele
${game.genre.raw}GenreDas Genre so, wie es in der Spielkarte stehtBildschirmschoner, Spiele
${game.isadult}Nur für Erwachsene?yes oder noBildschirmschoner, Spiele
${game.isfavorite}Ist ein Favorit?yes oder no (nie true/false)Bildschirmschoner, Spiele
${game.ishidden}Ist versteckt?yes oder noBildschirmschoner, Spiele
${game.islastversion}Ist die neueste Version?yes oder noBildschirmschoner, Spiele
${game.isnotagame}Ist kein Spiel?yes oder noBildschirmschoner, Spiele
${game.ispreinstalled}Ist vorinstalliert?yes oder noSpiele, Bildschirmschoner
${game.license}LizenzDie Lizenz, oft leerBildschirmschoner, Spiele
${game.name}Name des SpielsDer Name des SpielsBildschirmschoner, Spiele
${game.players}Anzahl der Spieler„1“, „2“, „1-4“, „4+“…Bildschirmschoner, Spiele
${game.players.max}Spieler — MaximumEine Zahl — z. B. „4“Bildschirmschoner, Spiele
${game.players.min}Spieler — MinimumEine Zahl — z. B. „1“Bildschirmschoner, Spiele
${game.publisher}HerausgeberZ. B. „Sega“. „UNKNOWN“, wenn nicht vorhandenBildschirmschoner, Spiele
${game.releasedate}ErscheinungsdatumISO-Datum — z. B. „1991-06-23“. „UNKNOWN“, wenn nicht vorhandenBildschirmschoner, Spiele
${game.synopsis}BeschreibungDer Vorstellungstext, oft langBildschirmschoner, Spiele

Bewertung und Statistiken

SchreibweiseWas es istWas sie liefertWo
${game.lastplayed}Letzte PartieISO-Datum, oder „NEVER“, wenn nie gespieltBildschirmschoner, Spiele
${game.rating.10}Bewertung (von 10)Eine ganze Zahl von 0 bis 10Bildschirmschoner, Spiele
${game.rating.100}Bewertung (von 100)Eine ganze Zahl von 0 bis 100Bildschirmschoner, Spiele
${game.rating.5}Bewertung (von 5)Eine ganze Zahl von 0 bis 5 — keine SterneSpiele, Bildschirmschoner
${game.timesplayed}Anzahl der PartienEine Anzahl von PartienBildschirmschoner, Spiele
${game.totalplayed}Gesamte SpielzeitEine Dauer — z. B. „3h 12m“. „NONE“, wenn nullBildschirmschoner, Spiele

Bilder und Video des Spiels

SchreibweiseWas es istWas sie liefertWo
${game.media.boxpath}Verpackung (Box Art)Spiele, Bildschirmschoner
${game.media.imagepath}Cover / BildDer Pfad des Covers. Leer, wenn das Spiel keines hat — siehe ifexistsBildschirmschoner, Spiele
${game.media.thumbpath}MiniaturbildDer Pfad des MiniaturbildsBildschirmschoner, Spiele
${game.media.videopath}VideoDer Pfad des VideosBildschirmschoner, Spiele

Datenträger des Spiels

SchreibweiseWas es istWas sie liefertWo
${game.support.index}Index des DatenträgersDie Nummer der Disc — leer, wenn es nur eine gibtBildschirmschoner, Spiele
${game.support.number}Nummer des DatenträgersAlles zusammengesetzt — z. B. „2A/3“Bildschirmschoner, Spiele
${game.support.side}Seite des DatenträgersDie Seite des Datenträgers — A, B…Bildschirmschoner, Spiele
${game.support.total}Anzahl der DatenträgerDie Anzahl der Datenträger. „UNKNOWN“, wenn unbekanntBildschirmschoner, Spiele
${game.support.type}Art des DatenträgersCartridge · CD/DVD · Harddisk · Files · Tape · Quick Disc · 3" Floppy · 3".5 Floppy · 5".25 Floppy · PCB · UnknownBildschirmschoner, Spiele

System des Spiels

SchreibweiseWas es istWas sie liefertWo
${game.system}Name des Systems des SpielsDer vollständige Name des Systems des SpielsBildschirmschoner, Spiele
${game.system.input.keyboard}Vom System des Spiels verlangte Tastaturmandatory · recommended · optional · noBildschirmschoner, Spiele
${game.system.input.mouse}Vom System des Spiels verlangte Mausmandatory · recommended · optional · noBildschirmschoner, Spiele
${game.system.input.pad}Vom System des Spiels verlangter Controllermandatory · recommended · optional · noBildschirmschoner, Spiele
${game.system.logo}Logo des Systems des SpielsDer Pfad seines LogosBildschirmschoner, Spiele
${game.system.manufacturer}Hersteller des Systems des SpielsSein HerstellerBildschirmschoner, Spiele
${game.system.name}Kurzname des Systems des SpielsSein interner NameBildschirmschoner, Spiele
${game.system.releasedate}Jahr des Systems des SpielsSein ErscheinungsjahrBildschirmschoner, Spiele
${game.system.type}Typ des Systems des Spiels (technischer Name)Wie ${system.type}: console · handheld · arcade…Bildschirmschoner, Spiele
${game.system.type.name}Typ des Systems des SpielsDerselbe, im KlartextBildschirmschoner, Spiele

Emulator

SchreibweiseWas es istWas sie liefertWo
${game.emulator.compatibility}Kompatibilitätunknown · low · average · good · high · perfectBildschirmschoner, Spiele
${game.emulator.extensions}Unterstützte ErweiterungenDie unterstützten Erweiterungen — z. B. „.bin .gen .md“Bildschirmschoner, Spiele
${game.emulator.hasnetplay}Online-Spiel möglich?yes oder noBildschirmschoner, Spiele
${game.emulator.hassoftpatching}Akzeptiert Patches?yes oder noSpiele, Bildschirmschoner
${game.emulator.islibretro}Ist ein Libretro-Kern?yes oder noBildschirmschoner, Spiele
${game.emulator.name}Name des EmulatorsZ. B. „libretro picodrive“Bildschirmschoner, Spiele
${game.emulator.speed}Geschwindigkeitunknown · low · average · good · high · perfectBildschirmschoner, Spiele

Die Maschine und ihre Einstellungen

SchreibweiseWas es istWas sie liefertWo
${display.overscan}Overscan?yes oder noBildschirmschoner, Systeme, Menü, Spiele
${random.between(a,b,c)}Ein zufälliger Wert aus…einer der angegebenen Werteüberall
${random.range(1,10)}Eine Zufallszahl zwischen…eine ganze Zahl zwischen den beiden Grenzenüberall
${display.resolution}Auflösungfhd (1080p und mehr) · hd (720p) · vga · qvgaBildschirmschoner, Systeme, Menü, Spiele
${display.tate}Hochkant-Bildschirm (TATE)?yes oder noBildschirmschoner, Systeme, Menü, Spiele
${display.tateleft}Hochkant nach links?yes oder noSysteme, Menü, Spiele, Bildschirmschoner
${display.tateright}Hochkant nach rechts?yes oder noBildschirmschoner, Systeme, Menü, Spiele
${hardware.board}MaschinenmodellDas Modell — „RPi 5“, „PC x64“, „RG351P/M“…Bildschirmschoner, Systeme, Menü, Spiele
${hardware.crt}CRT-Bildschirm?yes oder noMenü, Spiele, Bildschirmschoner, Systeme
${hardware.isanbernic}Ist es ein Anbernic?yes oder noBildschirmschoner, Systeme, Menü, Spiele
${hardware.isodroid}Ist es ein Odroid?yes oder noBildschirmschoner, Systeme, Menü, Spiele
${hardware.ispc}Ist es ein PC?yes oder noBildschirmschoner, Systeme, Menü, Spiele
${hardware.ispi}Ist es ein Raspberry Pi?yes oder noBildschirmschoner, Systeme, Menü, Spiele
${hardware.jamma}Jamma-Automat?yes oder noSysteme, Menü, Spiele, Bildschirmschoner
${recalbox.built}Build-DatumDas Build-DatumBildschirmschoner, Systeme, Menü, Spiele
${recalbox.version}Recalbox-VersionZ. B. „10.0“Bildschirmschoner, Systeme, Menü, Spiele
${root}Ordner des ThemesDie Wurzel des ausgewählten Themes — vor alle deine Pfade zu setzenMenü, Spiele, Bildschirmschoner, Systeme
${settings.language}SpracheDie Sprache allein — z. B. „fr“Bildschirmschoner, Systeme, Menü, Spiele
${settings.locale}Sprache und LandSprache und Land — z. B. „fr_FR“Bildschirmschoner, Systeme, Menü, Spiele
${settings.region}Gewählte Regioneu · us · jpBildschirmschoner, Systeme, Menü, Spiele
${settings.timezone}ZeitzoneZ. B. „Europe/Paris“Bildschirmschoner, Systeme, Menü, Spiele

Deine maßgeschneiderten Variablen

Deine eigenen benannten Werte — eine Farbe, eine Schrift — erstellt im Studio.

Die Variablen der vorherigen Seite sind die von Recalbox: ${system}, ${game.developer}… Sie werden geliefert, du verwendest sie nur.

Diese hier sind deine. Du gibst einem Wert einen Namen — einer Farbe, einer Schrift, einem Pfad — du verwendest diesen Namen überall, und an dem Tag, an dem du den Wert änderst, folgt das ganze Theme. Das macht die Farboptionen möglich: eine Wahl definiert die Variable neu, und sonst nichts.

Sie im Studio erstellen

  1. öffne Variablen in der Werkzeugleiste: das Panel öffnet sich rechts;
  2. + Neue Variable, gib ihr einen Namen, und sage, was es ist — eine Farbe (du bekommst den Farbwähler, Transparenz eingeschlossen), eine Schrift (gewählt aus denen des Themes), oder ein anderer Wert (ein Text, ein Pfad, oder eine andere Variable);
  3. in einem Farbfeld bietet das kleine { } neben dem Feld deine an, und in der Schriftenliste erscheinen sie ganz oben.

Das Studio zeigt unter dem Feld den berechneten Wert: eine Variable, die eine andere verwendet, lässt sich auf einen Blick lesen.

Von Hand, ohne das Studio

Sie werden in einem <variables>-Block geschrieben. Das Tag, die Namensregeln, der Geltungsbereich und die Bedingungen werden auf Deine eigenen Variablen erklärt, in „Die Struktur eines Themes“.


Bedingt anzeigen

Die 26 Bedingungen: die Maschine, der Bildschirm, und das angezeigte System.

Eine if=-Bedingung lässt eine Komponente nur in bestimmten Fällen erscheinen.

<image name="fond" if="crt">…</image>

Sie lassen sich mit ! (nicht), & (und), | (oder) kombinieren — oder, wenn du Wörter bevorzugst, not, and, or: if="crt and not tate". Siehe Mehrere Bedingungen kombinieren.

⚠️ Ein Bezeichner, der in dieser Liste fehlt, wird von Recalbox ignoriert und in themes.log als unbekannt gemeldet.

Überall — die Maschine und der Bildschirm

BedingungWahr, wenn…
hd fhd vga qvgader Bildschirm diese Auflösung hat
crtder Bildschirm eine Bildröhre ist
overscandas Bild übersteuert (CRT ohne Jamma)
tate tateleft taterightder Bildschirm vertikal steht
jamma bartopdie Maschine ein Arcade-Automat ist
ispc ispi isodroid isanbernicdie Maschine dieses Modell ist
nomenudie Menüs deaktiviert sind

Nur dort, wo ein System angezeigt wird

Diese acht fragen das aktuelle System ab. Sie gelten daher nur in der Ansicht Systeme und in der Spieleliste — anderswo gibt es kein System, und die Bedingung ist immer falsch.

BedingungWahr, wenn…
console handheld computer arcade engine port fantasydas System von diesem Typ ist
virtuales ein automatisches System ist (Favoriten, Zuletzt gespielt, Alle Spiele…)
favoritees das automatische System Favoriten ist
lastplayedes das automatische System Zuletzt gespielt ist

⚠️ favorite bedeutet nicht, dass das markierte Spiel ein Favorit ist: Es geht um das System. Es gibt keine Bedingung für ein Spiel oder einen Ordner — um auf den Inhalt eines Spiels zu reagieren, nutzt man seine Variablen (${game.isfavorite}) oder ifexists.


Mehrere Bedingungen kombinieren

UND, ODER, „nicht das“, und die Gruppen in Klammern.

Ein Etikett pro Bedingung

Du wählst eine Bedingung aus der Liste, sie wird zu einem Etikett. Der kleine Button davor sagt, in welche Richtung sie zählt:

Auf einem bereits gesetzten Etikett kehrt derselbe Button die Richtung um; das ✕ entfernt es.

Die Gruppen

Eine Gruppe ist eine Klammer. Darin sagst du, ob alle Bedingungen nötig sind, oder mindestens eine. Zwischen zwei Gruppen stellt sich dieselbe Frage: UND oder ODER.

Drei Schreibweisen für dieselben Operatoren

Was man sagen willZeichenAusgeschrieben
und&AND
oder|OR
nicht!NOT

Die beiden Schreibweisen mischen sich, und Groß- und Kleinschreibung spielt keine Rolle: if="crt AND !tate" entspricht if="crt & !tate".

⚠️ && und || funktionieren nicht. Zwei Zeichen hintereinander sind ein Syntaxfehler, und ein fehlerhafter Ausdruck ist falsch: die Komponente verschwindet, ohne dass irgendetwas auf dem Bildschirm darauf hinweist.

Beispiel: „auf einem Röhrenbildschirm, und in Arcade oder in den Favoriten“ schreibt man

crt & (arcade | favorite)

⚠️ Die Reihenfolge der Gruppen zählt

Die Maschine liest von links nach rechts, ohne Vorrang. a | b & c ist dort (a | b) & c, und nicht a | (b & c). Deshalb setzt das Studio systematisch die Klammern: was du liest, ist genau das, was die Maschine verstehen wird.

Innerhalb einer Gruppe dagegen spielt die Reihenfolge keine Rolle: „nicht Full HD und Arcade“ sagt dasselbe wie „Arcade und nicht Full HD“.

Eine Bedingung wird an zwei Stellen geschrieben

Dieselbe Bedingung, an der Komponente selbst oder an nur einer ihrer Eigenschaften, sagt nicht dasselbe:

<image name="filtre" if="crt">…</image>      <!-- ① die Komponente existiert NUR auf einem CRT -->

<text name="titre">                          <!-- ② die Komponente existiert immer… -->
  <fontSize if="crt">0.09</fontSize>         <!--    …aber ihre Größe ändert sich auf einem CRT -->
  <fontSize if="!crt">0.05</fontSize>
</text>

① an der Komponente: sie erscheint, oder sie existiert gar nicht. ② an einer Eigenschaft: die Komponente ist immer da, nur einer ihrer Werte ändert sich.

Im Studio ist es in beiden Fällen derselbe Button und dasselbe Fenster — was du hier baust, gilt dort identisch.


Die Systeme

Die internen Namen, die in deinen Ordnern und Dateien erwartet werden.

Jedes System trägt mehrere Namen, und man darf sie nicht verwechseln:

Der Ordner, den Sie in Ihrem Theme anlegen, trägt den Namen von ${system.name}. Einige Systeme bilden eine Ausnahme: Sie stehen unter ihrer Tabelle.

Die Maschinen (121)

System${system.name}${system}${system.manufacturer}${system.type}
240ptestsuite240ptestsuite240ptestsuitevirtualvirtual
Acorn BBC MicrobbcmicroAcorn BBC MicroAcorncomputer
Amiga AGAamiga1200Amiga AGACommodorecomputer
Amiga CD32amigacd32Amiga CD32Commodoreconsole
Amiga CDTVamigacdtvAmiga CDTVCommodoreconsole
Amiga ECS/OCSamiga600Amiga ECS/OCSCommodorecomputer
Amstrad GX4000gx4000Amstrad GX4000Amstradconsole
AmstradCPCamstradcpcAmstradCPCAmstradcomputer
Apple IIapple2Apple IIApplecomputer
Apple IIGSapple2gsApple IIGSApplecomputer
Apple MacintoshmacintoshApple MacintoshApplecomputer
ArduboyarduboyArduboyfantasyfantasy
Atari 2600atari2600Atari 2600Atariconsole
Atari 5200atari5200Atari 5200Atariconsole
Atari 7800atari7800Atari 7800Atariconsole
Atari 8bitsatari800Atari 8bitsAtaricomputer
Atari JaguarjaguarAtari JaguarAtariconsole
Atari STataristAtari STAtaricomputer
ColecovisioncolecovisionColecovisionColecoconsole
Commodore 64c64Commodore 64Commodorecomputer
Commodore VIC-20vic20Commodore VIC-20Commodorecomputer
DaphnedaphneDaphneDaphnearcade
DICEdiceDICEDICEarcade
Dos (x86)dosDos (x86)IBMcomputer
Dragon 32/64dragonDragon 32/64DragonDatacomputer
EasyRPGeasyrpgEasyRPGvirtualengine
Elektronika BKbkElektronika BKElektronikacomputer
Epoch Cassette VisioncassettevisionEpoch Cassette VisionEpochconsole
Exelvision EXL 100exl100Exelvision EXL 100Exelvisioncomputer
Fairchild Channel FchannelfFairchild Channel FFairchildconsole
Family Computer Disk SystemfdsFamily Computer Disk SystemNintendoconsole
FinalBurn NeofbneoFinalBurn NeoFBNarcade
Game and WatchgwGame and WatchNintendohandheld
Game BoygbGame BoyNintendohandheld
Game Boy AdvancegbaGame Boy AdvanceNintendohandheld
Game Boy ColorgbcGame Boy ColorNintendohandheld
GameCubegamecubeGameCubeNintendoconsole
Infocom Z-MachinezmachineInfocom Z-MachineInfocomengine
LowRes NXlowresnxLowRes NXvirtualfantasy
LutrolutroLutrovirtualfantasy
LynxlynxLynxAtarihandheld
MamemameMameMamearcade
Mattel IntellivisionintellivisionMattel IntellivisionMattelconsole
MegaDuckmegaduckMegaDuckWelbackhandheld
MGT SAM CoupésamcoupeMGT SAM CoupéMGTcomputer
MoonlightmoonlightMoonlightNVidiavirtual
MSX1msx1MSX1Microsoftcomputer
MSX2msx2MSX2Microsoftcomputer
MSXturboRmsxturborMSXturboRMicrosoftcomputer
NEC PC-88pc88NEC PC-88NECcomputer
NEC PC-98pc98NEC PC-98NECcomputer
NEC PC-FXpcfxNEC PC-FXNECconsole
Neo-Geo AESneogeoNeo-Geo AESSNKconsole
Neo-Geo CDneogeocdNeo-Geo CDSNKconsole
Neo-Geo PocketngpNeo-Geo PocketSNKhandheld
Neo-Geo Pocket ColorngpcNeo-Geo Pocket ColorSNKhandheld
Nintendo 64n64Nintendo 64Nintendoconsole
Nintendo 64DD64ddNintendo 64DDNintendoconsole
Nintendo DSndsNintendo DSNintendohandheld
Nintendo Entertainment SystemnesNintendo Entertainment SystemNintendoconsole
Odyssey2o2emOdyssey2Magnavoxconsole
OpenBORopenborOpenBORSenile Teamengine
Oric/AtmosoricatmosOric/AtmosTangerinecomputer
Othello MultivisionmultivisionOthello MultivisionTsukudaconsole
PalmpalmPalmPalmhandheld
Panasonic 3DO3doPanasonic 3DOPanasonicconsole
PC EnginepcenginePC EngineNECconsole
PC Engine CDpcenginecdPC Engine CDNECconsole
Philips CD-IcdiPhilips CD-IPhillipsconsole
Philips P2000Tp2000tPhilips P2000TPhilipscomputer
Philips VG 5000vg5000Philips VG 5000Philipscomputer
PICO-8pico8PICO-8virtualfantasy
Pocket Challenge v2pcv2Pocket Challenge v2Benessehandheld
Pokémon MinipokeminiPokémon MiniNintendohandheld
Sammy AtomiswaveatomiswaveSammy AtomiswaveSammyarcade
SatellaviewsatellaviewSatellaviewNintendoconsole
ScreenshotsimageviewerScreenshotsvirtualvirtual
ScummVMscummvmScummVMLudvig Strigeusengine
Sega 32Xsega32xSega 32XSegaconsole
Sega CDsegacdSega CDSegaconsole
Sega DreamcastdreamcastSega DreamcastSegaconsole
Sega Game GeargamegearSega Game GearSegahandheld
Sega Master System / Mark IIImastersystemSega Master System / Mark IIISegaconsole
Sega MegadrivemegadriveSega MegadriveSegaconsole
Sega Model3model3Sega Model3Segaarcade
Sega NAOMInaomiSega NAOMISegaarcade
Sega NAOMI 2naomi2Sega NAOMI 2Segaarcade
Sega NAOMI GD-ROM SystemnaomigdSega NAOMI GD-ROM SystemSegaarcade
Sega PicopicoSega PicoSegaconsole
Sega SaturnsaturnSega SaturnSegaconsole
Sega SG1000sg1000Sega SG1000Segaconsole
Sharp X1x1Sharp X1Sharpcomputer
Sharp X68000x68000Sharp X68000Sharpcomputer
SolarussolarusSolarusSolarusengine
Sony Playstation 1psxSony Playstation 1Sonyconsole
Sony Playstation 2ps2Sony Playstation 2Sonyconsole
Sony Playstation PortablepspSony Playstation PortableSonyhandheld
SpectravideospectravideoSpectravideoSpectravideocomputer
ST-VstvST-VSegaarcade
SuFami TurbosufamiSuFami TurboBandaiconsole
Super Cassette VisionscvSuper Cassette VisionEpochconsole
Super Nintendo Entertainment SystemsnesSuper Nintendo Entertainment SystemNintendoconsole
SupergrafxsupergrafxSupergrafxNECconsole
Texas Instrument TI-99/4Ati994aTexas Instrument TI-99/4ATexas Instrumentcomputer
ThomsonthomsonThomsonThomsoncomputer
TIC-80tic80TIC-80portfantasy
TRS-80 Color Computertrs80cocoTRS-80 Color ComputerTandycomputer
UzeboxuzeboxUzeboxportconsole
VectrexvectrexVectrexMBconsole
Videopac+ G7400videopacplusVideopac+ G7400Philipsconsole
Vircon32vircon32Vircon32virtualconsole
Virtual BoyvirtualboyVirtual BoyNintendoconsole
Visual Pinball StandalonevpinballVisual Pinball StandaloneRandy Davisengine
WASM-4wasm4WASM-4Bruno Garciafantasy
Watara SupervisionsupervisionWatara SupervisionWatarahandheld
WiiwiiWiiNintendoconsole
WonderSwanwswanWonderSwanBandaihandheld
WonderSwan ColorwswancWonderSwan ColorBandaihandheld
XboxxboxXboxMicrosoftconsole
ZX81zx81ZX81Sinclaircomputer
ZXSpectrumzxspectrumZXSpectrumSinclaircomputer

Die Ordner, die nicht den Namen des Systems tragen. Nur für diese heißt der Ordner in Ihrem Theme anders als ${system.name}.

System${system.name}Anzulegender Ordner
Dos (x86)dospc
GameCubegamecubegc
Odyssey2o2emodyssey2
Oric/Atmosoricatmosoric
Thomsonthomsonto8
WonderSwanwswanwonderswan
WonderSwan Colorwswancwonderswancolor

Die virtuellen Systeme (11)

Recalbox baut sie selbst, aus deinen Spielen: sie haben keine Systemdatei, aber sehr wohl einen Theme-Ordner, und du kannst sie wie alle anderen einkleiden.

System${system.name}${system}${system.type}
PortsportsPortsvirtual
FavoritesfavoritesFavoritesvirtual
Last playedlastplayedLast playedvirtual
All gamesallgamesAll gamesvirtual
MultiplayermultiplayerMultiplayervirtual
ArcadearcadeArcadevirtual-arcade
LightgunlightgunLightgunvirtual
TatetateTatevirtual
DialdialDialvirtual
TrackballtrackballTrackballvirtual
ChallengeschallengesChallengesvirtual

Die Ordner, die nicht den Namen des Systems tragen. Nur für diese heißt der Ordner in Ihrem Theme anders als ${system.name}.

System${system.name}Anzulegender Ordner
Last playedlastplayedauto-lastplayed
All gamesallgamesauto-allgames
Multiplayermultiplayerauto-multiplayer
Lightgunlightgunauto-lightgun
Tatetateauto-tate
Dialdialauto-dial
Trackballtrackballauto-trackball
Challengeschallengesauto-challenges

Arcade nach Hersteller (54) (${system.type} = virtual-arcade)

System${system.name}${system}
Acclaimarcade-manufacturer-acclaimAcclaim
Atariarcade-manufacturer-atariAtari
Atlusarcade-manufacturer-atlusAtlus
Banprestoarcade-manufacturer-banprestoBanpresto
Capcom Cps1arcade-manufacturer-capcom-cps1Capcom Cps1
Capcom Cps2arcade-manufacturer-capcom-cps2Capcom Cps2
Capcom Cps3arcade-manufacturer-capcom-cps3Capcom Cps3
Capcomarcade-manufacturer-capcomCapcom
Cavearcade-manufacturer-caveCave
Data eastarcade-manufacturer-data eastData east
Exidyarcade-manufacturer-exidyExidy
Hng64arcade-manufacturer-hng64Hng64
Igsarcade-manufacturer-igsIgs
Irem M72arcade-manufacturer-irem-m72Irem M72
Irem M92arcade-manufacturer-irem-m92Irem M92
Iremarcade-manufacturer-iremIrem
Itecharcade-manufacturer-itechItech
Jalecoarcade-manufacturer-jalecoJaleco
Kanekoarcade-manufacturer-kanekoKaneko
Konami Gxarcade-manufacturer-konami-gxKonami Gx
Konamiarcade-manufacturer-konamiKonami
Midwayarcade-manufacturer-midwayMidway
Mitchellarcade-manufacturer-mitchellMitchell
Namco Naarcade-manufacturer-namco-naNamco Na
Namco Nbarcade-manufacturer-namco-nbNamco Nb
Namco System1arcade-manufacturer-namco-system1Namco System1
Namco System10arcade-manufacturer-namco-system10Namco System10
Namco System11arcade-manufacturer-namco-system11Namco System11
Namco System12arcade-manufacturer-namco-system12Namco System12
Namco System18arcade-manufacturer-namco-system18Namco System18
Namco System2arcade-manufacturer-namco-system2Namco System2
Namcoarcade-manufacturer-namcoNamco
Neogeoarcade-manufacturer-neogeoNeogeo
Nichibutsuarcade-manufacturer-nichibutsuNichibutsu
Nintendoarcade-manufacturer-nintendoNintendo
Nmkarcade-manufacturer-nmkNmk
Psikyoarcade-manufacturer-psikyoPsikyo
Raizingarcade-manufacturer-raizingRaizing
Sammyarcade-manufacturer-sammySammy
Sega Stvarcade-manufacturer-sega-stvSega Stv
Sega System16arcade-manufacturer-sega-system16Sega System16
Sega System18arcade-manufacturer-sega-system18Sega System18
Sega System32arcade-manufacturer-sega-system32Sega System32
Segaarcade-manufacturer-segaSega
Seibuarcade-manufacturer-seibuSeibu
Setaarcade-manufacturer-setaSeta
Snkarcade-manufacturer-snkSnk
Taito F3arcade-manufacturer-taito-f3Taito F3
Taito Gnetarcade-manufacturer-taito-gnetTaito Gnet
Taitoarcade-manufacturer-taitoTaito
Technosarcade-manufacturer-technosTechnos
Tecmoarcade-manufacturer-tecmoTecmo
Toaplanarcade-manufacturer-toaplanToaplan
Viscoarcade-manufacturer-viscoVisco

Nach Genre (56) (${system.type} = virtual)

System${system.name}${system}
Actiongenre-actionAction
Platformgenre-actionplatformerPlatform
Platform Shootergenre-actionplatformshooterPlatform Shooter
First Person Shootergenre-actionfirstpersonshooterFirst Person Shooter
Shoot'em Upgenre-actionshootemupShoot'em Up
Shoot with Gungenre-actionshootwithgunShoot with Gun
Fightinggenre-actionfightingFighting
Beat'em Allgenre-actionbeatemupBeat'em All
Infiltrationgenre-actionstealthInfiltration
Battle Royalegenre-actionbattleroyaleBattle Royale
Rythm & Musicgenre-actionrythmRythm & Music
Adventuregenre-adventureAdventure
Textual Adventuregenre-adventuretextTextual Adventure
Graphical Adventuregenre-adventuregraphicsGraphical Adventure
Visual Novelgenre-adventurevisualnovelsVisual Novel
Interactive Moviegenre-adventureinteractivemovieInteractive Movie
Real Time 3D Adventuregenre-adventurerealtime3dReal Time 3D Adventure
Survivalgenre-adventuresurvivalhorrorSurvival
RPGgenre-rpgRPG
Action RPGgenre-rpgactionAction RPG
MMORPGgenre-rpgmmoMMORPG
Dungeon Crawlergenre-rpgdungeoncrawlerDungeon Crawler
Tactical RPGgenre-rpgtacticalTactical RPG
JRPGgenre-rpgjapaneseJRPG
Party based RPGgenre-rpgfirstpersonpartybasedParty based RPG
Simulationgenre-simulationSimulation
Build & Managementgenre-simulationbuildandmanagementBuild & Management
Life Simulationgenre-simulationlifeLife Simulation
Fishing & Huntinggenre-simulationfishandhuntFishing & Hunting
Vehicle Simulationgenre-simulationvehicleVehicle Simulation
Science Fiction Simulationgenre-simulationscifiScience Fiction Simulation
Strategygenre-strategyStrategy
eXplore, eXpand, eXploit & eXterminategenre-strategy4xeXplore, eXpand, eXploit & eXterminate
Artillerygenre-strategyartilleryArtillery
Auto-battlergenre-strategyautobattlerAuto-battler
Multiplayer Online Battle Arenagenre-strategymobaMultiplayer Online Battle Arena
Real Time Strategygenre-strategyrtsReal Time Strategy
Turn Based Strategygenre-strategytbsTurn Based Strategy
Tower Defensegenre-strategytowerdefenseTower Defense
Wargamegenre-strategywargameWargame
Sportsgenre-sportsSports
Racinggenre-sportracingRacing
Sport Simulationgenre-sportsimulationSport Simulation
Competition Sportgenre-sportcompetitiveCompetition Sport
Fighting/Violent Sportgenre-sportfightFighting/Violent Sport
Pinballgenre-pinballPinball
Board gamegenre-boardBoard game
Casual gamegenre-casualCasual game
Digital Cardsgenre-digitalcardDigital Cards
Puzzle & Logicgenre-puzzleandlogicPuzzle & Logic
Multiplayer Party Gamegenre-partyMultiplayer Party Game
Triviagenre-triviaTrivia
Casinogenre-casinoCasino
Multi Game Compilationgenre-compilationMulti Game Compilation
Demo from Demo Screnegenre-demosceneDemo from Demo Screne
Educativegenre-educativeEducative

Die Schriften

Die der Maschine, und deine.

Eine Schrift kommt von zwei Orten, und das ändert, was mitgeliefert werden muss.

Die der Maschine

<fontPath>:/ubuntu_condensed.ttf</fontPath>

Das :/ bezeichnet die Ressourcen von EmulationStation. Nichts zu kopieren in dein Theme: die Datei ist auf jeder Recalbox vorhanden.

Deine

<fontPath>${root}/data/fonts/Exo2.otf</fontPath>

Die Datei muss in deinem Theme sein und wird mit ihm ausgeliefert. TTF und OTF funktionieren.

Die Größe

fontSize wechselt die Einheit je nach Wert: unter 1 ist es ein Anteil der Bildschirmhöhe; ab 1 sind es Pixel. Alles wird in Verhältnis, Prozent oder Pixel erklärt. Bevorzuge das Verhältnis: 0.045 ergibt überall denselben Anteil.

Die Pixelschriften

f8bitfortressplus ist nur bei Größen scharf, die Vielfache von 7 in Pixeln sind. Zwischen diesen Werten verschmiert sie. Das gilt für jede Pixel für Pixel gezeichnete Schrift: wenn du eine hinzufügst, prüfe, bei welchen Größen sie sauber ist.

fontStyle

normal · bold · italic · bolditalic

⚠️ Funktioniert nur, wenn die Schrift diese Schnitte enthält. Eine Schrift, die als einzelne „Regular“-Datei geliefert wird, wird nicht fett: du musst die „Bold“-Datei liefern und sie mit einem eigenen fontPath bezeichnen.

Mit Recalbox ausgeliefert

Nichts in dein Theme zu kopieren.

SchriftSchreibweise
Ubuntu Condensed:/ubuntu_condensed.ttf
DejaVu Sans Condensed:/dejavusanscondensed.ttf
Ubuntu Mono:/UbuntuMonoR.ttf
8-bit Fortress Plus — Pixelschrift, scharf in Vielfachen von 7:/f8bitfortressplus.ttf

Was eine Option ist

Dem Benutzer deines Themes Auswahlmöglichkeiten bieten.

Eine Option ist eine Eigenschaft, die der Benutzer in den Menüs seiner Maschine findet: „Themefarben: Blau / Grün / Rot“, „Retro-Filter: CRT / Scanlines / keiner“.

Sie ist es, die ein reiches Theme von einem starren unterscheidet.

Was eine Option wirklich tut

Eine Option ist kein „zeigen oder verstecken“-Schalter. Sie ist eine Datei, die über das Theme geladen wird und neu definiert, was sie will: eine Farbe, eine Schrift, ein ganzes Layout.

Bei den offiziellen Themes ändert die große Mehrheit der Optionen nur Farben — oft durch das Neudefinieren einer einfachen <variable>. Ausblendungen sind selten.

Eine Option wirkt auf alle Ansichten zugleich: sie ist eine Eigenschaft des Themes, nicht einer Ansicht.

Die Optionen des offiziellen Themes

recalbox-next-2025 bietet zehn davon, was eine gute Vorstellung davon gibt, was üblich ist:

OptionWas sie ändert
systemViewdas Layout der Systemliste
gameListdas der Spieleliste
gameclipviewdas des Bildschirmschoners
SysInfosdie Informationen der Systeme: vollständig, minimal, versteckt
gameInfosdie Informationen der Spiele
colorTheme12 Farbpaletten
shaderder Retro-Filter: CRT, Scanlines, Wabe, keiner
shadowdie Schattierung
bandsdie Farbbänder: dünn, dick, keine
iconesetThemedie Symbole der Hilfeleiste: 8 Sätze

Eine Option deklarieren: <subset>

Die genaue Syntax, in zwei Schritten.

Eine Option wird in zwei Schritten gebaut: man deklariert sie, dann listet man ihre Auswahlmöglichkeiten auf.

<subset subset="colorTheme" deklariert die GRUPPE + ihren Titel <include … name="1 - Blau"> <include … name="2 - Rot"> jede Auswahl = eine darüber geladene Datei Einstellungen ▸ Theme Themefarben ◁ Blau ▷ was der Benutzer sieht auf seiner Maschine das Präfix „1 - “ dient zum SORTIEREN der Auswahl: es wird nicht angezeigt

1. Die Gruppe deklarieren

<subset subset="colorTheme"
        title="THEME : Colors"      title.fr="THÈME : Couleurs"
        help="Choose the color set"  help.fr="Choisissez la palette" />
AttributAufgabe
subsetdie Kennung der Gruppe — sie verbindet die Auswahlmöglichkeiten miteinander
titledie Beschriftung, die der Benutzer im Menü liest
helpder Erklärungssatz unter der Beschriftung

title und help akzeptieren ein Sprachsuffix: title.fr, title.es… Die Version ohne Suffix dient als Rückfall.

2. Die Auswahlmöglichkeiten auflisten

Jede Auswahl ist ein <include>, das dasselbe subset trägt:

<include subset="colorTheme" name="Blue"  name.fr="Bleu">${root}/options/couleurs/bleu.xml</include>
<include subset="colorTheme" name="Green" name.fr="Vert">${root}/options/couleurs/vert.xml</include>
<include subset="colorTheme" name="Red"   name.fr="Rouge">${root}/options/couleurs/rouge.xml</include>
AttributAufgabe
subsetzu welcher Gruppe diese Auswahl gehört
namedie Beschriftung der Auswahl in der Liste (übersetzbar: name.fr)

Die Auswahl „keine“

Ein leeres <include> ergibt die Option „keine“ — nützlich, um das Theme in seinem Ursprungszustand zu lassen:

<include subset="shader" name="None" name.fr="Aucun"></include>

Eine Auswahl nur auf bestimmten Bildschirmen anbieten

<include subset="systemView" if="(hd | fhd) and !tate"
         name="Vertical left" name.fr="Vertical gauche">${root}/_views/vertical.xml</include>
<include subset="systemView" if="crt | jamma"
         name="Horizontal">${root}/_views/horizontal.xml</include>

Der Benutzer sieht nur die für seine Hardware relevanten Auswahlmöglichkeiten. So erscheint der Retro-Filter nicht auf einem Röhrenbildschirm, der ihn nicht braucht.

Der Inhalt einer Auswahldatei

Es ist eine gewöhnliche Theme-Datei, die nur neu definiert, was sich ändert:

<?xml version="1.0" encoding="UTF-8"?>
<theme>
  <variables>
    <variable name="CouleurPrincipale" value="7C2E44" />
  </variables>
</theme>

Drei nützliche Zeilen, und das ganze Theme wird rot — vorausgesetzt, das Theme wurde auf Variablen aufgebaut statt auf fest geschriebenen Farben.

⚠️ Die Optionen werden VOR den Ansichten geladen. Eine Variable gilt für das, was nach ihr gelesen wird: dort muss die Auswahl durchlaufen, damit die Ansichten davon profitieren.

Die Reihenfolge, die in theme.xml zu schreiben ist:

<theme name="Mon Thème" …>
  <include>${root}/variables.xml</include>      <!-- 1. die Standardwerte -->
  <include>${root}/options.xml</include>        <!-- 2. die Auswahl definiert sie neu -->
  <include>${root}/views/system.xml</include>   <!-- 3. die Ansichten, die sie verwenden -->
</theme>

Was passiert, wenn die Person die Auswahl wechselt

Recalbox liest das ganze Theme neu — alle Dateien, ab theme.xml, mit der neuen aktiven Auswahl. Deshalb erscheint in diesem Moment kurz „Theme wird aktualisiert…“.

Eine Option, die nur Farben ändert, definiert ausschließlich Variablen neu. Das ist die kürzeste Art, einen Farbsatz zu schreiben — und der Hauptgrund, <variables> zu verwenden.


Die Reihenfolge der Auswahlmöglichkeiten

Das Zahlenpräfix — und warum es nicht angezeigt wird.

Recalbox behält nicht die Reihenfolge, in der du deine <include> schreibst. Es sortiert die Auswahlmöglichkeiten selbst, in zwei Schritten:

  1. wenn ALLE Auswahlmöglichkeiten eine Zahl am Anfang ihres name haben, sortiert es nach dieser Zahl;
  2. sonst sortiert es nach der alphabetischen Reihenfolge des name.

Deshalb nummeriert man.

Die richtige Schreibweise

<include subset="bands" name="1 - Thin"   name.fr="1 - Fines">…</include>
<include subset="bands" name="2 - Thick"  name.fr="2 - Épaisses">…</include>
<include subset="bands" name="3 - None"   name.fr="3 - Aucune">…</include>

Das Präfix wird nicht angezeigt. Recalbox erkennt es, nutzt es zum Sortieren, und entfernt es dann, bevor die Beschriftung angezeigt wird. Der Benutzer liest „Dünn“, „Dick“, „Keine“.

Was die Engine als Präfix akzeptiert

Eine Zahl, dann ein Leerzeichen, ein Bindestrich oder ein Punkt, alles innerhalb der ersten acht Zeichen. Diese drei Schreibweisen funktionieren:

1 - Dünn
1. Dünn
1 Dünn

Die Falle

Die numerische Sortierung wird nur verwendet, wenn alle Auswahlmöglichkeiten nummeriert sind. Ein einziges Versäumnis, und Recalbox fällt auf die alphabetische Reihenfolge zurück — deine Auswahlmöglichkeiten ordnen sich von selbst neu, ohne Meldung.

<include subset="bands" name="1 - Fines">…</include>
<include subset="bands" name="2 - Épaisses">…</include>
<include subset="bands" name="Aucune">…</include>     <!-- ❌ bricht die Sortierung aller drei -->

Der Name der DATEIEN hingegen ist frei

Nicht zu verwechseln: die Zahl gehört in das Attribut name, nicht in den Dateinamen. Recalbox schaut nie, wie deine Datei heißt.

options/
  bandes/
    fines.xml        ← benenne sie, wie du willst
    epaisses.xml
    aucune.xml

Was zählt: ein Ordner pro Option, und Namen, die sagen, was sie tun.


Sein Theme ausprobieren

Es auf die Maschine kopieren, und im Problemfall das Protokoll lesen.

Ein Theme lässt sich nur eingeschaltet, auf einem Bildschirm beurteilen. Die Vorschau des Studios ist originalgetreu, aber nichts ersetzt die Maschine.

  1. das Theme aus dem Studio exportieren;
  2. den Ordner nach /recalbox/share/themes/ kopieren;
  3. auf der Maschine: Menü → Eigenschaften der Oberfläche → Theme, und deines auswählen.

📄 Das Protokoll: themes.log

Das ist die erste Stelle, an der man nachsieht, wenn etwas nicht erscheint.

/recalbox/share/system/logs/themes.log

Es vermerkt, mit Datei und Zeile als Beleg:

Eine unsichtbare Komponente ohne Eintrag im Protokoll bedeutet fast immer, dass extra="true" fehlt: siehe Die wichtigste Regel.


Dein Theme teilen

Dein Theme dem Theme-Manager von Recalbox vorschlagen — direkt aus dem Studio.

Recalbox hat einen Theme-Manager: Themes werden dort installiert, ohne dass man etwas von Hand kopiert. Damit ein Theme hineinkommt, muss man es vorschlagen — und alles geschieht aus diesem Studio heraus.

📘 Kein Repository zum Forken, keine Merge Request, keine Datei zum Schreiben: Das Studio baut das Paket, macht die Bildschirmfotos und reicht alles für dich ein.

Dein Theme vorschlagen

Zwei Wege, ein Ziel:

In beiden Fällen beschreibst du dein Theme in wenigen Feldern und schickst es ab. Das war's.

⚠️ Du brauchst das Recht dazu. Ein Theme vorzuschlagen steht den Rollen offen, die das Team im Recalbox-Discord bestimmt hat: Fehlt die Schaltfläche, fehlt dir das Recht.

Was das Studio für dich erledigt

⚠️ Dein Archiv geht unverändert raus. Das Studio schaut nur hinein, um die Bildschirmfotos zu machen; es schreibt es nie um. Deine Ordner, deine Dateinamen, deine Struktur: nichts verrutscht.

Was danach passiert

  1. dein Theme geht zur Abstimmung — die Theme-Macher sehen es sich Bildschirm für Bildschirm an und geben ihre Meinung ab, auf Wunsch mit ein paar Worten;
  2. eine Administratorin oder ein Administrator entscheidet. Die Abstimmung erhellt, sie entscheidet nicht: Niemand wird durch eine Zählung veröffentlicht;
  3. angenommen landet das Theme im Theme-Manager und jede Recalbox sieht es. Abgelehnt bekommst du eine Begründung — genug, um nachzubessern und erneut vorzuschlagen.

Verfolgen kannst du alles unter „Meine Themes“: Auf der Karte deines Themes steht „Anfrage offen“, und der Reiter „Veröffentlichen“ zeigt die Stimmen und die Rückmeldungen (ohne Namen).

Ein veröffentlichtes Theme aktualisieren

Derselbe Weg: Schlage dein Theme erneut vor, mit einer höheren Versionsnummer.

⚠️ Eine Aktualisierung geht nicht noch einmal durch die Abstimmung — es ist dein Theme, du kennst seinen Zustand. Sie wartet nur darauf, online gestellt zu werden. Niemand muss etwas neu installieren: Der Theme-Manager bietet die Aktualisierung an.

Woran es scheitert