8 Punkte von GN⁺ 2025-04-14 | 2 Kommentare | Auf WhatsApp teilen
  • Ein Beispiel für die vollständige Neugestaltung der UI für Wohnzimmergeräte auf Basis von Rust und WebAssembly
  • Es wurde eine Architektur entworfen, um auch auf Geräten mit sehr unterschiedlicher Leistung hohe Performance und geringe Eingabelatenz zu erreichen
  • Weg von React hin zu einem eigens entwickelten UI-SDK nur für Rust, um eine hohe Produktivität zu sichern
  • Verwaltung von Code-Komplexität und Performance durch eine auf Entity-Component-System (ECS) basierende Architektur
  • Eine ehrliche Analyse der Vor- und Nachteile sowie Probleme, die sich aus dem Einsatz von WebAssembly und Rust ergeben

Warum die Prime-Video-UI mit Rust und WebAssembly neu aufgebaut wurde

  • Amazon stand vor der Aufgabe, dieselbe Prime-Video-App auf verschiedenen Wohnzimmergeräten (Konsolen, Set-Top-Boxen, Streaming-Sticks, TVs usw.) auszuführen
  • Um auf Geräten mit sehr unterschiedlicher Leistung eine konsistente User Experience zu bieten, war eine performante UI-Engine unverzichtbar
  • Zuvor kam ein gemischter Tech-Stack aus React (TypeScript), JavaScript, C++, WebAssembly und Rust zum Einsatz
  • Wegen der langsamen Ausführung von JavaScript und der schwierigen Updates fiel die Entscheidung für eine vollständige Migration zu Rust
  • Mit WebAssembly lassen sich App-Updates leichter ausrollen, und Rust ist für Performance-Optimierung besonders geeignet

Zentrale Entwicklungsherausforderungen bei Wohnzimmergeräten

  • Es musste ein breites Spektrum an Leistungsklassen abgedeckt werden – von High-End-Geräten wie der PS5 bis zu stromsparenden USB-Sticks
  • Die Entwicklung musste mit einer einzigen Codebasis erfolgen, ohne für jedes Gerät ein eigenes Team aufzustellen
  • Auf den meisten Geräten sind nur Firmware-Updates ohne App-Store möglich, wodurch Updates für nativen Code schwierig sind
  • Für häufige UI-Updates ist Code auf Basis von JavaScript und WebAssembly im Vorteil
  • Als Kompromiss zwischen hohen Performance-Anforderungen und schnellen Update-Zyklen fiel die Wahl auf die Kombination aus Rust + WebAssembly

Vergleich der bisherigen Architektur mit der neuen Rust-basierten UI-Architektur

  • Die bisherige Architektur war wie folgt aufgebaut:
    • UI-Logik in React, während Rust (WebAssembly) die Low-Level-UI-Engine übernahm
    • React → Nachrichtenbus → WebAssembly-UI-Engine → C++-Rendering-Backend
  • Um Probleme mit der Eingabelatenz zu lösen, wurde die gesamte Business-Logik in das Rust-UI-SDK migriert
  • Die neue Architektur:
    • Vom UI-SDK bis zum Rendering komplett in Rust umgesetzt
    • Der Nachrichtenbus entfällt, alle Verarbeitungsschritte laufen innerhalb von WebAssembly
    • Der Code wird zu WebAssembly kompiliert und an den TV ausgeliefert, was Update-Geschwindigkeit und Reaktionsfähigkeit verbessert

Zentrale Bestandteile des neuen Rust-UI-SDK

  • Einführung eines Composable-Konzepts ähnlich wie in React → wiederverwendbare UI-Bausteine
  • Ein reaktives UI-System auf Basis von Signal und Effect
    • Signal: Wenn sich ein Wert ändert, wird der zugehörige Effect ausgelöst
    • Memo: Reagiert nur dann, wenn sich der vorherige Wert geändert hat
  • Die UI-Hierarchie wird über das Makro compose! definiert
  • UI-Elemente bestehen aus Widgets (mitgelieferten Komponenten) und Composables (benutzerdefinierten Strukturen)
  • Einsatz einer Entity-Component-System (ECS)-Architektur:
    • Entity: ID
    • Component: Attributdaten (z. B. Layout, RenderInfo, Text)
    • System: Eine Funktion, die Logik für eine bestimmte Kombination von Components ausführt

Aufbau und Funktionsweise des ECS-Systems

  • Jedes System benötigt bestimmte Kombinationen von Components und verarbeitet darauf basierend UI-Updates
  • Beispiele:
    • Resource Management System: Bild-Component → GPU-Upload → Update von RenderInfo
    • Layout System: Berechnung verschiedener layoutbezogener Components
    • Rendering System: Tatsächliche Bildausgabe auf Basis von RenderInfo
  • Diese Struktur ermöglicht die schrittweise Migration verschiedener Seiten von React nach Rust
  • Koexistenz und Wechsel zwischen JavaScript-basierten und Rust-basierten Seiten funktionieren reibungslos

Gute Ergebnisse und Vorteile

  • Auch JavaScript-/React-Entwickler konnten erfolgreich auf das Rust-UI-SDK wechseln, ohne Produktivitätsverlust
  • Dank der vertrauten Struktur des UI-SDK konnten sich auch Rust-Einsteiger schnell einarbeiten
  • Layout-Animationen, schnelle Bildschirmwechsel und andere zuvor unmögliche Funktionen ließen sich umsetzen
  • Interne Entwicklertools (Resource Manager, Layout Inspector usw.) konnten ebenfalls auf Basis von Rust schnell entwickelt werden
  • Die Eingabelatenz wurde massiv von 250 ms auf 33 ms reduziert (auf Geräten mit geringer Leistung)

Schwierigkeiten und technische Grenzen

  • Das WebAssembly System Interface (WASI) ist noch ein sich entwickelndes Ökosystem, sodass Rust-Updates bestehenden Code beschädigen können
  • In WebAssembly führt ein panic zum kompletten App-Absturz → schwierig für die Stabilität
    • Im Gegensatz zu JavaScript ist die Ausnahmebehandlung unzureichend → der Typ Result muss aktiv genutzt werden
    • Bei Abhängigkeiten von externen Bibliotheken muss auf panic-freie Implementierungen hingewirkt werden
  • In Browser-Umgebungen werden WebAssembly und bestimmte Rendering-APIs teils nicht unterstützt, daher kommt die Lösung im Web-Client nicht zum Einsatz

Bytecode Alliance und Beiträge zum Ökosystem

  • Amazon beteiligt sich als Mitglied der Bytecode Alliance aktiv an der Standardisierung von WASI und an Verbesserungen relevanter Funktionen
  • Die eingesetzte WebAssembly Micro Runtime basiert auf C; parallel wird auch das Rust-basierte Wasmtime geprüft
  • Für die Weiterentwicklung des WebAssembly-Ökosystems gibt Amazon direktes technisches Feedback und beteiligt sich an der Entwicklung

Sonstiges Q&A

  • Ist das auch im Webbrowser möglich? → Einige WebKit-Browser unterstützen WASM nicht, dazu kommen Performance-Einbußen und hohe Implementierungskomplexität; daher wird es derzeit noch geprüft
  • Eine Umsetzung mit WebGL wäre möglich, wird aber vorerst zurückgestellt, da der Nutzen im Verhältnis zum Aufwand aktuell gering erscheint

Zusammenfassung

  • Die Rust+WebAssembly-basierte UI von Prime Video erfüllt drei zentrale Ziele zugleich: hohe Performance, geringe Eingabelatenz und schnelle Updates
  • Das eigene UI-SDK und die ECS-Architektur ermöglichen eine effiziente Verwaltung komplexer UI-Abläufe
  • Die Einführung von Rust ist nicht einfach, doch mit systematischem Design und passender Entwicklungskultur lassen sich Produktivität und Stabilität zugleich erreichen
  • Das WebAssembly-Ökosystem befindet sich zwar noch in Entwicklung, ist aber für den produktiven Einsatz bereits gut praktikabel
  • Die erfolgreiche Einführung basierte auf gründlichem Prototyping und einer schrittweisen Migrationsstrategie

2 Kommentare

 
seunggi 2025-04-14

Im Vergleich zu Frontends, die standardmäßig mit State-Management-Bibliotheken arbeiten, denke ich bei Games eher, dass dort wirklich jeder State jeden anderen State beeinflusst und man es daher einfach auf die harte Tour macht. Umgekehrt wäre der Einsatz von ECS in Anwendungs-Apps wohl vergleichbar damit, dass jeder Entwickler oder jede eigene Bibliothek ein standardisiertes Muster für State-Management verwendet — daher würde mich interessieren, wie sie diesen Teil gelöst haben.

 
y15un 2025-04-14

ECS, das man sonst eher aus Game-Engines kennt, auf die UI anzuwenden – das ist schon eine ziemlich originelle Idee. Wieder etwas dazugelernt heute.