{
 "$schema": "../../schema.json",
 "schema": "fundus/1",
 "id": "produkt-ui-hero-perspektiv-tilt",
 "name": "Produkt-UI-Hero mit Perspektiv-Tilt (Screenshot richtet sich beim Scrollen auf)",
 "name_en": "Perspective-tilt product hero / screenshot scroll reveal",
 "kurz": "Das Dashboard eines Flussvereins liegt gekippt unter der Mission und richtet sich beim Scrollen auf, bis es frontal und lesbar steht.",
 "kategorie": "Hero & Section-Layouts",
 "kategorie_slug": "hero-layouts",
 "kategorie_nr": 4,
 "bau_chat": "C2",
 "prioritaet": "B",
 "trendstatus": "etabliert",
 "belegstatus": "teilbelegt",
 "website_belege": 1,
 "stimmung": [
  "präzise"
 ],
 "stimmung_roh": [
  "technisch",
  "produktig",
  "präzise",
  "modern"
 ],
 "technik": [
  "css",
  "motion",
  "framer-motion",
  "scroll-driven-css",
  "gsap",
  "scrolltrigger"
 ],
 "technik_gruppen": [
  "css",
  "gsap",
  "andere"
 ],
 "leistungskosten": "niedrig",
 "steckbrief": {
  "beschreibung": "Unter Headline und Call-to-Action liegt ein großer Screenshot der Produkt-Oberfläche in einem Rahmen, etwa ein Dashboard, Editor oder App-Fenster. Zu Beginn ist er um die X-Achse nach hinten gekippt (rotateX um 20°, als Klappe bis 90°). Die Oberkante liegt weiter weg als die Unterkante, dazu kommt ein leichter Zoom. Beim Scrollen richtet sich die Fläche scroll-gekoppelt auf und skaliert auf 1. Die Headline wandert dabei nach oben weg. Am Ende steht das UI frontal und lesbar im Viewport, oft mit gestaffeltem Schatten für Tiefe.",
  "warum_es_wirkt": "Das Aufrichten inszeniert den ersten Blick ins Produkt wie einen Vorhang, der sich hebt. Der Besucher holt sich das UI mit dem eigenen Scroll heran. Das weckt Neugier und gibt ihm Kontrolle. Die Perspektive macht einen flachen Screenshot räumlich, ganz ohne WebGL.",
  "wann_einsetzen": "Landingpages für SaaS, Apps und Tools, deren Oberfläche das stärkste Argument ist. Template-Heros für Software-Kunden. Case Studies, die ein Interface vorstellen, etwa ein Shop-Backend oder ein Buchungs-Tool. Auch Vereine und Verwaltungen mit einem öffentlichen Daten- oder Transparenz-Dashboard.",
  "wann_nicht": "Wenn es kein echtes, ansehnliches UI gibt; Mock-Screenshots wirken austauschbar. Bei Portfolios ohne Produkt. Wenn der Screenshot kleinteiligen Text zeigt, der im gekippten Zustand flimmert. Wenn der Hero schon schwer ist, etwa mit Video oder 3D.",
  "varianten": [
   "Klassisch: rotateX 20° auf 0°, scale 1.05 auf 1, Headline translateY 0 auf −100px (Aceternity Container Scroll).",
   "Gepinnte Bühne: Die Headline hebt ab, der Screenshot richtet sich auf und fährt in die Mitte (Motion Screenshot Scroll Reveal).",
   "Klappe: Die Fläche klappt aus 90° hoch, transform-origin oben. Bei Pitch als Sektionsübergang mit Farbverlauf statt Screenshot.",
   "Nur beim Laden: einmalige Animation von gekippt auf flach, ohne Scroll-Kopplung.",
   "Mobil: kleinere Skalierung (0.7 auf 0.9) und eine mobile Ansicht des Produkts statt des Desktop-Screenshots."
  ],
  "umsetzung": "Markup: <section class=\"tilt-hero\"> mit Headline und <figure class=\"tilt-frame\">. Das Elternelement bekommt perspective: 1000px (gängig sind 800 bis 1200px). Der Rahmen dreht um die Mitte, für die Klappe um die Oberkante (transform-origin: 50% 0). Nativ ohne JS: .tilt-frame { animation: aufrichten linear both; animation-timeline: view(); animation-range: entry 0% cover 50%; } @keyframes aufrichten { from { transform: rotateX(20deg) scale(1.05); } to { transform: none; } }. Mit Motion: const { scrollYProgress } = useScroll({ target: ref }); rotateX = useTransform(scrollYProgress, [0, 1], [20, 0]); scale = useTransform(scrollYProgress, [0, 1], [1.05, 1]). Mit GSAP: gsap.fromTo(frame, { rotateX: 20, scale: 1.05 }, { rotateX: 0, scale: 1, ease: 'none', scrollTrigger: { trigger: section, start: 'top top', end: 'bottom bottom', scrub: true } }). Die Demo rechnet den Fortschritt in wenigen Zeilen Vanilla-JS aus der Scroll-Position und setzt die Transforms direkt. Fallstricke: Den Screenshot in 2× Auflösung liefern, weil die Perspektive ihn dehnt. will-change: transform nur während der Animation. Text im Bild nicht als Ersatz für echten Text nutzen. Die Scroll-Strecke großzügig wählen (150 bis 200vh), sonst ist die Bewegung zu schnell.",
  "mobil": "Kippung auf kleinen Screens reduzieren oder durch reine Skalierung ersetzen (Aceternity: 0.7 auf 0.9 unter 768px). Den Screenshot gegen eine mobile Ansicht des Produkts tauschen. Die Scroll-Strecke verkürzen.",
  "reduzierte_bewegung": "Screenshot flach und unskaliert zeigen (transform: none). Headline statisch, keine gepinnte Strecke.",
  "barrierefreiheit": "Der Screenshot braucht einen aussagekräftigen Alt-Text, der sagt, was das UI zeigt. Keine Kerninformation nur im Bild. Die Fokusreihenfolge bleibt gleich, weil nur transform animiert wird."
 },
 "messwerte": {
  "easing": "linear (scroll-gekoppelt, scrub)",
  "dauer_ms": "",
  "stagger_ms": "",
  "distanz": "rotateX 20° auf 0°, scale 1.05 auf 1, Headline translateY 0 auf −100px; perspective 1000px",
  "sonstiges": "Mobil scale 0.7 auf 0.9 statt 1.05 auf 1 (Breakpoint 768px); Container 60rem (mobil) / 80rem hoch. Pitch: rotateX 90° auf 0°, transform-origin 50% 0, Scroll-Bereich ‚start end‘ bis ‚end start‘.",
  "herkunft": "beobachtet",
  "quelle": "https://ui.aceternity.com/registry/container-scroll-animation.json; https://framerusercontent.com/sites/3VdCx5FgIQlqRKsXSF2a7l/ScrollGradient.CY2u63Jp.mjs"
 },
 "kurve": {
  "bezier": [
   0,
   0,
   1,
   1
  ],
  "css": "cubic-bezier(0, 0, 1, 1)",
  "name": "linear",
  "dauer_ms": null
 },
 "gesehen_bei": [
  {
   "seite": "Pitch",
   "url": "https://pitch.com/",
   "auszeichnung": "",
   "beobachtung": "Live geprüft: Framer-Code-Komponente ScrollGradient im Abschnitt ‚Transition‘. Ein 100vh hohes Bild mit transform-origin 50% 0 startet bei rotateX(90deg) (im SSR-HTML sichtbar) und richtet sich scroll-gekoppelt auf: useScroll offset ['start end','end start'], useTransform(scrollYProgress,[0,scrollSensitivity=1],[rotationStart=90,rotationEnd=0]). Gleiche Mechanik wie beim Produkt-Tilt, hier aber auf einen Farbverlauf als Sektionsübergang angewendet, nicht auf einen UI-Screenshot.",
   "art": "website"
  },
  {
   "seite": "Aceternity UI – Container Scroll Animation",
   "url": "https://ui.aceternity.com/components/container-scroll-animation",
   "auszeichnung": "",
   "beobachtung": "Quellcode (Registry) gelesen: perspective 1000px am Elternelement; useScroll auf den Container; rotateX useTransform [0,1] auf [20,0]; scale [1.05,1] (mobil ≤768px: [0.7,0.9]); Headline translateY [0,−100]; Container 60rem/80rem hoch; Karte mit 6-stufigem Schatten (0 9px 20px … 0 233px 65px). Diese Komponente steckt hinter vielen SaaS- und Framer-Heros.",
   "art": "demo"
  },
  {
   "seite": "Motion UI – Screenshot Scroll Reveal",
   "url": "https://motion.dev/ui/components/screenshot-scroll-reveal",
   "auszeichnung": "",
   "beobachtung": "Laut Komponentenseite: gepinnte Scroll-Bühne, Headline hebt ab, Screenshot kippt auf und skaliert in die Mitte. Parameter tiltSpeed (rotateX-Start = BASE_TILT_DEG × tiltSpeed), scaleSpeed, headlineSpeed. Die Zahlenwerte sind nur im kostenpflichtigen Quellcode einsehbar.",
   "art": "demo"
  }
 ],
 "tutorials": [
  {
   "titel": "Aceternity UI – Container Scroll Animation (Komponente mit Code)",
   "url": "https://ui.aceternity.com/components/container-scroll-animation"
  },
  {
   "titel": "Scroll-driven Animations (Chrome for Developers)",
   "url": "https://developer.chrome.com/docs/css-ui/scroll-driven-animations"
  }
 ],
 "kombinierbar_mit": [
  "css-3d-transforms",
  "pinned-scrub-scrollytelling",
  "medien-expansion-scroll",
  "bento-grid-interaktiv",
  "logo-wand-social-proof"
 ],
 "urls": {
  "detail": "https://cecodesign.de/lab/fundus/hero-layouts/produkt-ui-hero-perspektiv-tilt/",
  "meta": "https://cecodesign.de/lab/fundus/hero-layouts/produkt-ui-hero-perspektiv-tilt/meta.json",
  "demo": "https://cecodesign.de/lab/fundus/hero-layouts/produkt-ui-hero-perspektiv-tilt/demo"
 },
 "herkunft": {
  "quelldateien": [
   "patch-luecken-a.json"
  ]
 },
 "bau": {
  "status": "fertig",
  "kurz": "Das Dashboard eines Flussvereins liegt gekippt unter der Mission und richtet sich beim Scrollen auf, bis es frontal und lesbar steht.",
  "demo": true,
  "abhaengigkeiten": [],
  "werte": {
   "perspective": "1000px am Elternelement (.szene)",
   "rotateX": "20° → 0° (Klassisch, Beim Laden); 90° → 0° (Klappe)",
   "scale": "1.05 → 1; unter 768px (Klassisch) 0.7 → 0.9",
   "transform_origin": "50% 50% (Klassisch, Beim Laden); 50% 0 (Klappe)",
   "headline": "translateY 0 → −100px; opacity 1 → 0 zwischen 20 % und 75 % Fortschritt",
   "rahmen_hub": "translateY vom Startplatz unter dem Text bis 24px unter den Kopf, linear zum Fortschritt (Weg per JS gemessen)",
   "easing": "linear (Scroll-Fortschritt 1:1, scrub)",
   "scroll_strecke": "Hero 200vh, unter 768px 170vh; Bühne position: sticky, 100svh",
   "fortschritt": "p = −hero.top / (hero.height − innerHeight), auf 0…1 begrenzt",
   "klappe_verlauf": "Farbverlauf #A9CCEA → #002E6D über dem UI; Deckkraft 1 ab 70°, 0 ab 30°",
   "beim_laden": "1000ms, cubic-bezier(0.645, 0.045, 0.355, 1), Verzögerung 200ms, einmalig",
   "schatten": "0 0 #0000004d, 0 9px 20px #0010304a, 0 37px 37px #00103042, 0 84px 50px #00103026, 0 149px 60px #0010300a, 0 233px 65px #00103003",
   "ui_dauer_ms": 150,
   "ui_kurve": "cubic-bezier(0.645, 0.045, 0.355, 1)",
   "vorfuehrung": "Runde 8400ms: 8 % oben halten, 48 % hinunter (Kosinus), 16 % halten, 22 % zurück"
  },
  "ausloeser": "scroll",
  "touch": "Unter 768px tauscht die Demo das Dashboard gegen die Telefon-Ansicht des Produkts. Kippung 20° → 0° bleibt, die Skalierung läuft 0.7 → 0.9, die Strecke ist 170vh. Kein Hover nötig.",
  "reduziert": "Keine Scroll-Strecke und kein Pinning. Screenshot steht flach und unskaliert (transform: none) unter der statischen Headline; die Variante „Beim Laden“ spielt nicht ab.",
  "korrekturen": {
   "beschreibung": "Unter Headline und Call-to-Action liegt ein großer Screenshot der Produkt-Oberfläche in einem Rahmen, etwa ein Dashboard, Editor oder App-Fenster. Zu Beginn ist er um die X-Achse nach hinten gekippt (rotateX um 20°, als Klappe bis 90°). Die Oberkante liegt weiter weg als die Unterkante, dazu kommt ein leichter Zoom. Beim Scrollen richtet sich die Fläche scroll-gekoppelt auf und skaliert auf 1. Die Headline wandert dabei nach oben weg. Am Ende steht das UI frontal und lesbar im Viewport, oft mit gestaffeltem Schatten für Tiefe.",
   "warum_es_wirkt": "Das Aufrichten inszeniert den ersten Blick ins Produkt wie einen Vorhang, der sich hebt. Der Besucher holt sich das UI mit dem eigenen Scroll heran. Das weckt Neugier und gibt ihm Kontrolle. Die Perspektive macht einen flachen Screenshot räumlich, ganz ohne WebGL.",
   "wann_einsetzen": "Landingpages für SaaS, Apps und Tools, deren Oberfläche das stärkste Argument ist. Template-Heros für Software-Kunden. Case Studies, die ein Interface vorstellen, etwa ein Shop-Backend oder ein Buchungs-Tool. Auch Vereine und Verwaltungen mit einem öffentlichen Daten- oder Transparenz-Dashboard.",
   "wann_nicht": "Wenn es kein echtes, ansehnliches UI gibt; Mock-Screenshots wirken austauschbar. Bei Portfolios ohne Produkt. Wenn der Screenshot kleinteiligen Text zeigt, der im gekippten Zustand flimmert. Wenn der Hero schon schwer ist, etwa mit Video oder 3D.",
   "varianten": [
    "Klassisch: rotateX 20° auf 0°, scale 1.05 auf 1, Headline translateY 0 auf −100px (Aceternity Container Scroll).",
    "Gepinnte Bühne: Die Headline hebt ab, der Screenshot richtet sich auf und fährt in die Mitte (Motion Screenshot Scroll Reveal).",
    "Klappe: Die Fläche klappt aus 90° hoch, transform-origin oben. Bei Pitch als Sektionsübergang mit Farbverlauf statt Screenshot.",
    "Nur beim Laden: einmalige Animation von gekippt auf flach, ohne Scroll-Kopplung.",
    "Mobil: kleinere Skalierung (0.7 auf 0.9) und eine mobile Ansicht des Produkts statt des Desktop-Screenshots."
   ],
   "umsetzung": "Markup: <section class=\"tilt-hero\"> mit Headline und <figure class=\"tilt-frame\">. Das Elternelement bekommt perspective: 1000px (gängig sind 800 bis 1200px). Der Rahmen dreht um die Mitte, für die Klappe um die Oberkante (transform-origin: 50% 0). Nativ ohne JS: .tilt-frame { animation: aufrichten linear both; animation-timeline: view(); animation-range: entry 0% cover 50%; } @keyframes aufrichten { from { transform: rotateX(20deg) scale(1.05); } to { transform: none; } }. Mit Motion: const { scrollYProgress } = useScroll({ target: ref }); rotateX = useTransform(scrollYProgress, [0, 1], [20, 0]); scale = useTransform(scrollYProgress, [0, 1], [1.05, 1]). Mit GSAP: gsap.fromTo(frame, { rotateX: 20, scale: 1.05 }, { rotateX: 0, scale: 1, ease: 'none', scrollTrigger: { trigger: section, start: 'top top', end: 'bottom bottom', scrub: true } }). Die Demo rechnet den Fortschritt in wenigen Zeilen Vanilla-JS aus der Scroll-Position und setzt die Transforms direkt. Fallstricke: Den Screenshot in 2× Auflösung liefern, weil die Perspektive ihn dehnt. will-change: transform nur während der Animation. Text im Bild nicht als Ersatz für echten Text nutzen. Die Scroll-Strecke großzügig wählen (150 bis 200vh), sonst ist die Bewegung zu schnell.",
   "mobil": "Kippung auf kleinen Screens reduzieren oder durch reine Skalierung ersetzen (Aceternity: 0.7 auf 0.9 unter 768px). Den Screenshot gegen eine mobile Ansicht des Produkts tauschen. Die Scroll-Strecke verkürzen.",
   "reduzierte_bewegung": "Screenshot flach und unskaliert zeigen (transform: none). Headline statisch, keine gepinnte Strecke.",
   "barrierefreiheit": "Der Screenshot braucht einen aussagekräftigen Alt-Text, der sagt, was das UI zeigt. Keine Kerninformation nur im Bild. Die Fokusreihenfolge bleibt gleich, weil nur transform animiert wird."
  },
  "geprueft": "01.11.2026",
  "notiz": "Welt: Rezept verein-nonprofit-wirkung mit der erfundenen Zusammenfluss EO aus Bozen, die an Talfer, Eisack und Etsch Wasserproben misst. Das Produkt-UI ist ihr öffentliches Transparenz-Dashboard „Flussbuch“ (Messstellen-Karte als eigene SVG, Mittelverwendung, letzte Messungen), als HTML gebaut statt als Bild und mit role=img samt Alt-Text. Big Shoulders 800 versal und Archivo, Navy #002E6D, Gelb nur am Spenden-Button. Gepinnte Bühne mit drei Varianten: Klassisch (20°, 1.05), Klappe 90° (Oberkante als Scharnier, Farbverlauf solange die Fläche steil steht, wie bei Pitch) und Beim Laden (einmalig, InOut-Kurve des Rezepts). Unter 768px eine Telefon-Ansicht mit 0.7 → 0.9. Die Leiste unten zeigt die live verwendeten Werte. Vorführen scrollt die Strecke selbst hinunter und wieder hinauf. AD-Review 01.11.2026: Note 5. Zugang 02.11.2026: Grau der UI-Attrappe #6b7785 → #5f6a77 (5,0:1 auf #edf5fa), Status „prüfen“ als Text #b33a26 (Punkt bleibt #C8442F); Knopf-Rahmen im Kontrastmodus."
 }
}
