Zum Inhalt springen
    WingoUI
    KomponentenVorlagenDokuPreiseKI-AgentenBlogChangelog
    1. Startseite
    2. Blog
    3. Komponenten-Guides
    4. Framer Motion Spring: Presets für Stiffness und Damping
    Read in English
    1. Blog
    2. Komponenten-Guides
    3. Framer Motion Spring: Presets für Stiffness und Damping
    Komponenten-Guides
    Komponenten-Guides

    Framer Motion Spring: Presets für Stiffness und Damping

    SR
    Serban Rusu · Gründer von Wingo UI
    13. Okt. 2026 · 9 Min. Lesezeit

    Auf dieser Seite

    0%
    1. Wie funktioniert eine Framer Motion Spring Animation?
    2. Welche Werte für Stiffness und Damping sollte eine UI nutzen?
    3. Wie sieht jedes Spring Preset in echten Komponenten aus?
      1. Snappy für alles, was ein Finger berührt
      2. Smooth als Standard für Overlays und Layout
      3. Bouncy für einen Akzent pro Screen
      4. Gentle für große Flächen
    4. Wie teilst du Springs in einer Komponentenbibliothek?
    5. Können CSS Transitions dieselbe Spring nutzen?
    6. Welche Fehler lassen Springs falsch wirken?
    7. Was solltest du als Nächstes installieren?
    8. Häufige Fragen
      1. Welche Werte für Stiffness und Damping eignen sich für eine Framer Motion Spring?
      2. Welche Spring nutzt Framer Motion standardmäßig?
      3. Sollte ich duration und bounce oder stiffness und damping verwenden?
      4. Wie verhindere ich, dass eine Framer Motion Spring nachfedert?
      5. Ist Framer Motion dasselbe wie das Paket motion?

    Kurz gesagt

    Ein gutes Set an Framer Motion Springs ist klein: snappy (Stiffness 500, Damping 32) für Press-Feedback und Toggles, smooth (300 / 30) als Standard für Dialoge, Toasts und Layout, bouncy (400 / 18) für seltene verspielte Akzente und gentle (120 / 20) für große Flächen und Charts. Über das Gefühl entscheidet das Dämpfungsverhältnis damping / (2 * sqrt(stiffness * mass)): Unter 1 schwingt die Spring über, ab 1 nicht. Leg die vier in eine Datei, importier sie überall, statt Zahlen inline zu tippen, und tausch sie gegen eine sofortige Transition oder einen Fade, wenn jemand reduzierte Bewegung eingestellt hat.

    Veröffentlicht am 13. Okt. 2026

    Eine Framer Motion Spring besteht aus zwei Zahlen, die bestimmen, wie sich jeder Tap, jeder Toggle und jedes Popover in deiner App anfühlt. In den meisten Codebases landen Dutzende davon inline: hier stiffness: 400, damping: 17, dort 260 / 20, kopiert aus dem Tutorial, das an dem Tag gerade offen war. Dieses Tutorial ersetzt das durch vier benannte Presets. Es zeigt die echten Werte für Stiffness und Damping aus den Motion Presets von Wingo UI, misst, was jedes Preset tut, und erklärt, welche UI welche Spring bekommt und wie du sie in einer ganzen Komponentenbibliothek teilst.

    Das Paket heißt inzwischen motion. Der Upgrade-Guide auf motion.dev (opens in a new tab) (geprüft im Oktober 2026) ersetzt framer-motion durch motion und verschiebt die Imports nach motion/react. Die Spring-Optionen bleiben gleich: Eine Framer Motion Spring und eine motion react spring transition nehmen dieselben Werte stiffness, damping und mass. Alles hier nutzt motion 12.43.

    Wie funktioniert eine Framer Motion Spring Animation?

    Eine Spring hat keine feste Dauer. Motion simuliert eine Masse an einer Feder: stiffness bestimmt, wie stark die Feder zum Ziel zieht, damping ist die Reibung, die sie bremst, und mass gibt an, wie schwer das bewegte Objekt ist (standardmäßig 1). Die Animation endet, sobald der Wert nah genug am Ziel und langsam genug ist, um anzuhalten.

    Für die UI-Arbeit hat das zwei wichtige Folgen:

    1. Das Gefühl entsteht aus dem Verhältnis, nicht aus den rohen Zahlen. Das Dämpfungsverhältnis ist damping / (2 * Math.sqrt(stiffness * mass)). Unter 1 schießt der Wert über das Ziel hinaus und schwingt zurück. Ab 1 kommt er ohne Überschwingen an. Zwei Springs mit demselben Verhältnis wirken wie dieselbe Kurve in unterschiedlichem Tempo.
    2. Eine Spring behält ihre Geschwindigkeit, wenn du das Ziel änderst. Laut der Transition-Doku von Motion (opens in a new tab) übernehmen physikalische Springs die Geschwindigkeit laufender Gesten oder Animationen, zeitbasierte nicht. Tippst du zweimal schnell auf ein Segmented Control, biegt der Thumb zur neuen Option ab, statt anzuhalten und neu zu starten.

    Das Verhältnis prüfst du in einer Zeile:

    ts
    type SpringOptions = { stiffness: number; damping: number; mass?: number };
    // unter 1 schwingt über, ab 1 kommt ohne Überschwingen an
    export function dampingRatio({ stiffness, damping, mass = 1 }: SpringOptions) {
    return damping / (2 * Math.sqrt(stiffness * mass));
    }
    dampingRatio({ stiffness: 300, damping: 30 }); // 0.87
    dampingRatio({ stiffness: 400, damping: 18 }); // 0.45

    Welche Werte für Stiffness und Damping sollte eine UI nutzen?

    Wenn du nur Werte zum Kopieren suchst: Diese vier aus lib/motion.ts in Wingo UI sind die einzigen Springs, die unsere Komponenten nutzen.

    ts
    import type { Transition } from "motion/react";
    export const springs = {
    // Press-Feedback, Toggles, Switch-Thumbs, Häkchen: alles, was auf einen Finger reagiert
    snappy: { type: "spring", stiffness: 500, damping: 32 },
    // der Standard: Popovers, Menüs, Tab-Indikatoren, Layout-Wechsel, Dialoge
    smooth: { type: "spring", stiffness: 300, damping: 30 },
    // nur für verspielte Akzente: ein Like, ein aufpoppendes Badge, ein Erfolgshaken
    bouncy: { type: "spring", stiffness: 400, damping: 18 },
    // große Flächen und langsame Reveals: Sheets beim Einrasten, Seitenabschnitte, Chart-Balken
    gentle: { type: "spring", stiffness: 120, damping: 20 },
    } as const satisfies Record<string, Transition>;
    export type SpringName = keyof typeof springs;

    Wir haben jedes Preset mit dem spring()-Generator von motion selbst gemessen, aus motion-dom 12.43: ein Wert, der von 0 auf 100 animiert, mit Masse 1. „Innerhalb 1 %“ ist die Zeit, ab der der Wert nur noch höchstens eine Einheit vom Ziel abweicht.

    PresetStiffness / DampingDämpfungsverhältnisÜberschwingenInnerhalb 1 %Einsatz
    snappy500 / 320,724,0 %296 msPresses, Switches, Thumbs von Segmented Controls, Häkchen
    smooth300 / 300,870,4 %270 msDialoge, Toasts, Listenzeilen, Tab-Indikatoren, Layout
    bouncy400 / 180,4520,5 %439 msein Like, ein Badge, ein Erfolgsicon
    gentle120 / 200,91unter 0,1 %486 msChart-Balken, Seitenabschnitte, große Reveals
    Physik-Default von motion100 / 100,5016,3 %879 mswas du mit type: "spring" allein bekommst

    Lies die Tabelle aus Sicht der Nutzer, und denk daran: Die Einschwingzeit ist nicht die gefühlte Geschwindigkeit. Snappy legt 90 % der Strecke in 120 ms zurück, smooth braucht dafür 188 ms. Den Rest seiner Zeit verbringt snappy mit 4 % Überschwingen, und genau das fühlt sich an, als reagiere das Control direkt auf den Finger. Smooth kommt insgesamt etwas früher zur Ruhe, ohne sichtbares Überschwingen, also wackelt ein Dialog beim Öffnen nie. Bouncy schießt um ein Fünftel über: Auf einem Erfolgshaken macht das einmal Spaß, auf jedem Popover nervt es. Gentle braucht etwa eine halbe Sekunde und bleibt ruhig, das passt zu einem ganzen Chart, das sich aufbaut.

    Die letzte Zeile ist die Falle. Schreibst du transition={{ type: "spring" }} ohne Zahlen, fällt motion auf Stiffness 100 und Damping 10 zurück: fast eine Sekunde Einschwingen und 16 % Überschwingen. Gib immer ein benanntes Preset an.

    Die Demo unten ist gleichzeitig ein Framer Motion Spring Visualizer: Vier Bälle laufen nebeneinander mit den vier Springs. Wähl in den Playground-Controls eine Spring und spiel dann die Liste erneut ab, um sie an echten Zeilen zu sehen.

    Schau dir das Rennen der vier Bälle an: snappy und smooth landen gleichzeitig, bouncy schießt über, gentle kommt zuletzt. Dann spiel die Liste mit jeder Spring erneut ab.
    $ npx wingo-ui@latest add motion
    FreeDoku: Motion presets

    Wie sieht jedes Spring Preset in echten Komponenten aus?

    Snappy für alles, was ein Finger berührt

    Alle drückbaren Flächen der Bibliothek teilen sich denselben Press-Effekt: Skalierung auf 0,97 mit springs.snappy. Der kostenlose Button holt ihn aus einer einzigen Konstante, und deine eigenen Komponenten können das auch:

    tsx
    "use client";
    import { motion } from "motion/react";
    import { press } from "@/lib/motion";
    // press ist { whileTap: { scale: 0.97 }, transition: springs.snappy }
    export function LikeButton({ onLike }: { onLike: () => void }) {
    return (
    <motion.button
    type="button"
    onClick={onLike}
    {...press}
    className="h-10 touch-manipulation rounded-full bg-foreground/5 px-4 text-sm font-medium [-webkit-tap-highlight-color:transparent]"
    >
    Gefällt mir
    </motion.button>
    );
    }

    Der kostenlose Switch bewegt seinen Thumb mit animate(pos, checked ? 1 : 0, springs.snappy) auf einem Motion Value und dehnt den Thumb mit derselben Spring, solange er gedrückt bleibt. Das kostenlose Segmented Control schiebt seinen Thumb ebenfalls mit snappy und gibt dessen aktuelle Geschwindigkeit an die nächste Animation weiter. Ein zweiter Tap mitten in der Bewegung ändert die Richtung also ohne Ruck:

    ts
    // das Thumb-Muster des Segmented Control: neues Ziel ohne Tempoverlust
    animate(x, 0, { ...springs.snappy, velocity: x.getVelocity() });
    Tippe schnell auf Day, Week, Month und Year oder zieh den Thumb: Er behält sein Tempo, wenn du es dir mitten in der Bewegung anders überlegst.
    $ npx wingo-ui@latest add segmented-control
    FreeDoku: Segmented Control

    Der Guide zum React Segmented Control (auf Englisch) behandelt den Rest dieses Controls, vom ziehbaren Thumb bis zur Radio-Semantik.

    Smooth als Standard für Overlays und Layout

    Dialoge, Toasts, Listenzeilen und Inhaltswechsel erscheinen alle mit springs.smooth. Mit ihrem Verhältnis von 0,87 schwingt smooth 0,4 % über. Bei einem Dialog, der 8px nach oben an seinen Platz gleitet, sind das ein paar Hundertstel Pixel, also landet die Fläche weich und ohne sichtbares Wackeln. Popovers und Menüs sind die Ausnahme: Ihr Preset nutzt snappy, weil sie direkt auf einen Klick antworten. Smooth ist auch die richtige Spring für layout-Animationen, bei denen ein Bounce benachbarte Inhalte zittern ließe.

    tsx
    "use client";
    import { AnimatePresence, motion } from "motion/react";
    import { springs } from "@/lib/motion";
    export function SavedNotice({ show }: { show: boolean }) {
    return (
    <AnimatePresence>
    {show && (
    <motion.p
    initial={{ opacity: 0, y: 4 }}
    animate={{ opacity: 1, y: 0 }}
    exit={{ opacity: 0, transition: { duration: 0.15 } }}
    transition={springs.smooth}
    className="text-sm text-muted-foreground"
    >
    Änderungen gespeichert
    </motion.p>
    )}
    </AnimatePresence>
    );
    }

    Achte auf den Exit: ein kurzes Tween, keine Spring. Ein schneller Abgang wirkt reaktionsschnell, und der Auftritt darf sich Zeit lassen. Deshalb verschwinden die meisten Presets in lib/motion in 150 ms.

    Bouncy für einen Akzent pro Screen

    Bouncy gehört dorthin, wo ein kleiner Jubelmoment gewollt ist: Die Icon-Kachel eines Alert Dialogs poppt mit { ...springs.bouncy, delay: 0.06 } auf, und ein Erfolgshaken kann das genauso. Lass es weg bei allem, was Leute viele Male am Tag öffnen. Die 20 % Überschwingen, die beim ersten Mal Freude machen, sind beim zehnten Menü nur noch Rauschen.

    Gentle für große Flächen

    Große Elemente sollten sich langsam bewegen. Chart-Balken wachsen mit springs.gentle und einer kleinen Verzögerung pro Balken, und Seitenabschnitte blenden damit ein. Bei Stiffness 120 dauert die Bewegung etwa eine halbe Sekunde und schießt nie sichtbar über. Ein 300px hoher Balken schießt also nicht über seinen Wert hinaus und zeigt nicht für einen Moment falsche Daten.

    Wie teilst du Springs in einer Komponentenbibliothek?

    Leg sie in eine Datei und importier sie überall. Mit drei Gewohnheiten bleibt diese Datei die einzige Quelle für Spring-Werte:

    1. Benannte Presets, nie Inline-Zahlen. In Wingo UI tauchen springs.snappy und springs.smooth jeweils in mehr als 100 Komponentendateien auf (Stand Oktober 2026). Etwa 15 Komponentendateien stimmen für eine bestimmte Geste noch eine Spring inline ab. Das sind die Ausnahmen, die einen Review wert sind, nicht die Regel. Das Gefühl der ganzen Bibliothek neu abzustimmen ist eine Änderung in einer Zeile.
    2. Presets über den Springs. Ein Preset bündelt initial, animate, exit und transition. Ein Popover ist also <motion.div {...presets.popover} /> statt vier Props, die mit der Zeit auseinanderlaufen.
    3. Ein einziger Weg für reduzierte Bewegung. useMotionTransition(springs.smooth) gibt die Spring zurück oder { duration: 0 }, wenn jemand reduzierte Bewegung eingestellt hat, und useMotionPreset("popover") macht aus Bewegung einen kurzen Opacity-Fade. Beide lesen die Einstellung erst nach der Hydration, damit Server- und Client-Markup übereinstimmen. Unser Guide zu prefers-reduced-motion erklärt, warum das in Next.js wichtig ist.
    tsx
    "use client";
    import { motion } from "motion/react";
    import { springs, useMotionTransition } from "@/lib/motion";
    export function TabIndicator({ left, width }: { left: number; width: number }) {
    const transition = useMotionTransition(springs.smooth);
    return (
    <motion.span
    aria-hidden
    initial={false}
    animate={{ x: left, scaleX: width }}
    transition={transition}
    className="absolute bottom-0 left-0 h-0.5 w-px origin-left bg-foreground"
    />
    );
    }

    Wenn dir ein Provider lieber ist: MotionConfig von motion nimmt eine transition entgegen, die für jede Motion-Komponente darin zum Standard wird. <MotionConfig transition={springs.smooth}> an der Wurzel ersetzt also die eingebauten Defaults von motion in deiner App. Zwei Einschränkungen: Dieser Standard gilt auch für Opacity und Farben, die dann das 0,3-Sekunden-Tween von motion verlieren. Und reduzierte Bewegung ist eine eigene Einstellung: reducedMotion="user" auf demselben MotionConfig schaltet Transform-Animationen ab, wenn das System es verlangt. Komponenten, die snappy brauchen, geben es weiterhin explizit an.

    Die ganze Datei bekommst du mit npx wingo-ui@latest add motion. Sie ist kostenlos und installiert das Paket motion sowie den SSR-sicheren Media-Query-Hook, den sie für reduzierte Bewegung nutzt.

    Können CSS Transitions dieselbe Spring nutzen?

    Ja, für alles, was nicht über motion läuft, etwa ein Tailwind-Hover oder ein Wechsel von data-state. CSS linear() nimmt eine Liste von Punkten und zeichnet die Kurve durch sie hindurch. Du kannst eine Spring also einmal abtasten und als Easing verwenden. MDN führt linear() als Baseline, seit Dezember 2023 in allen Browsern verfügbar.

    Wingo UI liefert zwei abgetastete Gegenstücke als Tokens in globals.css: --motion-ease-snappy mit --motion-duration-snappy (450 ms) für snappy und --motion-ease-spring mit --motion-duration-spring (500 ms) für smooth. Das Überschwingen siehst du in den Zahlen: Die snappy-Kurve erreicht ihren Höchstwert bei 1,0398, also die 4 % aus der Tabelle oben.

    tsx
    <div className="transition-transform duration-(--motion-duration-snappy) ease-(--motion-ease-snappy) data-[open=true]:scale-100 data-[open=false]:scale-95" />

    Eine abgetastete Kurve kann ihre Geschwindigkeit nicht behalten, wenn sie unterbrochen wird. Nutz sie für einfache Zustandswechsel und lass Drags, Thumbs und alles, was oft ein neues Ziel bekommt, bei den Springs von motion.

    Welche Fehler lassen Springs falsch wirken?

    • Springs ohne Namen. Jedes Inline-stiffness ist eine künftige Inkonsistenz. Durchsuch deine Codebase nach stiffness: außerhalb der Preset-Datei.
    • Bouncy auf Elementen, die Leute den ganzen Tag öffnen. Heb dir das Überschwingen für Momente auf, die es verdienen.
    • Bouncy Springs auf Opacity und Farben. Opacity endet bei 1, also ist ein Überschwingen von 20 % unsichtbar und verzögert nur das Ende der Animation. Ein reiner Fade wirkt als kurzes Tween besser, und das ist auch der Default von motion für Werte ohne Transform. Läuft Opacity zusammen mit einem Transform auf smooth, wie in den Presets oben, sind 0,4 % Überschwingen zu wenig, um eine Rolle zu spielen.
    • Duration und Physik in einem Objekt. Laut der Motion-Doku werden bounce und duration überschrieben, sobald stiffness, damping oder mass gesetzt sind. { duration: 0.2, stiffness: 400 } ignoriert die Dauer also stillschweigend.
    • Kein Weg für reduzierte Bewegung. Bewegung, die die Systemeinstellung ignoriert, kann bei manchen Menschen Übelkeit auslösen. Leite jede Spring durch einen einzigen Hook.

    Weitere Guides wie diesen findest du unter Komponenten-Guides. Oder fang mit dem Pillar an, unserem Guide zu React Formular-Komponenten, der diese Springs in jedem Feld nutzt.

    Was solltest du als Nächstes installieren?

    Fang mit den Presets an: npx wingo-ui@latest add motion kopiert lib/motion.ts kostenlos in dein Projekt, mit den vier Springs, den Presets, den Gesten-Schwellenwerten und den Hooks für reduzierte Bewegung. Ergänz danach den kostenlosen Button, Switch oder das Segmented Control, und sie übernehmen automatisch dieselben Springs.

    Komponenten in diesem Artikel

    • Motion presets

      The shared springs, enter and exit presets, stagger helpers and reduced-motion hooks every animated component uses.

      Free
    • Button

      The React button component every screen starts with: five variants, six tones, all sizes, and a loading state that never jumps.

      Free
    • Switch

      A React toggle switch for settings that apply at once: a spring thumb that stretches and drags, thumb icons, and async saves that roll back.

      Free
    • Segmented Control

      A React iOS-style segmented control with a raised thumb that slides and follows your finger.

      Free

    Häufige Fragen

    Welche Werte für Stiffness und Damping eignen sich für eine Framer Motion Spring?

    Für UI deckt eine Stiffness zwischen 120 und 500 mit einem Dämpfungsverhältnis von etwa 0,7 bis 0,9 fast alles ab; geh nur für einen bewussten Bounce tiefer. Unsere vier Presets sind 500 / 32 für Press-Feedback und Toggles, 300 / 30 für Overlays und Layout, 400 / 18 für verspielte Akzente und 120 / 20 für große Flächen, alle mit der Standardmasse 1.

    Welche Spring nutzt Framer Motion standardmäßig?

    In motion 12.43 animiert ein Transform wie x oder y mit Stiffness 500 und Damping 25, scale mit Stiffness 550 und Damping 30 (kritisch gedämpft, wenn der Wert Richtung 0 geht), und Opacity oder Farben bekommen ein Tween von 0,3 Sekunden. Gibst du type: "spring" ohne Zahlen an, gelten die Physik-Defaults Stiffness 100, Damping 10 und Masse 1, und die schwingen etwa 16 % über.

    Sollte ich duration und bounce oder stiffness und damping verwenden?

    Nimm duration und bounce, wenn dir das Design eine Zeit vorgibt, und stiffness und damping, wenn die Spring die Geschwindigkeit einer Geste oder einer unterbrochenen Animation behalten soll. Laut der Motion-Doku übernehmen physikalische Springs diese Geschwindigkeit, zeitbasierte nicht, und stiffness, damping oder mass überschreiben duration und bounce.

    Wie verhindere ich, dass eine Framer Motion Spring nachfedert?

    Erhöhe damping, bis das Dämpfungsverhältnis 1 erreicht, also damping mindestens 2 * sqrt(stiffness * mass). Bei Stiffness 300 und Masse 1 sind das etwa 35; alles darüber kommt ohne Überschwingen an, nur langsamer.

    Ist Framer Motion dasselbe wie das Paket motion?

    Ja. Framer Motion erscheint jetzt als motion, und der Upgrade-Guide auf motion.dev ersetzt npm install framer-motion durch npm install motion und importiert aus motion/react. Spring-Optionen wie stiffness, damping und mass funktionieren genauso.

    • Motion
    • Animation
    • React
    • Design Systems

    Teilen

    SR

    Über den Autor

    Serban Rusu

    Gründer von Wingo UI

    Serban Rusu hat Wingo UI gegründet. Er baut die Komponenten, die CLI und den MCP-Server und schreibt über React-UIs für Smartphones und KI-Agents.

    Mehr von Serban
    Weiterlesen

    Ähnliche Artikel

    Alle Artikel
    Komponenten-Guides

    shadcn Registry: Fremde Komponenten sicher einbinden

    So nutzt du die shadcn Registry einer fremden Bibliothek in shadcn/ui: Namespaces, Auth-Header, Vorschau per Dry Run und die Dateien, die dabei kollidieren.

    SRSerban Rusu·13. Okt. 2026·8 Min. Lesezeit
    Komponenten-Guides

    shadcn Komponenten updaten, ohne Änderungen zu verlieren

    shadcn Komponenten updaten, ohne Änderungen zu verlieren: was shadcn diff und add --diff zeigen, was ein 2-Wege-Diff verschweigt und wie der 3-Wege-Merge geht.

    SRSerban Rusu·9. Okt. 2026·10 Min. Lesezeit
    Vergleiche und Alternativen

    Chakra UI vs shadcn 2026: Style Props oder Tailwind?

    Chakra UI vs shadcn im Oktober 2026: Style Props auf Emotion oder Tailwind-Code, der dir gehört. Theming, Turbopack, RSC und Smartphones, mit Codebeispielen.

    SRSerban Rusu·16. Okt. 2026·10 Min. Lesezeit
    Newsletter

    Neue Artikel per E-Mail

    Neue Guides, Tutorials und Vergleiche aus dem Wingo UI Blog, sobald sie erscheinen. Die meisten Artikel sind auf Englisch.

    Kein Spam. Du kannst dich jederzeit abmelden.

    WingoUI

    Animierte, konfigurierbare, mobile-first React-Komponenten und Blöcke. Kopier den Quellcode, pass ihn an und lass deinen Coding-Agenten damit bauen.

    Produkt

    • Komponenten
    • Vorlagen
    • Preise
    • KI-Agenten
    • Theme-Generator

    Ressourcen

    • Doku
    • Blog
    • Changelog
    • Changelog-RSS
    • llms.txt

    Rechtliches

    • AGB
    • Datenschutz
    • Rückerstattung
    • Lizenz
    • Impressum

    Komponenten-Kategorien

    • Buttons & Actions
    • Inputs
    • Forms
    • Navigation
    • Overlays
    • Feedback
    • Data Display
    • Tables & Lists
    • Charts & Stats
    • Layout
    • Media
    • AI Kit
    • Text & Effects
    • Mobile
    • Commerce
    • Marketing Sections
    • Blocks
    • Hooks & Utilities

    © 2026 Wingo UI

    Wingo UI