XTend Dokumentation
Dunkelmodus aktivieren

XTend Developer Center

Build with XTend today

RMT AnimationEngine

Die RMT AnimationEngine beschreibt UI-Übergänge zusammen mit den Surfaces und Actions, die sie auslösen. Effekte, Dauer, Easing, Unterbrechungsverhalten und barrierearme Fallbacks werden dadurch bereits beim Build geprüft, statt erst in verteiltem Browsercode sichtbar zu werden.

Voraussetzungen

Du benötigst eine RMT-vNext-Quelle mit mindestens zwei Surfaces und einer Action, die zwischen ihnen wechselt. Für ein ausgeliefertes Bundle muss der Maraca-Build mit Orchestrierung und Transitions aktiviert sein. Der lokale Compiler liegt in tools/rmt-language/vnext-compiler.js; die Browser-Runtime wird über xtendrmt/rmt-animation-engine-runtime.js bereitgestellt.

xt rmt lint app.rmt --json
xt rmt build app.rmt --bundle maraca --orchestration strict --transitions strict --out dist --json

Der Build muss im Orchestrierungsartefakt das Schema xtend.rmt.animation-engine.v1 ausgeben. Zur Laufzeit meldet die Engine xtend.rmt.animation-engine-runtime.v1 und stellt unter anderem runSurfaceTransitionPhase(), listActiveAnimations() und snapshot() bereit.

Eine Transition deklarieren

Das folgende Dokument verbindet eine Action mit zwei Surfaces. animation docs.motion.detail ist das wiederverwendbare Preset; transition docs.motion.openDetail bindet es an den konkreten Zustandswechsel. Der Host muss keine CSS-Klasse erraten und keine Action nachträglich beobachten.

template docs.motion.example {
  state docs.motion.list type object preserve {
    initial {
      id "list"
      hidden false
    }
  }

  state docs.motion.detail type object preserve {
    initial {
      id "detail"
      hidden true
    }
  }

  selector docs.motion.list from state docs.motion.list {
    output MotionSurface
  }

  selector docs.motion.detail from state docs.motion.detail {
    output MotionSurface
  }

  action docs.motion.openDetail {
    input source string
    reduce state.docs.motion.list.hidden = true
    reduce state.docs.motion.detail.hidden = false
    emit docs.motion.changed with surface "detail"
  }

  animation docs.motion.detail {
    effect slide-left
    durationMs 240
    easing "cubic-bezier(.2,.8,.2,1)"
    reducedMotion fade
  }

  transition docs.motion.openDetail {
    trigger action docs.motion.openDetail
    from surfaces [docs.motion.list]
    to surfaces [docs.motion.detail]
    use animation docs.motion.detail
    layoutKey "docs-motion-content"
    interrupt replace
    reducedMotion fade
    lane transition
  }

  portal docs.motion.root root "#app" layer surface

  surface docs.motion.list kind view component x-section {
    source selector docs.motion.list
    key list.id
    portal docs.motion.root
    lane visible weight 80 {
      mount docs-motion-list from selector docs.motion.list
    }
  }

  surface docs.motion.detail kind view component x-section {
    source selector docs.motion.detail
    key detail.id
    portal docs.motion.root
    lane visible weight 80 {
      mount docs-motion-detail from selector docs.motion.detail
    }
  }
}

Der Compiler löst use animation auf und überträgt Effekt, Dauer, Easing und Reduced-Motion-Policy in den Transition-Record. Explizite Werte im transition-Block dürfen das Preset für diesen einen Wechsel überschreiben. Die Transition-Lane trennt die sichtbare Bewegung von Daten- oder Hintergrundarbeit.

Effekte und Layout

Die aktuelle Effektliste umfasst fade, crossfade, vier Slide-Richtungen, scale, pop, zoom, flip, rotate, expand, collapse, fade-blur, shared-element, layout-flip und none. Für gewöhnliche Inhalte sind fade, slide-left, slide-right und pop gute Startpunkte. Bewegung über große Distanzen oder lange Laufzeiten erschwert Orientierung und sollte nicht als Standardnavigation dienen.

shared-element und layout-flip benötigen einen stabilen layoutKey. Ohne diesen Schlüssel kann der Compiler die korrespondierenden Layoutzustände nicht verbinden und meldet rmt.animation.layout_key_missing. crossfade wird als überlappende Enter-/Exit-Phase abgesenkt; andere Effekte verwenden standardmäßig serielle Phasen. Eine timeline kann die Reihenfolge explizit als parallel oder sequenziell festlegen.

Wird eine laufende Transition erneut ausgelöst, steuert interrupt das Verhalten. replace übernimmt die neueste Nutzerabsicht, finish wartet auf den laufenden Übergang und cancel verwirft ihn. Für Navigation ist replace meist die robusteste Wahl, weil eine schnelle zweite Aktion nicht hinter einer alten visuellen Entscheidung warten muss.

Eigene Keyframes und Spring-Sampling

Ein Preset darf eigene Enter- oder Exit-Keyframes definieren. Standardmäßig akzeptiert der Compiler nur opacity und transform; damit bleibt der übliche Pfad compositorfreundlich. Eine Spring-Definition wird beim Build in feste Samples übersetzt, sodass die Browser-Runtime keine Physik neu berechnen muss.

template docs.motion.popExample {
  animation docs.motion.pop {
    effect pop
    durationMs 240
    easing "cubic-bezier(.18,.9,.22,1)"
    keyframe enter {
      opacity 0
      transform "scale(.92)"
      offset 0
    }
    keyframe enter {
      opacity 1
      transform "scale(1)"
      offset 1
    }
    spring {
      stiffness 210
      damping 22
      mass 1
    }
    reducedMotion fade
  }
}

Filter sind absichtlich ausgeschlossen, solange ein Preset sie nicht einzeln erlaubt. Für fade-blur muss deshalb allowFilter true vorhanden sein. Diese Ausnahme sollte kurz bleiben, weil ein Blur über einen großen Text- oder Tabellenbereich deutlich teurer als Opacity und Transform sein kann.

template docs.motion.blurExample {
  animation docs.motion.blur {
    effect fade-blur
    durationMs 180
    easing "ease-out"
    allowFilter true
    keyframe enter {
      opacity 0
      filter "blur(6px)"
      offset 0
    }
    keyframe enter {
      opacity 1
      filter "blur(0px)"
      offset 1
    }
    reducedMotion fade
  }
}

Reduced Motion und Laufzeitverhalten

reducedMotion fade ersetzt den gewählten Effekt durch einen kurzen Fade von höchstens 120 ms, wenn der Browser prefers-reduced-motion: reduce meldet. instant und none führen ohne sichtbare Bewegung zum Zielzustand. Die Runtime liest die echte Browserpräferenz; Produktionscode darf matchMedia dafür nicht überschreiben.

Die Live-Demo oberhalb dieses Artikels verwendet dieselbe Runtime und einen vorab kompilierten Plan. Die Auswahl verändert nur eine begrenzte Vorschaukopie des AOT-Records. Systemeinstellung übernimmt die Browserpräferenz, während die drei Vorschauoptionen den jeweiligen Fallback über einen injizierten Testadapter sichtbar machen. Die Demo verändert keine Browser-Globals und lädt während des Replay keine Daten nach.

AnimationEngine-Ereignisse wie xtend-rmt:animation-start, xtend-rmt:animation-phase, xtend-rmt:animation-complete, xtend-rmt:animation-interrupt und xtend-rmt:animation-fallback eignen sich für Telemetrie. Der kanonische Zustand bleibt trotzdem in RMT State und Surface Runtime; Ereignisse sind Beobachtungssignale, keine zweite State-Quelle.

Erwartetes Ergebnis

Nach einem erfolgreichen Build enthält das Maraca-Artefakt einen AnimationEngine-Plan mit aufgelösten Presets, Transition-Zielen, Scheduler-Records und Reduced-Motion-Policies. Beim Auslösen der Action animiert die Runtime Exit und Enter, aktualisiert danach die Surface-Sichtbarkeit und räumt aktive Animationen auf. snapshot() zeigt aktive Records, Fallback-Zähler, die letzten Ergebnisse und redigierte Diagnostics.

Die vollständige Produktprobe unter products/rmt-animation-testbench zeigt zusätzlich SSR Resume, XScaler-Preflight und mehrere lazy Surfaces. Starte sie bei Bedarf mit:

npm --prefix products/rmt-animation-testbench run build
npm --prefix products/rmt-animation-testbench run dev

Danach ist die TestBench standardmäßig unter http://127.0.0.1:9196/ erreichbar.

Fehlerbehebung

SignalUrsacheBehebung
rmt.animation.effect_unknownDer Effekt gehört nicht zum Compilerkatalog.Nutze einen Effekt aus der Liste dieses Artikels und kompiliere erneut.
rmt.animation.reference_missinguse animation verweist auf kein bekanntes Preset.Gleiche die vollständig qualifizierten IDs von Animation und Transition ab.
rmt.animation.layout_key_missingshared-element oder layout-flip besitzt keinen layoutKey.Vergib auf der Transition einen stabilen Schlüssel für beide Layoutzustände.
rmt.animation.filter_opt_in_missingfade-blur verwendet Filter ohne Freigabe.Setze allowFilter true im referenzierten Animation-Preset.
rmt.animation.interrupt_invalidDie Interrupt-Policy ist unbekannt.Verwende replace, finish oder cancel.
rmt.animation.transition_reduced_motion_invalidDie Reduced-Motion-Policy ist ungültig.Verwende fade, instant oder none.
rmt.animation_engine.xutils_missingDie Runtime findet keinen lokalen XUtils-Transition-Runner.Binde components/xutils.js lokal vor der AnimationEngine ein; die Engine degradiert bis dahin instantan.

Die vollständige Syntax steht in Validation und Transitions. Der RMT Authoring Guide ordnet Animationen in State, Actions und Surfaces ein; Motion und Kontrast beschreibt die zugehörigen Accessibility-Prüfungen.

(c) 2026 - CCS Networks | Powered by XRouter PHP Extension