Rim & Ridge — Design System¶
Visuelle Identität des TRGB-BikeComputers: ein rundes 480×480-Display (GC9A01-Klasse-TFT), LVGL-UI. Zurückhaltend, dünne Linien, ein Akzentton (Messing) auf Anthrazit. Benannt nach dem Bootlogo-Motiv — der Bildschirmrand selbst ist die Felge.
Status:
| Screen | Datei | Zustand |
|---|---|---|
| Mainscreen | mainscreen.svg |
implementiert, EEZStudio/TRGB-BikeComputer.eez-project, Screen rim_ridge, inkl. Straßenqualität-Indikator (rr_line_rq, §4) |
| Navigationsscreen | navscreen.svg |
implementiert, Screen rim_ridge_nav (SCREEN_ID_RIM_RIDGE_NAV) |
| Einstellungen | settings.svg |
implementiert, Screen RimRidgeSettings (SCREEN_ID_RIM_RIDGE_SETTINGS), gegenüber der SVG um WLAN-Reconnect, Kalibrierung und Referenzfahrt erweitert (§6) |
| Kletter-Screen | climbscreen.svg |
implementiert, Screen RimRidgeClimb (SCREEN_ID_RIM_RIDGE_CLIMB), Höhenprofil mit Farbe nach Steigung (§6) |
| RQ-Ride-Screen | rqscreen.svg |
Umgesetzt (Screen RimRidgeRQ) — Nav-Pille, Speed, Puls, Wegzähler (Tourstrecke) mit echten Daten; RQ-Index aus ui_RimRidgeUpdateRoadQuality(); Untergrund-Pillen, Qualitäts-Regler und Aufnahme-Taste live über I2CSensors::setRoadLabel*()/startRoadCapture() verdrahtet (Tap togglet, zweiter Tap auf den aktiven Wert setzt ihn zurück) |
Jede SVG-Datei ist 1:1 im Ziel-Koordinatensystem (480×480 Einheiten =
480×480 physische Pixel) und lässt sich direkt im Browser oder per
rsvg-convert -w 480 -h 480 mainscreen.svg -o preview.png in echter
Pixelgröße prüfen — bei einem runden 480px-Display mit wenig Fläche ist das
kein optionaler Schritt, siehe „Lektion: Icon-Größe" unten.
Bei Abweichungen zwischen SVG und implementiertem Screen zählt der EEZ-Screen. Dieses Dokument beschreibt den aktuellen Stand des Designs. Es soll reichen, um einen weiteren Screen im selben System zu bauen, ohne das gesamte Bild neu erfinden zu müssen.
1. Farbpalette¶
Alle Werte sind in screens.h/theme_colors[] als COLOR_ID_RR_* bereits
angelegt und verifiziert (1:1 mit den Werten unten) — beim Bauen neuer
Screens diese Theme-Farben referenzieren, nicht neu hex-codieren.
Token (COLOR_ID_RR_…) |
Hex | Verwendung |
|---|---|---|
BACKGROUND |
#161B1F |
Screen-Hintergrund (Anthrazit) |
RIM_OUTLINE |
#3A362E |
äußerer Bezel-Ring, r=234, 1.5px, jeder Screen |
ARC_TRACK |
#332F28 |
unbefüllter Teil des Speed-/Distanz-Rings |
BRASS |
#CBA36B |
Primärakzent — Linien, Icons, Ring-Füllung, Zahlen-Highlights |
PARCHMENT_BRIGHT |
#F3ECDF |
Hero-Wert (Speed-Zahl) und Ø-Marker |
PARCHMENT |
#E7E2D6 |
sekundäre Werte: Distanz, Temp, Höhe, Steigung, HF, Button-Labels |
MUTED |
#9BA097 |
Einheiten, kleine Caption-Labels |
SAGE |
#7FA08F |
Naturbezug: Höhen-/Steigungs-Icon, Akku-Füllstand „gut" |
PANEL_BG |
#1E252B |
Flächen von Chips/Buttons |
TOUR_BG |
#282019 |
Fläche des Modus-Chips |
ZONE_BLUE … ZONE_RED |
#6C90B0 #6FA98C #D7B463 #CE8A4C #C1604A |
HF-Zonen 1–5, einzige bewusst bunte Stelle im System |
Feldweg/Straßenname und die kleinere Entfernung des übernächsten
Hinweises laufen auf #A39D8E (gedämpftes Pergament, kein eigenes Token in
EEZ — beim Anlegen ergänzen oder auf MUTED mappen).
In theme_colors[] liegen zusätzlich 16 nicht-RR_-präfixte Farb-IDs
(NAV_ICON_RECOLOR, ARC_SPEED_TRACK, GRADIENT_GOOD_GREEN …) mit
grellen Platzhalterwerten (reines Grün/Rot/Blau) — nicht Teil dieses
Systems, bei Gelegenheit aufräumen.
2. Typografie¶
Drei Fonts, klar nach Rolle getrennt — nie nach Geschmack mischen:
| Rolle | Font | Schnitt | Beispiele |
|---|---|---|---|
| Hero-/Sekundärzahl | Big Shoulders Display | 700 (hero), 600 (sekundär) | Speed (130px Main / 48px Nav), Entfernung (84px Nav), Distanz/Cadence/Watt/Temp/Höhe/Steigung/HF-Wert (20–28px) |
| Feld-/Button-Label | IBM Plex Sans | 600 | Button-Beschriftung („Neustart", „Tiefschlaf"), Straßenname |
| Einheit / technisches Label | IBM Plex Mono | 400–500 | Einheiten (KM/H, rpm, W), Modus-Chip-Text, Screen-Titel, Build/IP-Werte |
Google Fonts (fonts.googleapis.com/css2?family=Big+Shoulders+Display:wght@600;700&family=IBM+Plex+Sans:wght@400;600&family=IBM+Plex+Mono:wght@400;500)
für Vorschau/Browser. Für LVGL über den Font-Converter als Bitmap-Font
exportieren (ui_font_by7x128 ist bereits die 128px-Variante von Big
Shoulders Display für den Speed-Wert) — pro tatsächlich benutzter
Kombination aus Font+Gewicht+Größe ein eigener Bitmap-Font, LVGL kann
Schriften nicht laufzeit-skalieren.
Lektion: Icon-Größe¶
Piktogramm-Icons (Fahrrad, Stop-Schild etc.) brauchen mindestens 32–34px
Kantenlänge. Bei 20px verschwimmen Details wie die Speiche-Löcher eines
Laufrads praktisch vollständig — getestet sowohl kantengeglättet als auch
als simuliertes 1-Bit-Rendering (dem härtesten Fall: kein Alpha-Blending).
Die bereits exportierten Ride-State-Icons (ui_image_rr_icon_state_*.c)
nutzen 34×34px bei LV_IMG_CF_ALPHA_8BIT — das ist die richtige
Referenzgröße und das richtige Format (kantengeglätteter Alpha-Kanal, per
lv_obj_set_style_img_recolor zur Laufzeit auf RR_BRASS eingefärbt, statt
Farbe fest ins Bitmap zu backen). Neue Icons nach demselben Muster
exportieren, nicht als LV_IMG_CF_INDEXED_1BIT wie die älteren
SquareLine-Assets (2026-09-27 entfernt).
3. Koordinatensystem¶
480×480, Zentrum (240, 240). Kein Layout-Grid — die Kreisform bestimmt,
wie viel horizontaler Platz an einer bestimmten Höhe verfügbar ist:
halbe Breite(dy) = √(r_sicher² − dy²) r_sicher ≈ 205
dy = vertikaler Abstand von 240. Bei dy = 0 (Bildschirmmitte) sind
±205px verfügbar; bei dy = 148 (Höhe der Nav-Pille/Statuszeile) nur noch
±141px. Das ist der Grund, warum breite Elemente (HF-Zonenleiste,
Speed-Zahl) auf Zentrumshöhe sitzen und schmale, kurze Inhalte
(Statuszeile, Buttons) oben/unten. Vor jedem neuen Element an dessen Y-Höhe
kurz nachrechnen, nicht nach Gefühl platzieren — das war die häufigste
Fehlerquelle in der Entstehung dieses Designs.
r_sicher ≈ 205 ergibt sich aus dem Arc-Ring bei r=222 mit 16px Dicke
(Innenkante ≈ 214) minus Sicherheitsabstand. Bezel-Ring bei r=234 ist rein
dekorativ und beansprucht keinen Inhaltsraum.
4. Wiederverwendbare Komponenten¶
Gapped Arc (Speed-/Distanz-Ring)¶
Ein lv_arc-taugliches Muster: zwei konzentrische Kreise (Track + Füllung),
270° Bogen mit fester 90°-Lücke unten, Nullpunkt fix unten links.
r = 222, Strichdicke = 16
Umfang C = 2·π·r ≈ 1394.87
Track-dasharray = "1046.15 348.72" (0.75·C / 0.25·C)
Füllung-dasharray = "{0.75·C·wert/max} {C−…}" z. B. 55 % → "575.38 819.49"
beide: transform="rotate(135 240 240)"
Bedeutung ist screen-abhängig: auf dem Mainscreen befüllt sich der Ring
mit der Geschwindigkeit (0 = leer, max = voller Ring). Auf dem
Navigationsscreen zeigt derselbe Mechanismus die Distanz zum Manöver
(befüllt sich beim Näherkommen). Ø-Marker: ein <line> quer über den Ring
bei r ± 10, Winkel 225° + 270°·(ø-wert/max) im Uhrzeigersinn ab 12 Uhr —
Polarkoordinaten-Hilfsformel dafür:
x = cx + r·sin(θ) y = cy − r·cos(θ) (θ in Grad, 0° = oben, im Uhrzeigersinn)
HF-Zonenband¶
Fünf 52×14-Rechtecke nebeneinander (äußere mit rx=7 abgerundet), feste
Zonenfarben (§1), plus ein kleines Dreieck als Positions-Marker über dem
Segment, das dem aktuellen Wert entspricht. Bewusst der einzige Ort mit
mehr als zwei gleichzeitigen Farben — hier trägt Farbe echte Funktion.
Pille / Chip¶
rx = Höhe/2 (voller Pill), Fläche PANEL_BG (Nav-Chip) oder TOUR_BG
(Modus-Chip), Rahmen BRASS bei 30–40% Deckkraft, 1.5px. Für Container mit
mehreren Elementen (Spur-Anzeige) rx≈9 statt vollem Pill — unterscheidet
„Container" optisch von „Schalter/Hinweis".
Icon-Buttons (rund) vs. Buttons mit Label (Pille)¶
Mainscreen-Buttons (Pause, Einstellungen) sind reine Icon-Kreise, r=25,
Fläche PANEL_BG, Rahmen BRASS 2px — genug Kontext durch Position, kein
Text nötig. Der Einstellungen-Screen nutzt breitere Pillen (210×40,
rx=20) mit Icon und Label, weil „Neustart"/„Tiefschlaf" ohne Text
nicht eindeutig genug wären und hier deutlich mehr Platz ist als im
gedrängten Mainscreen-Fuß.
Segmentierter Wähler (diskrete Stufen)¶
Für eine kleine, feste Anzahl Stufen (z. B. Qualität 1–4) statt eines
kontinuierlichen lv_slider: n Kreise (r=20, Fläche PANEL_BG,
Rahmen BRASS 2px) im festen Abstand 60px nebeneinander, verbunden durch
eine dünne Linie (BRASS 25 % Deckkraft, stroke-width=3) als optische
Klammer. Gewählte Stufe: Kreis voll BRASS, Ziffer in BACKGROUND
(dunkel-auf-hell statt hell-auf-dunkel) statt Rahmen — derselbe
Auswahl-Kontrast wie beim gefüllten Modus-Chip unten. r=20 ist bewusst
in derselben Größenordnung wie die runden Icon-Buttons (r=25, §4) — große
Ziele, einhändig bedienbar. Erster Einsatzort: RQ-Ride-Screen (§6).
Stat-Gruppe (Icon + Wert + Einheit)¶
Wiederkehrendes Muster für Cadence/Watt/Temp/Höhe/Steigung: kleines
Linien-Icon (stroke-width 1.6–2.2, BRASS), Wert direkt darunter oder
daneben in Big Shoulders Display 600, Einheit klein in IBM Plex Mono,
MUTED. Bei zwei symmetrischen Gruppen (Cadence/Watt) als schmale Spalte
außerhalb der Speed-Zahl platzieren, nicht auf gleicher Höhe daneben — sonst
Kollisionsgefahr mit der großen Zahl (siehe §3).
Fahrzeit / Uhrzeit¶
Ein Slot, zwei mögliche Inhalte — welcher gerade gilt, ist App-Logik, nicht Teil dieser Spezifikation. Icon und Wert wechseln immer zusammen:
- Fahrzeit (Stoppuhr-Icon: Kreis + Krone oben + Zeiger) — verstrichene
Zeit der aktuellen Fahrt/Tour, Format
H:MM:SSbzw.MM:SS - Uhrzeit (schlichtes Zifferblatt-Icon: Kreis + zwei Zeiger, keine
Krone) — aktuelle Tageszeit, Format
HH:MM
Sitzt zwischen Nav-Pille/Spur-Anzeige (y≈132) und der Speed-Zahl (Ziffern
beginnen ≈y177). Icon fest bei
x=210, Wert linksbündig ab x=224 (nicht als Gruppe zentriert), damit die
unterschiedliche Zeichenbreite von 1:24:07 gegenüber 14:32 nicht bei
jedem Wechsel neu zentriert werden muss — dieselbe Technik wie beim
Nav-Chip-Icon+Text. Big Shoulders Display 600, 28px, PARCHMENT — wie alle
anderen Werte auf dem Screen, keine Sonderbehandlung.
Spur-Anzeige (Lane-Widget)¶
Ein gemeinsamer Rahmen (rx≈9, PANEL_BG, BRASS-Kontur 30–45%
Deckkraft) um alle Fahrspur-Pfeile — kein Rahmen pro Pfeil, das kostet
nur Platz ohne Mehrwert. Ein Pfeil pro echter Fahrspur:
- eindeutige Richtung → einfacher Pfeil,
BRASSvoll (empfohlen) oder 40–45% Deckkraft (nicht deine Spur) - mehrere Richtungen in einer Spur → ein Pfeil mit gemeinsamem Schaft, der sich in Äste aufspaltet (nicht zwei separate Pfeil-Icons nebeneinander — kollidiert bei kleiner Kachelgröße). Nur der Ast, der der tatsächlichen Route entspricht, in voller Deckkraft.
Konditional: nur sichtbar, wenn OsmAnd Spurdaten liefert. Auf dem
Mainscreen sitzt sie links der Nav-Pille, die dafür um 46px nach rechts
rutscht (animiert, ~600ms, mit Ruhephasen an beiden Enden — kein abruptes
Springen). Ohne Spurdaten bleibt die Nav-Pille an ihrer zentrierten
Grundposition (x=150).
Fahrzustand-Icon¶
Vier Zustände, alle fahrradbezogen (nicht abstrakt — ein einzelnes Laufrad allein liest sich bei 34px nicht zuverlässig als „Fahrrad"):
| Zustand | Motiv | Gedanke |
|---|---|---|
| Fahren | Fahrrad (2 Laufräder + Rahmen) | Grundzustand |
| Cruise | dasselbe Fahrrad, kleiner + Lupe oben rechts | bewusst langsam, am Suchen (Sightseeing, Eisdiele, Brunnen) statt am Fahren |
| Stop | Stoppschild (Oktagon) | kurzer, unfreiwilliger Halt (Ampel) |
| Pause | Tasse | längere, selbst gewählte Rast |
EEZ-Assets bereits vorhanden: img_rr_icon_state_power (Fahren),
img_rr_icon_state_coasting (Cruise), img_rr_icon_state_stop,
img_rr_icon_state_break (Pause) — 34×34, ALPHA_8BIT. Pfad-Referenz für
das Fahrrad-Grundmotiv (Konstruktion, falls ein Icon neu gebaut werden
muss):
Laufräder: Kreis r=3.2 bei (-5.5, 3) und (5.5, 3)
Rahmen: M-5.5,3 L-0.8,3 M-0.8,3 L-3,-4.3 M-0.8,3 L3.8,-4.8
M3.8,-4.8 L5.5,3 M-3,-4.3 L3.8,-4.8
Sattel/Lenker-Kappen: M-4.2,-4.6 L-1.8,-4 M2.8,-5.6 L4.8,-4.2
Straßenqualität-Indikator¶
Umgesetzt als rr_line_rq, ein einzelnes LVGLLineWidget. Kein Icon, keine
Beschriftung — die Farbe ist die Information, bewusst minimal („nur die
Qualitätsklasse als kleiner farbiger Indikator", BMI160-basiert).
- Sitzt im Container
rr_group_rq_modedirekt unter dem Fahrzustand-Icon (align=BOTTOM_MID, Widget140×5, Linie0,0 → 115,0,line_width=5) — ein dünner Balken knapp über der Bildschirmkante. - Klasse
n(1–5) →line_colorauf die entsprechende der fünf HF-Zonenfarben (§1,ZONE_BLUE…ZONE_RED,theme_colors[26..30]) — glatt = blau, sehr rau = rot, dieselbe Reihenfolge wie die HF-Leiste. - Klasse 0 (noch keine Daten oder zu langsam/Stillstand) → Widget bleibt
sichtbar,
line_coloraufRRBrass(derselbe Messington wie der Rest der UI) statt einer der fünf Zonenfarben — bewusst kein Ein-/Ausblenden bei jeder Ampelpause, die Linie ist durchgehend präsent, nur die Farbe trägt die Information. Identisch mit dem JSON-Default in EEZ Studio, vor der ersten echten Klasse. - Auf allen fünf Screens identisch:
rr_group_rq_mode(ContainerBOTTOM_MID, Offset(0,-5),197×40, darin Fahrzustand-IconTOP_MIDundrr_line_rqBOTTOM_MID) ist 1:1 alsrq_group_rq_mode(RQ-Ride),rrnav_group_rq_mode(Navigation),rrset_group_rq_mode(Einstellungen) undrrclimb_group_rq_mode(Kletter-Screen) kopiert. Icon und Linienfarbe setzenui_RimRidgeUpdateStateIcon()/ui_RimRidgeUpdateRoadQuality()auf allen Kopien. Tipp auf die Gruppe öffnet den RQ-Ride-Screen, auf dem RQ-Ride-Screen selbst geht es damit zurück zum Mainscreen (ActionGoToRq). Änderungen an der Gruppe immer auf allen fünf Screens gleich machen. - Verdrahtet in
ui_RimRidgeUpdateRoadQuality()(src/ui/RimRidgeCustFunc.cpp) — DatenketteRoadQuality/I2CSensors→Statistics::updateRoadQualityUi()→UIFacade::updateRoadQuality().
5. Icon-Bibliothek¶
| Icon | EEZ-Asset | Konstruktion |
|---|---|---|
| WLAN | img_rr_icon_wifi |
Punkt + zwei konzentrische offene Bögen |
| GPS | img_rr_icon_gps |
Pin-Kontur (Bézier) + Kreis |
| Akku | img_rr_icon_battery |
Rechteck + Pol-Nase, Füllstands-Rechteck innen (SAGE = gut) |
| Nav-Abbiegepfeil | img_rr_icon_turn |
gewinkelte Linie + Pfeilspitze, 64×64 (größer, da Hero-Element auf dem Nav-Screen) |
| Cadence | img_rr_icon_cadence |
offener Kreisbogen + Pfeilspitze (rotierende Bewegung) |
| Watt | img_rr_icon_power |
Blitz-Polygon |
| Temperatur | img_rr_icon_temp |
Thermometer (Rechteck + Kreis-Bulb) |
| Höhe | img_rr_icon_height |
Bergsilhouette (Polyline) — Rückgriff auf das Bootlogo-Ridge-Motiv, SAGE |
| Steigung | img_rr_icon_gradient |
diagonale Linie + Winkel-Pfeilspitze |
| Herzfrequenz | img_rr_icon_heart |
zusammengesetzte Bézier-Herzform |
| Pause (Button) | img_rr_icon_pause |
zwei vertikale Balken |
| Einstellungen (Button) | — (noch kein eigenes rr_icon_-Asset, siehe unten) |
Kreis + Nabe + 6 radiale Zähne, 60°-Abstand |
| Fahrzustand ×4 | img_rr_icon_state_{power,coasting,stop,break} |
siehe §4 |
| Neustart (Settings) | img_rr_icon_cadence (wiederverwendet) |
Cadence-Icon (Kreisbogen + Pfeilspitze) als „rotierend/zurücksetzen" |
| Tiefschlaf (Settings) | img_rr_icon_moon |
Vollkreis r=8 minus versetzter Kreis r=7 bei (4.5,−2.5) („ausgestanzte" Mondsichel), ALPHA_8BIT |
| Stoppuhr (Fahrzeit) | img_rr_icon_stopwatch |
Kreis + kleine Krone/Taste oben + zwei Zeiger — siehe §4 „Fahrzeit / Uhrzeit" |
| Uhr (Uhrzeit) | img_rr_icon_clock |
wie Stoppuhr, aber ohne Krone — teilt sich denselben Widget-Slot mit dem Stoppuhr-Icon |
| Wegzähler (RQ-Ride) | noch nicht exportiert | Lineal-Motiv: waagrechte Linie + vier senkrechte Teilstriche (bewusst abstrakt wie das Cadence-/Steigungs-Icon, nicht wörtlich „Kilometerzähler") |
| Aufnahme-Taste (RQ-Ride) | noch nicht exportiert | Bereit-Zustand: Kreis + Ring + kleiner roter Punkt (Kamera-/Record-Sprache); Aufnahme-Zustand (nicht als Bild gezeichnet, nur beschrieben): Kreis voll rot + helles Stopp-Quadrat, dickerer roter Rahmen statt BRASS. Rot = ZONE_RED/#C1604A, dieselbe Zweitverwendung wie bei den Log-Level-Badges im Web-Dashboard (--rr-err) |
img_settings_icon existiert bereits (48×48, TRUE_COLOR_ALPHA — anderes
Format als der Rest, volltonig statt Alpha-Maske), das Icon des
Settings-Buttons auf dem Mainscreen. Vor Wiederverwendung in EEZ Studio
prüfen, ob der Export sauber ist (ein Test-Dekodieren ergab Streifen im
oberen Teil); die Zahnrad-Konstruktion oben ist der Ersatz, falls nötig.
6. Screens¶
Mainscreen — mainscreen.svg¶

Reihenfolge von innen nach außen: Speed (Zentrum, 130px, dominant) →
Cadence/Watt (flankierend, schmale Spalten bei x=80/400) →
Temp/Höhe/Steigung (Reihe bei y≈325) → HF-Wert + Zonenband (y≈353–380) →
Fußzeile (Pause-Taste links, Settings-Taste rechts, dazwischen eine
gemeinsame Spalte rr_tour_pill bei x173–307/y378–480: Distanz →
Modus-Chip → Fahrzustand-Icon 34px → Straßenqualität-Indikator, alle
vier senkrecht gestapelt statt nebeneinander — siehe §4 „Straßenqualität-
Indikator" für die Begründung) → außen der Speed-Arc mit Ø-Marker → oben
Statuszeile (WLAN/GPS/Akku) und Nav-Pille, links davon konditional die
Spur-Anzeige, darunter die Fahrzeit/Uhrzeit (y≈157, siehe §4) in der Lücke
zwischen Nav-Pille und Speed-Zahl.
Navigationsscreen — navscreen.svg¶

Blendet sich automatisch als Vollbild ein, wenn eine Nav-Anweisung ansteht, und danach wieder aus (zurück zum Mainscreen). Manuell: Tipp auf die Nav-Pille öffnet ihn, Wischen nach rechts schließt ihn.
Aufbau: Distanz-Ring (gleicher Mechanismus wie der Speed-Arc, siehe §4) →
großes Abbiege-Icon + Entfernung (Zahl in zwei Größen: 84px Wert + 34px
Einheit als tspan, damit die Einheit nicht gleich groß wie die Zahl
wirkt) → Straßenname darunter, gedämpft → übernächster Hinweis als kleines
Badge oben rechts, bewusst außerhalb der Hauptlesespur → Geschwindigkeit +
Steigung als mittelgroßes Paar → Herzfrequenz ganz unten, hier nur Farbe +
Zahl, kein Zonenband (auf diesem Screen sekundär). Spur-Anzeige oben,
gleiches Widget wie auf dem Mainscreen, hier bei voller Größe (scale
1.2 statt 0.75, mehr Platz vorhanden).
Bewusst ohne Fahrzeit/Uhrzeit-Widget: der Screen ist eng auf die anstehende Abbiegung zugeschnitten, und für die ambiente Info „wie lange fahre ich schon" ist der kurz eingeblendete Nav-Screen der falsche Ort — die gehört auf den Mainscreen, wo sie durchgehend sichtbar ist.
Einstellungen — settings.svg¶

Umgesetzt als RimRidgeSettings. Gegenüber der SVG-Studie
(Zahnrad, Titel, Build, IP, Neustart, Tiefschlaf) kamen WLAN-Reconnect,
IMU-Kalibrierung und Referenzfahrt dazu, damit sie unterwegs ohne Web bedienbar
sind (Bedienung unterwegs). Neustart und Tiefschlaf stehen deshalb
nebeneinander statt untereinander. Kein Statuszeilen-Kopf, aber unten die
gemeinsame Fahrzustand/RQ-Gruppe (§4). Öffnen: Tipp auf rr_btn_settings;
zurück: Wischen in beliebige Richtung. Logik: src/ui/RimRidgeSettingsCustFunc.cpp.
| Element | Box (x, y, w, h) | Font/Farbe | Inhalt |
|---|---|---|---|
rrset_ic_gear |
216, 24, 48, 48 | SettingsIcon, BRASS |
|
rrset_title |
TOP_MID, y=78 | 14, Abstand 3, BRASS |
„EINSTELLUNGEN" |
rrset_build_caption / _val |
TOP_MID, y=108 / 126 | 14 MUTED / 18 PARCHMENT |
v0.0.2-88 (51c4300) #1277 = Tag-Commits (Hash) #Build-Nr. |
rrset_ip_caption / _val |
TOP_MID, y=156 / 174 | 14 MUTED / 22 PARCHMENT |
IP, „… (AP)", oder „WLAN aus" / „verbinde ..." / „Verbindung verloren" / „kein WLAN gefunden" |
rrset_btn_wifi |
135, 208, 210, 40 | Pille, 18 | „WLAN verbinden"; DISABLED („verbinde ...", „WLAN verbunden") solange nicht offline |
rrset_btn_cal / rrset_btn_ref |
50/245, 258, 185, 40 | Pille, 18 | „Kalibrieren" / „Referenzfahrt" (läuft: „Abbrechen") |
rrset_cal_status / rrset_ref_status |
50/245, 302, 185, 2 Zeilen | 14, MUTED; läuft PARCHMENT, Fehler ZONE_RED |
„kalibriert 25.09.", „still halten ... 67 %", „Fehler: bewegt" / „Standard (150 mg)", „23 / 60 s ab 12 km/h", „142 mg 27.09." |
rrset_btn_reset / rrset_btn_sleep |
85/245, 346, 150, 40 | Pille mit Icon + 18 | Long-Press |
rrset_hint |
TOP_MID, y=392 | 14 MUTED |
„lange drücken" → „loslassen: Neustart" |
Pillen: PANEL_BG voll deckend, Rahmen BRASS 2 px bei border_opa 90,
PRESSED: Rahmen voll + Fläche TOUR_BG, DISABLED: Rahmen border_opa 40,
Text MUTED.
Entschiedene Punkte:
- Neustart/Tiefschlaf lösen per Long-Press aus und werden erst nach dem Loslassen ausgeführt: Tiefschlaf weckt über den Touch-Interrupt, ein noch aufliegender Finger würde sofort wieder wecken. Vorher werden Distanz (NVS) und Log-Dateien gesichert.
- Kalibrieren und Referenzfahrt starten per einfachem Tipp. Beides überschreibt erst bei Erfolg etwas; die Referenzfahrt lässt sich mit demselben Knopf abbrechen.
- Der WLAN-Knopf verbindet nur neu, wenn das WLAN aus ist (nach 100 s ohne Verbindung oder nach Verbindungsverlust schaltet es sich ab). AP-Modus und mehrere Zugangspunkte sind noch offen.
- Keine Helligkeitsregelung (Entscheidung: das dunkle Design ist auch nachts nicht zu hell; ggf. später ein kontraststärkeres Tag-Design).
Kletter-Screen — climbscreen.svg¶

Umgesetzt als RimRidgeClimb. Zeigt den Anstieg aus dem
Höhenprofil von TrailBridge; Erkennung, Kategorien und Einstellwerte stehen in
Anstiege. Blendet sich an bewerteten Anstiegen selbst ein und
danach wieder aus. Manuell: Tipp auf Höhe oder Steigung des Mainscreens
(Action GoToClimb), Wischen in beliebige Richtung schließt. Logik:
src/ui/RimRidgeClimbCustFunc.cpp.
Die Rangfolge folgt dem, was man am Berg wissen will: wie viel noch (Hero), wie steil gleich (Profil, Steigung voraus in ihrer Farbe), erst dann Tempo und Puls. Kein Statuszeilen-Kopf, unten die gemeinsame Fahrzustand/RQ-Gruppe.
| Element | Box (x, y, w, h) | Font/Farbe | Inhalt |
|---|---|---|---|
rrclimb_arc |
5, 5, 470, 470 | Gapped Arc (§4) | Anteil der geschafften Höhenmeter |
rrclimb_cat |
TOP_MID, y=46 | 18, Abstand 2, BRASS |
„KAT. 3", „KAT. HC", „ANSTIEG" (nicht bewertet), „KEIN ANSTIEG" |
rrclimb_rem_val |
TOP_MID, y=62 | 48, PARCHMENT_BRIGHT |
Höhenmeter bis zum Gipfel, „212 m" |
rrclimb_grp_total |
86, 112, 150, 32 | Höhen-Icon SAGE + 18 |
Höhenmeter des ganzen Anstiegs, „von 340 m" |
rrclimb_grp_dist |
250, 112, 144, 32 | Lineal-Icon + 18 | Strecke bis zum Gipfel, „2.4 km" |
rrclimb_profile |
60, 150, 360, 126 | PANEL_BG, Rahmen BRASS 1 px, rx=9 |
Profil, in C gezeichnet (unten) |
rrclimb_summit_alt |
im Profil, 8, 3 | 14, MUTED |
„Gipfel 812 m" / „kein Höhenprofil" |
rrclimb_grp_ahead |
70, 282, 160, 46 | 14 MUTED über 26 |
„NÄCHSTE 25 m" + mittlere Steigung voraus, in ihrer Profilfarbe |
rrclimb_grp_grad |
250, 282, 160, 46 | 14 MUTED über 26 PARCHMENT |
„GEMESSEN" + gemessene Steigung |
rrclimb_grp_speed |
96, 334, 136, 32 | 26 + Einheit 14 MUTED |
Geschwindigkeit, rechtsbündig an der Einheit |
rrclimb_grp_heart |
262, 334, 110, 32 | Herz-Icon + 26 | Puls |
rrclimb_grp_info |
188, 370, 150, 32 | Icon + 22 | Wechselfeld: Uhrzeit, Distanz, Temperatur, Trittfrequenz, Höhe; Icon wechselt mit, Einblenden 400 ms |
rrclimb_group_rq_mode |
BOTTOM_MID | gemeinsame Gruppe (§4) |
Profil: eine Spalte je Pixel, Höhe aus dem linear interpolierten Profil,
Farbe aus der Steigung des 25-m-Abschnitts in fünf Bändern auf den
Zonenfarben (§1): unter 1 % ZONE_BLUE, bis 4 % ZONE_GREEN, bis 7 %
ZONE_YELLOW, bis 10 % ZONE_ORANGE, darüber ZONE_RED. Nach den HF-Zonen
und dem RQ-Indikator die dritte Stelle, an der Farbe Funktion trägt, mit
derselben Bedeutung ruhig → hart. Der gefahrene Teil steht bei 35 %
Deckkraft, der Fahrer ist eine helle senkrechte Linie mit Punkt auf dem
Profil, der Gipfel trägt ein Fähnchen in BRASS. Sichtbar ist der Anstieg
von 100 m vor dem Fuß bis 150 m hinter dem Gipfel; die Höhenskala umfasst
mindestens 20 m, damit ein kleiner Hügel nicht wie ein Pass aussieht.
Entschiedene Punkte:
- Der Hero ist „noch bis oben" mit Einheit in derselben Größe („212 m"), als ein zentriertes Label. Zahl und Einheit in zwei Größen bräuchten eine feste Spalte, und die Zahl hat zwei bis vier Stellen.
- „von 340 m" setzt den Hero fort („212 m von 340 m") und spart eine Beschriftung.
>vor Werten, solange der Gipfel nicht im Profil liegt (kommt nicht mehr vor: das Handy schickt den Anstieg bis zum Gipfel).- Das Wechselfeld zeigt immer nur einen Wert mit seinem Icon. Fehlende Werte (kein Trittfrequenz-Sensor, keine Temperatur) werden übersprungen.
RQ-Ride-Screen — rqscreen.svg¶

Ein eigener Ride-Screen fürs gezielte Sammeln von Referenzdaten zur
Straßenqualität: Untergrund und subjektive Qualität von Hand markieren,
während optional eine Detailaufzeichnung läuft — ergänzt die automatische
Klassifikation (§4 „Straßenqualität-Indikator") um echte Ground-Truth-Daten,
z. B. für den Vergleich mit OSM-Tags oder zum
Nachschärfen der Schwellwerte in RQ::Config::classThr. Wie beim
Einstellungen-Screen bewusst ohne Statuszeile (WLAN/GPS/Akku) — der
Platz geht an die Bedienelemente unten, die auf diesem Screen den Vorrang
haben.
Aufbau von oben nach unten:
| Element | y (Zentrum/Baseline) | Größe/Wert | Hinweis |
|---|---|---|---|
| Nav-Pille | 30–70 | wie Mainscreen | von y=92 auf y=30 verschoben (§3-Formel an der neuen Höhe geprüft) |
| Geschwindigkeit | 140 (Wert) / 163 (Einheit) | 60px, PARCHMENT_BRIGHT |
„mittelgroß", gleichrangig mit RQ-Index |
| RQ-Index | 140 (Wert) / 163 (Caption) | 60px, Zonenfarbe (§1) | Ziffer 1–5 in der Farbe der aktuellen Klasse, kein Ausblenden bei 0 (Konvention wie rr_line_rq) |
| Puls | 185 (Icon) / 215 (Wert) | 22px | Herz-Icon wiederverwendet, kein Zonenband (zu klein für diesen Screen) |
| Wegzähler | 184 (Icon) / 215 (Wert) | 20px | neues Lineal-Icon (§5), Wert+Einheit ein String wie die Mainscreen-Distanz |
| Untergrund-Pillen | 240–318 | 6× 100×36, rx=18 |
Text-Pillen ohne Icon (Begründung: §2-Lektion zur Icon-Mindestgröße), 2×3-Raster: Asphalt/Schotter/Waldweg/Feldweg/Pflaster/Sonstiges |
| Qualität | 360 | 4× r=20 |
Segmentierter Wähler (§4), Stufen 1–4 |
| Aufnahme-Taste | 166 | r=28 |
in der freien Mittelspalte zwischen Geschwindigkeit und RQ-Index (212,138,56,56); unten sitzt die gemeinsame Fahrzustand/RQ-Gruppe (§4) |
Warum ein 4-stufiger Wähler statt der automatischen 5 Klassen: die
automatische Klassifikation (RQ::IntervalResult::roadClass, 1–5) und die
subjektive Nutzerbewertung hier sind bewusst getrennte Skalen — vermischen
würde verschleiern, ob eine Abweichung an der Wahrnehmung oder am Algorithmus
liegt. 4 statt 5 Stufen, weil eine Nutzerbewertung „exakt in der Mitte"
ohnehin selten trennscharf ist; falls sich in der Praxis zeigt, dass 5
Stufen für den Soll/Ist-Vergleich nötig sind, lässt sich ein fünfter Kreis
mit gleichem Abstand (60px) ergänzen, ohne das Muster zu ändern.
Speicherung und Verdrahtung: Das
manuelle Label landet als eigener Satztyp (LogRec::Label, Satztyp 3) im
Binärlog, zusätzlich in jedem Stoß-Satz und jedem Rohdaten-Block (siehe
src/LogRecords.h, Tools/bikelog/record.py); Firmware-API dafür ist
I2CSensors::setRoadLabelSurface()/setRoadLabelQuality()/
startRoadCapture()/stopRoadCapture()/getRoadLabelState(). Die 6
Untergrund-Pillen, die 4 Qualitätskreise und die Aufnahme-Taste sind über
direkte lv_obj_add_event_cb()-Aufrufe verdrahtet (nicht als EEZ-Actions —
11 fast identische Actions für reine Logik ohne Screen-Wechsel hätten
keinen Mehrwert gehabt), siehe ui_RimRidgeRQInitLabelControls()/
ui_RimRidgeRQUpdateLabel() in src/ui/RimRidgeRQCustFunc.cpp. Start/Stopp
ist ein einfacher Tap (kein Long-Press) — ein erneuter Tap auf die aktive
Pille/den aktiven Kreis setzt sie auf "keiner" zurück, ein Tap auf die
Aufnahme-Taste stoppt einen laufenden Mitschnitt. Die Anzeige liest den
Zustand dabei immer aus getRoadLabelState(), nie aus dem Tap selbst, weil
ein Mitschnitt nach spätestens 30 min von selbst endet und das Label einen
Neustart nicht übersteht.
7. Hinweise für die EEZ-Studio-Umsetzung¶
- Bild-Icons:
LV_IMG_CF_ALPHA_8BIT, perlv_obj_set_style_img_recolorzur Laufzeit aufRR_BRASS(oder die jeweilige Zonenfarbe) eingefärbt — nicht Farbe ins Bitmap backen. Mindestgröße 32–34px, siehe §2. - Arc-Widgets: beide Ringe (Speed, künftig Distanz) sind Standard-
lv_arcmit den Winkeln/Werten aus §4 — kein Custom-Drawing nötig. - Namenskonvention (aus dem bestehenden Mainscreen ableitbar):
rr_<element>für Widgets,rr_ic_<name>für Icons,rr_btn_<name>für Buttons,_val/_unit-Suffix für Wert/Einheit-Paare,_pill/_bgfür Chip-Flächen. - Screens:
SCREEN_ID_RIM_RIDGE,SCREEN_ID_RIM_RIDGE_NAV,SCREEN_ID_RIM_RIDGE_RQ,SCREEN_ID_RIM_RIDGE_SETTINGS,SCREEN_ID_RIM_RIDGE_CLIMB. Präfixe der Widgets:rr_,rrnav_,rq_,rrset_,rrclimb_. - Selbst gezeichnete Inhalte: ein Container im EEZ-Projekt legt Lage und
Rahmen fest, C zeichnet im Draw-Event hinein (
rrclimb_profile). Der Canvas zeigt dann den leeren Rahmen. - Prüfen auf dem Gerät: Screenshot und synthetische Touches per
Tools/uishot.py(siehe Debugging, „Oberfläche aus der Ferne testen"). - Fahrzeit/Uhrzeit-Widget:
rr_ic_time(Icon) +rr_time_val(Text) aufrim_ridge. Welcher Zustand gilt, entscheidet die Firmware (ui_RimRidgeUpdateTime()).