{
 "$schema": "../../schema.json",
 "schema": "fundus/1",
 "id": "split-mask-reveal",
 "name": "Maskierte Zeilen-/Wort-Enthüllung (SplitText mit Maske)",
 "name_en": "Masked SplitText reveal (line/word/char) / Masked line reveal (split lines slide up) / Split text mask reveal intro",
 "kurz": "Zeilen gleiten aus ihrer eigenen Maske nach oben: Text wird enthüllt statt eingeblendet, präzise wie ein Filmabspann.",
 "kategorie": "Schrift-Animationen",
 "kategorie_slug": "schrift-animationen",
 "kategorie_nr": 6,
 "bau_chat": "C1",
 "prioritaet": "A",
 "trendstatus": "etabliert",
 "belegstatus": "belegt",
 "website_belege": 4,
 "stimmung": [
  "ruhig",
  "editorial",
  "präzise",
  "luxuriös",
  "filmisch"
 ],
 "stimmung_roh": [
  "editorial",
  "luxuriös",
  "präzise",
  "ruhig",
  "typografisch",
  "filmisch"
 ],
 "technik": [
  "gsap",
  "splittext",
  "scrolltrigger",
  "css",
  "scroll-driven-css"
 ],
 "technik_gruppen": [
  "css",
  "gsap"
 ],
 "leistungskosten": "niedrig",
 "steckbrief": {
  "beschreibung": "1) Die Überschrift wird in Zeilen geteilt (für lautere Fassungen zusätzlich in Wörter oder Zeichen). 2) Jedes Teil bekommt einen eigenen Rahmen, der überstehenden Inhalt abschneidet: die Maske. 3) Der Inhalt startet 110 % seiner Höhe tiefer, also unsichtbar unter der Maskenkante. 4) Beim Laden oder beim Eintritt in den Viewport gleiten die Teile nacheinander auf ihren Platz, mit stark ausklingender Kurve (expo.out). 5) Die Animation läuft einmal. Bis zum Teilen ist der Text per CSS unsichtbar, damit kein ungeteilter Text aufblitzt.",
  "warum_es_wirkt": "Der Text scheint aus einer Kante herauszuwachsen, statt nur aufzutauchen. Das wirkt gedruckt, präzise und hochwertig, wie die Titelsequenz eines Films. Die Deckkraft bleibt bei 1, es gibt also keine matte Zwischenphase. Der Versatz führt das Auge in Leserichtung. Seit SplitText mit Masken-Option 2025 kostenlos wurde, ist das Muster auf ausgezeichneten Seiten Standard.",
  "wann_einsetzen": "Hero-Überschriften, Abschnittstitel, kurze Statements, große Zitate und Kapitelanfänge in Fallstudien. Auch als Abschluss eines Intros.",
  "wann_nicht": "Fließtext über drei, vier Zeilen, Navigation, Formulare und wiederkehrende Labels. Nicht auf jeder Überschrift der Seite, sonst nutzt sich der Effekt ab: besser nur H1 und H2. Zeichen-Teilung nie bei Schriften mit komplexer Zeichenbildung (sie zerstört Ligaturen).",
  "varianten": [
   "Zeilen (ruhig, Standard): 1000 ms, Versatz 80 ms",
   "Wörter: 800 ms, Versatz 40 ms",
   "Zeichen (laut, nur für kurze Wörter): 600 ms, Versatz 12 ms",
   "Mit Drehung: Zeile startet mit rotate 4–8° und richtet sich beim Hochgleiten auf",
   "An den Scroll gekoppelt (scrub) statt einmalig, für Kapitelübergänge",
   "Ohne JavaScript: Masken-Spans im HTML, Versatz über --i oder sibling-index(), Auslöser per animation-trigger",
   "Mit Scramble kombiniert (Zeichen entschlüsseln sich, während sie aufsteigen)"
  ],
  "umsetzung": "SplitText.create(el, { type: 'lines', mask: 'lines', autoSplit: true, onSplit(self) { return gsap.from(self.lines, { yPercent: 110, duration: 1, stagger: 0.08, ease: 'expo.out' }); } }). Für den Scroll-Auslöser scrollTrigger: { trigger: el, start: 'clamp(top 80%)', once: true } in den Tween.\n\nDrei Fallstricke: Erst nach document.fonts.ready teilen, sonst stimmen die Umbrüche nicht. Den Tween aus onSplit zurückgeben, dann setzt autoSplit ihn bei neuem Umbruch sauber neu auf. Masken schneiden Unterlängen und Akzente ab: Masken mit padding-block 0,1em und gleich großem negativem margin-block erweitern.",
  "mobil": "Funktioniert unverändert. Zeilen-Teilung bevorzugen, Zeichen erzeugen auf schmalen Bildschirmen sehr viele Elemente. autoSplit ist nötig, weil sich Umbrüche beim Drehen ändern.",
  "reduzierte_bewegung": "Kein Versatz, nur kurz einblenden (Deckkraft 0 → 1 in 200–300 ms) oder den Text sofort zeigen.",
  "barrierefreiheit": "SplitText setzt aria-label auf das Element und aria-hidden auf die Teile, Screenreader lesen also den ganzen Satz. Verschachtelte Links gehen dabei verloren: dann aria: 'none' und eine visuell versteckte Kopie. Der Text darf nie dauerhaft unsichtbar bleiben, wenn JavaScript fehlt: die Klasse zum Verstecken erst per JavaScript setzen."
 },
 "messwerte": {
  "easing": "cubic-bezier(0.23,1,0.32,1) (K72); power3.out (Dennis)",
  "dauer_ms": "900 (K72, Zeilen); 1000 (Dennis, Wörter)",
  "stagger_ms": "135 pro Zeile (K72); 10 pro Wort (Dennis)",
  "distanz": "−120 % → 0 (K72, von oben); y 100 % → 0 (Dennis)",
  "sonstiges": "CSS-Transition über Klasse .is-inview (Locomotive Scroll) statt JS-Tween bei K72",
  "herkunft": "beobachtet",
  "quelle": "https://k72.ca/assets/styles/main.css ; https://dennissnellenberg.com/assets/js/index-new.js",
  "aus_eintrag": [
   "split-mask-reveal"
  ]
 },
 "kurve": {
  "bezier": [
   0.16,
   1,
   0.3,
   1
  ],
  "css": "cubic-bezier(0.16, 1, 0.3, 1)",
  "name": "expo.out",
  "dauer_ms": 1000
 },
 "gesehen_bei": [
  {
   "seite": "Osmo – Masked Text Reveal",
   "url": "https://www.osmo.supply/resource/masked-text-reveal",
   "auszeichnung": "",
   "beobachtung": "Referenz-Implementierung mit GSAP 3.13 SplitText + ScrollTrigger, data-split-reveal für lines/words/chars, yPercent 110, expo.out, start 'clamp(top 80%)', once: true, autoSplit + Rückgabe des Tweens aus onSplit.",
   "art": "demo"
  },
  {
   "seite": "Locomotive (Agenturseite)",
   "url": "https://locomotive.ca/en",
   "auszeichnung": "",
   "beobachtung": "Projekttitel und Headlines sind zeilenweise umbrochen und mehrfach im Markup vorhanden, was auf zeilen-/wortweise Reveals hindeutet (aus dem Seitentext abgeleitet, Animation selbst nicht verifiziert).",
   "art": "website-ungeprueft",
   "browser_gemessen": true
  },
  {
   "seite": "OFF+BRAND",
   "url": "https://www.itsoffbrand.com",
   "auszeichnung": "laut eigener Seite Awwwards Site of the Year (Projekt nicht genannt)",
   "beobachtung": "Geteilte Hero-Headline ‚A different / Creative / approach‘ mit Scroll-Cue; zeilenweise Reveals aus Erinnerung, statisch nur Zeilenaufteilung sichtbar.",
   "art": "website-ungeprueft",
   "browser_gemessen": true
  },
  {
   "seite": "GSAP SplitText (seit 3.13 mit mask-Option)",
   "url": "https://gsap.com/blog/3-13",
   "auszeichnung": "",
   "beobachtung": "SplitText umschließt Zeilen/Wörter/Zeichen optional mit einem Clip-Element für genau diesen Reveal; autoSplit re-splittet bei Resize/Font-Load.",
   "art": "artikel"
  },
  {
   "seite": "Stas Bondar Portfolio ’25",
   "url": "https://tympanus.net/codrops/2025/03/25/stas-bondar-25-the-code-techniques-behind-a-next-level-portfolio/",
   "auszeichnung": "",
   "beobachtung": "Case-Study-Titel per SplitText in Zeilen und Zeichen. Zeichen scrambeln und faden ein, mit 0,1 Stagger je Zeilenindex.",
   "art": "artikel"
  },
  {
   "seite": "Thibault Guignand Portfolio",
   "url": "https://www.thibaultguignand.com/",
   "auszeichnung": "",
   "beobachtung": "Text-Reveal aus Scramble und Wipe: inset(0 0% 0 0), 0,6 s power2.out parallel zum Scramble. Die Elternhöhe wird vor dem SplitText-Lauf gesperrt, gegen Layoutsprünge.",
   "art": "website",
   "browser_gemessen": true
  },
  {
   "seite": "Webflow/GSAP: SplitText-Rewrite",
   "url": "https://origin.webflow.com/blog/gsap-splittext-rewrite",
   "auszeichnung": "",
   "beobachtung": "Offizieller Artikel zur Neufassung von SplitText (laut Titel). GSAP ist seit 2025 inklusive aller Plugins kostenlos.",
   "art": "artikel"
  },
  {
   "seite": "K72",
   "url": "https://k72.ca/",
   "auszeichnung": "",
   "beobachtung": "app.js: new SplitText(el,{type:'lines'}), jede Zeile in .c-text-lines_item_inner gewickelt (Wrapper overflow hidden); CSS: translate3d(0,-120%,0) → 0 bei .is-inview, 0,9 s cubic-bezier(0.23,1,0.32,1), Zeilen-Delay 0 / 0,135 s …",
   "art": "website",
   "browser_gemessen": true
  },
  {
   "seite": "Dennis Snellenberg",
   "url": "https://dennissnellenberg.com/",
   "auszeichnung": "",
   "beobachtung": "index-new.js: .span-lines wird per Regex in span.span-line > span.span-line-inner (Wort mit Maske) zerlegt; ScrollTrigger (start '0% 100%', toggleActions play none none reset) animiert from y 100 %, power3.out, 1 s, stagger 0,01.",
   "art": "website",
   "browser_gemessen": true
  },
  {
   "seite": "Lando Norris",
   "url": "https://www.landonorris.com/",
   "auszeichnung": "",
   "beobachtung": "OFF+BRAND-Bundle mit SplitText 3.13.0 im mask-Modus (Wrapper-Klasse '-mask', overflow clip) und eigenem Initialisierer für [split-text]-Attribute (lines, words, chars).",
   "art": "website",
   "browser_gemessen": true
  }
 ],
 "tutorials": [
  {
   "titel": "GSAP SplitText Dokumentation (mask, autoSplit, onSplit, aria)",
   "url": "https://gsap.com/docs/v3/Plugins/SplitText/"
  },
  {
   "titel": "Osmo – Masked Text Reveal",
   "url": "https://www.osmo.supply/resource/masked-text-reveal"
  },
  {
   "titel": "Motion splitText",
   "url": "https://motion.dev/docs/split-text"
  },
  {
   "titel": "Chrome – CSS scroll-triggered animations",
   "url": "https://developer.chrome.com/blog/scroll-triggered-animations"
  },
  {
   "titel": "GSAP 3.13 – SplitText-Rewrite (mask, autoSplit, aria)",
   "url": "https://gsap.com/blog/3-13"
  },
  {
   "titel": "Fly-in Text mit Scroll-Triggered Animations (Bramus, CodePen)",
   "url": "https://codepen.io/bramus/pen/gbrEzGJ"
  },
  {
   "titel": "From SplitText to MorphSVG: 5 Creative Demos Using Free GSAP Plugins (Codrops, 05/2025)",
   "url": "https://tympanus.net/codrops/2025/05/14/from-splittext-to-morphsvg-5-creative-demos-using-free-gsap-plugins/"
  },
  {
   "titel": "Adventures in text splitting: GSAP's SplitText rewrite (Webflow)",
   "url": "https://origin.webflow.com/blog/gsap-splittext-rewrite"
  },
  {
   "titel": "Webflow makes GSAP 100% free",
   "url": "https://webflow.com/blog/gsap-becomes-free"
  }
 ],
 "kombinierbar_mit": [
  "blur-reveal",
  "zahlen-odometer",
  "rotating-words",
  "clip-path-bild-reveal",
  "pinned-scrub-scrollytelling",
  "intro-ohne-wartezeit",
  "bildstapel-intro",
  "loader-wird-layout",
  "seitenname-typo-uebergang"
 ],
 "urls": {
  "detail": "https://cecodesign.de/lab/fundus/schrift-animationen/split-mask-reveal/",
  "meta": "https://cecodesign.de/lab/fundus/schrift-animationen/split-mask-reveal/meta.json",
  "demo": "https://cecodesign.de/lab/fundus/schrift-animationen/split-mask-reveal/demo"
 },
 "herkunft": {
  "quelldateien": [
   "schriftanimation.json",
   "scroll.json",
   "uebergaenge.json",
   "patch-belege-1.json"
  ],
  "pruefnotizen": [
   "patch-belege-1.json: 3 neue Produktionsbelege mit Werten."
  ],
  "zusammengelegt_aus": [
   "split-mask-reveal",
   "zeilen-masken-reveal",
   "split-text-masken-reveal"
  ],
  "querverweis_kategorien": [
   "Scroll & Section-Animationen",
   "Preloader & Intro"
  ]
 },
 "bau": {
  "status": "fertig",
  "kurz": "Zeilen gleiten aus ihrer eigenen Maske nach oben: Text wird enthüllt statt eingeblendet, präzise wie ein Filmabspann.",
  "demo": true,
  "abhaengigkeiten": [
   "gsap@3.15.0",
   "ScrollTrigger@3.15.0",
   "SplitText@3.15.0"
  ],
  "werte": {
   "easing": "expo.out = cubic-bezier(0.16, 1, 0.3, 1)",
   "dauer_ms": "Zeilen 1000 · Wörter 800 · Zeichen 600",
   "stagger_ms": "Zeilen 80 · Wörter 40 · Zeichen 12",
   "distanz": "yPercent 110 → 0",
   "abgang": "yPercent 0 → −110, 550 ms expo.in",
   "scroll": "start 'clamp(top 80%)', once"
  },
  "ausloeser": "laden, scroll",
  "touch": "Unverändert. autoSplit teilt nach Drehen oder neuer Breite neu, die Animation bleibt synchron.",
  "reduziert": "Kein Teilen, keine Bewegung: Überschrift und Satz blenden in 300 ms ein.",
  "korrekturen": {
   "beschreibung": "1) Die Überschrift wird in Zeilen geteilt (für lautere Fassungen zusätzlich in Wörter oder Zeichen). 2) Jedes Teil bekommt einen eigenen Rahmen, der überstehenden Inhalt abschneidet: die Maske. 3) Der Inhalt startet 110 % seiner Höhe tiefer, also unsichtbar unter der Maskenkante. 4) Beim Laden oder beim Eintritt in den Viewport gleiten die Teile nacheinander auf ihren Platz, mit stark ausklingender Kurve (expo.out). 5) Die Animation läuft einmal. Bis zum Teilen ist der Text per CSS unsichtbar, damit kein ungeteilter Text aufblitzt.",
   "warum_es_wirkt": "Der Text scheint aus einer Kante herauszuwachsen, statt nur aufzutauchen. Das wirkt gedruckt, präzise und hochwertig, wie die Titelsequenz eines Films. Die Deckkraft bleibt bei 1, es gibt also keine matte Zwischenphase. Der Versatz führt das Auge in Leserichtung. Seit SplitText mit Masken-Option 2025 kostenlos wurde, ist das Muster auf ausgezeichneten Seiten Standard.",
   "wann_einsetzen": "Hero-Überschriften, Abschnittstitel, kurze Statements, große Zitate und Kapitelanfänge in Fallstudien. Auch als Abschluss eines Intros.",
   "wann_nicht": "Fließtext über drei, vier Zeilen, Navigation, Formulare und wiederkehrende Labels. Nicht auf jeder Überschrift der Seite, sonst nutzt sich der Effekt ab: besser nur H1 und H2. Zeichen-Teilung nie bei Schriften mit komplexer Zeichenbildung (sie zerstört Ligaturen).",
   "varianten": [
    "Zeilen (ruhig, Standard): 1000 ms, Versatz 80 ms",
    "Wörter: 800 ms, Versatz 40 ms",
    "Zeichen (laut, nur für kurze Wörter): 600 ms, Versatz 12 ms",
    "Mit Drehung: Zeile startet mit rotate 4–8° und richtet sich beim Hochgleiten auf",
    "An den Scroll gekoppelt (scrub) statt einmalig, für Kapitelübergänge",
    "Ohne JavaScript: Masken-Spans im HTML, Versatz über --i oder sibling-index(), Auslöser per animation-trigger",
    "Mit Scramble kombiniert (Zeichen entschlüsseln sich, während sie aufsteigen)"
   ],
   "umsetzung": "SplitText.create(el, { type: 'lines', mask: 'lines', autoSplit: true, onSplit(self) { return gsap.from(self.lines, { yPercent: 110, duration: 1, stagger: 0.08, ease: 'expo.out' }); } }). Für den Scroll-Auslöser scrollTrigger: { trigger: el, start: 'clamp(top 80%)', once: true } in den Tween.\n\nDrei Fallstricke: Erst nach document.fonts.ready teilen, sonst stimmen die Umbrüche nicht. Den Tween aus onSplit zurückgeben, dann setzt autoSplit ihn bei neuem Umbruch sauber neu auf. Masken schneiden Unterlängen und Akzente ab: Masken mit padding-block 0,1em und gleich großem negativem margin-block erweitern.",
   "mobil": "Funktioniert unverändert. Zeilen-Teilung bevorzugen, Zeichen erzeugen auf schmalen Bildschirmen sehr viele Elemente. autoSplit ist nötig, weil sich Umbrüche beim Drehen ändern.",
   "reduzierte_bewegung": "Kein Versatz, nur kurz einblenden (Deckkraft 0 → 1 in 200–300 ms) oder den Text sofort zeigen.",
   "barrierefreiheit": "SplitText setzt aria-label auf das Element und aria-hidden auf die Teile, Screenreader lesen also den ganzen Satz. Verschachtelte Links gehen dabei verloren: dann aria: 'none' und eine visuell versteckte Kopie. Der Text darf nie dauerhaft unsichtbar bleiben, wenn JavaScript fehlt: die Klasse zum Verstecken erst per JavaScript setzen."
  },
  "geprueft": "31.10.2026",
  "notiz": "Pilot aus Chat B. Abgang (verbergen) nur für die Vorführung; auf echten Seiten läuft der Reveal einmal."
 }
}
