{
 "$schema": "../../schema.json",
 "schema": "fundus/1",
 "id": "cursor-masken-reveal",
 "name": "Masken- und Spotlight-Reveal am Cursor",
 "name_en": "Cursor mask reveal / spotlight reveal / x-ray hover / Spotlight / flashlight / mask reveal cursor",
 "kurz": "Ein Kreis am Zeiger wächst über der Überschrift von 40 auf 400 px und legt eine zweite, ehrlichere Ebene frei.",
 "kategorie": "Cursor",
 "kategorie_slug": "cursor",
 "kategorie_nr": 8,
 "bau_chat": "C4",
 "prioritaet": "A",
 "trendstatus": "etabliert",
 "belegstatus": "belegt",
 "website_belege": 2,
 "stimmung": [
  "editorial",
  "filmisch",
  "verspielt",
  "warm"
 ],
 "stimmung_roh": [
  "verspielt",
  "geheimnisvoll",
  "editorial",
  "persönlich",
  "dunkel",
  "dramatisch"
 ],
 "technik": [
  "css",
  "vanilla-js",
  "motion",
  "canvas",
  "three",
  "framer-motion",
  "gsap",
  "webgl-shader"
 ],
 "technik_gruppen": [
  "css",
  "js",
  "gsap",
  "webgl",
  "canvas",
  "andere"
 ],
 "leistungskosten": "niedrig",
 "steckbrief": {
  "beschreibung": "Zwei deckungsgleiche Ebenen liegen übereinander. Unten die sichtbare Basis (Text oder Bild), oben eine zweite Fassung (ehrlicher Text, Raster, Röntgenbild). Die obere Ebene trägt eine mask-image mit radial-gradient, deren Mittelpunkt dem Zeiger folgt. Abseits des Ziels ist der Kreis klein (Ø 40 px) und wirkt wie ein Cursorpunkt. Über dem Ziel wächst er auf Ø 400 px und legt die zweite Ebene frei, mit Überschwinger (back.out, 500 ms). Die Spotlight-Variante dreht das Prinzip um: Eine dunkle Fläche liegt über allem, nur am Zeiger ist es hell.",
  "warum_es_wirkt": "Neugier. Der Nutzer entdeckt eine zweite Bedeutungsebene, ohne dass sich das Layout verändert. Das erzeugt Doppelbödigkeit und eine kleine Pointe. Gut für Wortspiele und Persönlichkeit. Sehr erinnerbar, wenn der Inhalt den Effekt begründet.",
  "wann_einsetzen": "Hero-Statements und Über-uns-Seiten von Portfolios mit Pointe. Vorher/Nachher und Produkt-Innenleben (Röntgenblick). Kampagnen mit Doppelbotschaft. Dunkle Hero-Sektionen und 404-Seiten mit Taschenlampe.",
  "wann_nicht": "Wenn die verborgene Ebene wichtige Information trägt: Touch- und Tastaturnutzer sähen sie sonst nie. Bei langen Fließtexten. Auf Touch-first-Seiten ohne Ersatz wie Gedrückt-halten oder Umschalter.",
  "varianten": [
   "Zwei Fassungen eines Textes: Der Kreis wächst über der Überschrift von Ø 40 auf 400 px (Olivier Larose nach minhpham.design)",
   "Röntgenblick auf ein Bild: Die Maske zeigt Raster, Skizze oder Innenleben",
   "Taschenlampe: dunkle Fläche mit radialem Lichtkegel am Zeiger (radial-gradient an --x/--y)",
   "Pinsel: eine Canvas-Maske sammelt Pinselstriche, die nach 1,4 s verblassen; darunter das fertige Foto, darüber die Skizze",
   "Vorher/Nachher-Scharfzeichnen: Basis unscharf, die Maske zeigt das scharfe Bild",
   "Spotlight mit per @property registrierten Größen und Zeigerposition in Prozent (Chrome-Anleitung)",
   "Malen und Radieren mit Canvas destination-out, die Spur bleibt stehen (Olivier Larose, Paint Reveal)",
   "WebGL: Spotlight-Shader oder Fluid-Simulation als Maske für eine zweite 3D-Szene (Codrops 03/2026)"
  ],
  "umsetzung": "CSS: @property --r { syntax: '<length>'; inherits: false; initial-value: 20px; } registrieren, sonst animiert transition den Radius nicht. Obere Ebene: mask-image: radial-gradient(circle var(--r) at var(--x) var(--y), #000 calc(100% - 1.5px), transparent 100%), dazu -webkit-mask-image. transition: --r .5s cubic-bezier(0.34, 1.56, 0.64, 1). Über dem Ziel --r auf 200px setzen (Ø 400 px). JS: pointermove setzt das Ziel, ein rAF-Loop lerpt x/y mit 0,12 pro Bild und schreibt --x/--y in Pixeln. Alternative nach Larose: SVG-Kreis als mask-image, mask-size und mask-position folgen dem Zeiger. Spotlight: Overlay mit radial-gradient(circle var(--r) at var(--x) var(--y), transparent, rgba(0,0,0,.7) 78 %, rgba(0,0,0,.96)), transition: --r 200ms ease-in-out. Fallstricke: obere Ebene pointer-events: none, damit Links darunter klickbar bleiben. Radius in Pixeln statt Prozent, sonst wird der Kreis zur Ellipse. Beide Ebenen gleich aufbauen (Breite, Schrift, Abstände), sonst springen die Zeilen.",
  "mobil": "Gedrückt halten zeigt die Maske groß unter dem Finger, Ziehen bewegt sie. Dazu ein Umschalter, der die zweite Ebene ganz zeigt. Alternativ wandert die Maske einmal selbst. Die Paint-Variante funktioniert mit Touch gut.",
  "reduzierte_bewegung": "Kein Nachlauf, die Maske sitzt direkt am Zeiger. Die Größe springt ohne Animation. Alternativ zeigt ein Umschalter beide Ebenen nacheinander statisch.",
  "barrierefreiheit": "Die Basis trägt den vollständigen Inhalt. Die verborgene Ebene ist echter Text, aber aria-hidden, wenn sie nur Pointe ist. Wichtige Aussagen gehören in die zugängliche Ebene. Ein Umschalter (button mit aria-pressed) macht die zweite Ebene für Tastatur und Touch sichtbar."
 },
 "messwerte": {
  "easing": "backOut (Olivier Larose); ease-in-out (Chrome)",
  "dauer_ms": "500 (Größe, Larose); 200 (Chrome)",
  "stagger_ms": "",
  "distanz": "Maskendurchmesser 40 px → 400 px",
  "sonstiges": "",
  "herkunft": "beobachtet",
  "quelle": "https://blog.olivierlarose.com/tutorials/mask-cursor-effect ; https://developer.chrome.com/docs/modern-web-guidance/guides/ui-behaviors/interactive-content-reveal",
  "aus_eintrag": [
   "cursor-masken-reveal"
  ]
 },
 "kurve": {
  "bezier": [
   0.34,
   1.56,
   0.64,
   1
  ],
  "css": "cubic-bezier(0.34, 1.56, 0.64, 1)",
  "name": "back.out",
  "dauer_ms": 500
 },
 "gesehen_bei": [
  {
   "seite": "Olivier Larose: Mask Cursor Effect",
   "url": "https://blog.olivierlarose.com/tutorials/mask-cursor-effect",
   "auszeichnung": "",
   "beobachtung": "WebkitMaskPosition/-Size folgen dem Cursor; Größe 40 px → 400 px über dem Text; tween backOut 0.5 s; inspiriert von minhpham.design.",
   "art": "artikel",
   "weitere_beobachtung": "WebkitMaskPosition folgt Zeiger, mask-size 40 → 400 px bei Hover, Tween backOut 0,5 s."
  },
  {
   "seite": "Minh Pham – Portfolio",
   "url": "https://minhpham.design/",
   "auszeichnung": "",
   "beobachtung": "Von Olivier Larose als Inspiration für den Masken-Cursor genannt; zwei Fassungen desselben Texts (‚making good shit since 2009‘ / ‚Hiding bad shit since 2009‘) im Markup – der Masken-Reveal zeigt die ehrliche Version.",
   "art": "website",
   "weitere_beobachtung": "Im Tutorial als Inspirationsquelle verlinkt (nicht selbst geöffnet)."
  },
  {
   "seite": "Chrome Developers: Interactive content reveal",
   "url": "https://developer.chrome.com/docs/modern-web-guidance/guides/ui-behaviors/interactive-content-reveal",
   "auszeichnung": "",
   "beobachtung": "Offizielle Anleitung: mask-image radial-gradient mit @property --inner-size/--outer-size, pointermove + ResizeObserver setzen --mouse-x/-y in %, Transition 0.2 s ease-in-out.",
   "art": "artikel"
  },
  {
   "seite": "Codrops: Dual-Scene Fluid X-Ray Reveal in Three.js (03/2026)",
   "url": "https://tympanus.net/codrops/2026/03/23/building-a-dual-scene-fluid-x-ray-reveal-effect-in-three-js/",
   "auszeichnung": "",
   "beobachtung": "Im Codrops-Telegram-Kanal gelistet; Artikel beim Abruf nicht lesbar – Technikdetails nicht verifiziert.",
   "art": "artikel"
  },
  {
   "seite": "Olivier Larose: Paint Reveal",
   "url": "https://blog.olivierlarose.com/tutorials/paint-reveal",
   "auszeichnung": "",
   "beobachtung": "Reveal/Radieren über Canvas-Blendmode destination-out.",
   "art": "artikel"
  },
  {
   "seite": "Josh W. Comeau",
   "url": "https://www.joshwcomeau.com/",
   "auszeichnung": "",
   "beobachtung": "404-Seite (app/not-found-Chunk): :root:before Vollflächen-Overlay mit radial-gradient(circle 16vmax at var(--cursorX) var(--cursorY), transparent 0 %, rgba(0,0,0,.5) 80 %, rgba(0,0,0,.8) 100 %) – Taschenlampen-Spotlight, Systemcursor ausgeblendet.",
   "art": "website"
  }
 ],
 "tutorials": [
  {
   "titel": "Olivier Larose: Mask Cursor Effect",
   "url": "https://blog.olivierlarose.com/tutorials/mask-cursor-effect"
  },
  {
   "titel": "Chrome: Interactive content reveal",
   "url": "https://developer.chrome.com/docs/modern-web-guidance/guides/ui-behaviors/interactive-content-reveal"
  },
  {
   "titel": "Osmo – Spotlight Cursor (Unicorn Studio)",
   "url": "https://www.osmo.supply/resource/spotlight-cursor-unicorn-studio"
  }
 ],
 "kombinierbar_mit": [
  "kontextueller-cursor",
  "karten-spotlight-glow",
  "webgl-bildverzerrung",
  "cursor-follower-lerp",
  "blend-difference-cursor"
 ],
 "urls": {
  "detail": "https://cecodesign.de/lab/fundus/cursor/cursor-masken-reveal/",
  "meta": "https://cecodesign.de/lab/fundus/cursor/cursor-masken-reveal/meta.json",
  "demo": "https://cecodesign.de/lab/fundus/cursor/cursor-masken-reveal/demo"
 },
 "herkunft": {
  "quelldateien": [
   "hover.json",
   "schriftanimation.json",
   "patch-belege-1.json"
  ],
  "pruefnotizen": [
   "patch-belege-1.json: Zweiter Produktionsbeleg (zusammen mit minhpham.design). Effekt dort auf der 404-Seite."
  ],
  "zusammengelegt_aus": [
   "cursor-masken-reveal",
   "spotlight-mask-cursor"
  ],
  "trendstatus_begruendung": "Konflikt aufsteigend (hover) vs. etabliert (Cursor). Aufgelöst zu 'etabliert': die mask-image-Technik am Zeiger ist seit Jahren auf Portfolio-Seiten verbreitet und durch zahlreiche Tutorials standardisiert; neu ist nur die Häufung als 'versteckte Wahrheit'-Gag.",
  "querverweis_kategorien": [
   "Hover"
  ]
 },
 "bau": {
  "status": "fertig",
  "kurz": "Ein Kreis am Zeiger wächst über der Überschrift von 40 auf 400 px und legt eine zweite, ehrlichere Ebene frei.",
  "demo": true,
  "abhaengigkeiten": [],
  "werte": {
   "maske": "mask-image: radial-gradient(circle var(--r) at var(--x) var(--y), #000 calc(100% - 1.5px), transparent 100%) plus -webkit-mask-image",
   "radius_property": "@property --r { syntax: '<length>'; inherits: false; initial-value: 20px }",
   "durchmesser_px": "40 → 400 (--r 20px → min(200px, 42vw))",
   "easing_maske": "cubic-bezier(0.34, 1.56, 0.64, 1) (back.out)",
   "dauer_maske_ms": 500,
   "umschalter_alles_zeigen": "--r 150vmax, 900 ms, gleiche Kurve",
   "lerp": "0.12 pro Bild bei 60 Hz, auf die echte Bildrate umgerechnet (1 - (1 - 0.12)^(dt/16.667))",
   "trefferzone_px": 8,
   "spotlight_radius": "160 → 260 px (min(160px, 36vw) → min(260px, 48vw)), Umschalter 150vmax in 600 ms",
   "spotlight_easing": "cubic-bezier(0.42, 0, 0.58, 1) (ease-in-out)",
   "spotlight_dauer_ms": 200,
   "spotlight_verlauf": "rgba(12,11,10,0) 0 %, rgba(12,11,10,.08) 40 %, rgba(12,11,10,.7) 78 %, rgba(12,11,10,.96) 100 %; darüber Lichtschein rgba(255,210,140,.1) → transparent 75 %",
   "roentgen_filter": "filter: grayscale(1) invert(1) contrast(1.25); mix-blend-mode: screen; opacity .9 auf #1d39b0, darüber SVG-Raster 12 Spalten",
   "farben": "Papier #eeebe4, Tinte #141413, Akzent zweite Ebene #e4502f, Röntgen #1d39b0, Bühne #0c0b0a / #16130f, Gold #d9b46a",
   "schrift": "Instrument Sans 500, Satz clamp(46px, 7.4vw, 116px), Laufweite -0.045em, Zeilenhöhe .95; Akzent Instrument Serif Italic",
   "ui_ms": 150,
   "vorfuehrung_ms": 8000
  },
  "ausloeser": "hover",
  "touch": "Gedrückt halten zeigt die Maske groß unter dem Finger, Ziehen auf Satz oder Bild bewegt sie (touch-action: none nur dort). Beim Laden wandert die Maske einmal selbst. Der Knopf zeigt die zweite Ebene ganz. Pinsel: mit dem Finger auf der Skizze malen (touch-action: none nur im Rahmen); die Striche bleiben beim nächsten Tippen erhalten.",
  "reduziert": "Kein Nachlauf, die Maske sitzt direkt am Zeiger, die Größe springt ohne Übergang. Die Vorführung zeigt beide Ebenen im Wechsel (2,6 s) statt Bewegung. Der Knopf bleibt. Pinsel: Striche verblassen nicht, kein Nachlauf; die Vorführung wechselt zwischen Skizze und Foto.",
  "korrekturen": {
   "beschreibung": "Zwei deckungsgleiche Ebenen liegen übereinander. Unten die sichtbare Basis (Text oder Bild), oben eine zweite Fassung (ehrlicher Text, Raster, Röntgenbild). Die obere Ebene trägt eine mask-image mit radial-gradient, deren Mittelpunkt dem Zeiger folgt. Abseits des Ziels ist der Kreis klein (Ø 40 px) und wirkt wie ein Cursorpunkt. Über dem Ziel wächst er auf Ø 400 px und legt die zweite Ebene frei, mit Überschwinger (back.out, 500 ms). Die Spotlight-Variante dreht das Prinzip um: Eine dunkle Fläche liegt über allem, nur am Zeiger ist es hell.",
   "warum_es_wirkt": "Neugier. Der Nutzer entdeckt eine zweite Bedeutungsebene, ohne dass sich das Layout verändert. Das erzeugt Doppelbödigkeit und eine kleine Pointe. Gut für Wortspiele und Persönlichkeit. Sehr erinnerbar, wenn der Inhalt den Effekt begründet.",
   "wann_einsetzen": "Hero-Statements und Über-uns-Seiten von Portfolios mit Pointe. Vorher/Nachher und Produkt-Innenleben (Röntgenblick). Kampagnen mit Doppelbotschaft. Dunkle Hero-Sektionen und 404-Seiten mit Taschenlampe.",
   "wann_nicht": "Wenn die verborgene Ebene wichtige Information trägt: Touch- und Tastaturnutzer sähen sie sonst nie. Bei langen Fließtexten. Auf Touch-first-Seiten ohne Ersatz wie Gedrückt-halten oder Umschalter.",
   "varianten": [
    "Zwei Fassungen eines Textes: Der Kreis wächst über der Überschrift von Ø 40 auf 400 px (Olivier Larose nach minhpham.design)",
    "Röntgenblick auf ein Bild: Die Maske zeigt Raster, Skizze oder Innenleben",
    "Taschenlampe: dunkle Fläche mit radialem Lichtkegel am Zeiger (radial-gradient an --x/--y)",
    "Pinsel: eine Canvas-Maske sammelt Pinselstriche, die nach 1,4 s verblassen; darunter das fertige Foto, darüber die Skizze",
    "Vorher/Nachher-Scharfzeichnen: Basis unscharf, die Maske zeigt das scharfe Bild",
    "Spotlight mit per @property registrierten Größen und Zeigerposition in Prozent (Chrome-Anleitung)",
    "Malen und Radieren mit Canvas destination-out, die Spur bleibt stehen (Olivier Larose, Paint Reveal)",
    "WebGL: Spotlight-Shader oder Fluid-Simulation als Maske für eine zweite 3D-Szene (Codrops 03/2026)"
   ],
   "umsetzung": "CSS: @property --r { syntax: '<length>'; inherits: false; initial-value: 20px; } registrieren, sonst animiert transition den Radius nicht. Obere Ebene: mask-image: radial-gradient(circle var(--r) at var(--x) var(--y), #000 calc(100% - 1.5px), transparent 100%), dazu -webkit-mask-image. transition: --r .5s cubic-bezier(0.34, 1.56, 0.64, 1). Über dem Ziel --r auf 200px setzen (Ø 400 px). JS: pointermove setzt das Ziel, ein rAF-Loop lerpt x/y mit 0,12 pro Bild und schreibt --x/--y in Pixeln. Alternative nach Larose: SVG-Kreis als mask-image, mask-size und mask-position folgen dem Zeiger. Spotlight: Overlay mit radial-gradient(circle var(--r) at var(--x) var(--y), transparent, rgba(0,0,0,.7) 78 %, rgba(0,0,0,.96)), transition: --r 200ms ease-in-out. Fallstricke: obere Ebene pointer-events: none, damit Links darunter klickbar bleiben. Radius in Pixeln statt Prozent, sonst wird der Kreis zur Ellipse. Beide Ebenen gleich aufbauen (Breite, Schrift, Abstände), sonst springen die Zeilen.",
   "mobil": "Gedrückt halten zeigt die Maske groß unter dem Finger, Ziehen bewegt sie. Dazu ein Umschalter, der die zweite Ebene ganz zeigt. Alternativ wandert die Maske einmal selbst. Die Paint-Variante funktioniert mit Touch gut.",
   "reduzierte_bewegung": "Kein Nachlauf, die Maske sitzt direkt am Zeiger. Die Größe springt ohne Animation. Alternativ zeigt ein Umschalter beide Ebenen nacheinander statisch.",
   "barrierefreiheit": "Die Basis trägt den vollständigen Inhalt. Die verborgene Ebene ist echter Text, aber aria-hidden, wenn sie nur Pointe ist. Wichtige Aussagen gehören in die zugängliche Ebene. Ein Umschalter (button mit aria-pressed) macht die zweite Ebene für Tastatur und Touch sichtbar."
  },
  "geprueft": "02.11.2026",
  "notiz": "Portfolio-Ausschnitt des erfundenen Studio Fernlicht mit drei Varianten: Text (zwei Fassungen eines Satzes, Kreis Ø 40 → 400 px, back.out 500 ms), Röntgen (Magazin Gefüge, darunter Negativ mit 12-Spalten-Raster) und Spotlight (dunkle Bühne mit der Marke Eselsohr, Lichtkegel 160 → 260 px, ease-in-out 200 ms). Größe hängt an einer Trefferzone um das Ziel, nicht an Hover-Events, damit Vorführung und Zeiger gleich laufen. Knopf zeigt die zweite Ebene ganz (Tastatur, Touch, reduzierte Bewegung). Bilder 01.11.2026: eigene Bilder statt Portfolio. Zugang 02.11.2026: --leise Alpha .56 auf .64 (5,2:1), leise Labels der verborgenen Ebene auf Orange .62 auf .95 (4,6:1) und auf Blau .62 auf .74 (5,2:1), Knopfrahmen im Kontrastmodus. Korrektur 02.11.2026: Variante pinsel (Paintbrush-Prinzip, eigener Code): Keramik-Stillleben für die erfundene Werkstatt Keramik Tonfeld, die Skizze wird aus dem Foto berechnet (Sobel + Schraffur), Pinselstempel mit Borsten, Halten 1,4 s, Verblassen 1,6 s. Varianten nach Regel 13 (?v=text|roentgen|spot|pinsel, replaceState); Variantenknöpfe umbrechen bei 320 px.",
  "varianten": [
   {
    "id": "text",
    "name": "Text: zwei Fassungen eines Satzes",
    "knopf": "Text",
    "wann": "Studio- oder Agentur-Startseite mit einem Haltungssatz, der eine ehrlichere zweite Fassung versteckt.",
    "werte": {
     "maske": "radial-gradient, Ø 40 → 400 px, back.out 500 ms"
    }
   },
   {
    "id": "roentgen",
    "name": "Röntgen: Raster unter dem Layout",
    "knopf": "Röntgen",
    "wann": "Editorial, Architektur oder Produkt, wenn das Innenleben (Raster, Konstruktion, Skizze) neugierig machen soll.",
    "werte": {
     "zweite_ebene": "grayscale(1) invert(1) contrast(1.25), screen auf #1d39b0, SVG-Raster"
    }
   },
   {
    "id": "spot",
    "name": "Spotlight: Lichtkegel auf dunkler Bühne",
    "knopf": "Spotlight",
    "wann": "Kultur, Lesung, Nachtprogramm: eine dunkle Bühne, auf der nur sichtbar wird, wohin man leuchtet.",
    "werte": {
     "radius": "160 → 260 px",
     "easing": "ease-in-out 200 ms"
    }
   },
   {
    "id": "pinsel",
    "name": "Pinsel: Striche legen das Foto unter der Skizze frei",
    "knopf": "Pinsel",
    "wann": "Studio, Fotografie oder Handwerk, wenn Entwurf und Ergebnis gezeigt werden (Skizze → Foto, Rohbau → fertig); die Striche verblassen, das Bild bleibt unverfälscht.",
    "werte": {
     "technik": "zwei Canvas im Bildrahmen: Maske sammelt Pinselstempel, Farb-Canvas = Maske, dann source-in das Foto (object-fit cover)",
     "pinsel": "Ø min(84 px, 12 % der Rahmenbreite), bei Tempo ≥ 1,6 px/ms bis 0,55 × (≈ 46 px); Stempel alle 0,18 Ø entlang der Strecke, gedreht in Zugrichtung",
     "stempel": "128 × 128 Canvas, 34 Borsten in Zugrichtung, zum Rand kürzer und blasser, Breite 2 bis 5,4 px",
     "halten_ms": 1400,
     "verblassen_ms": "1600, smoothstep; höchstens 900 Stempel",
     "skizze": "einmal aus dem Foto gerechnet (900 px breit): Graustufe, 3 × 3 Weichzeichnen, Sobel-Kante (0,07, × 3,2) als Graphit #282623 auf Papier #eeebe4, dunkle Flächen schraffiert (jede 7. Diagonale); ohne Pixelzugriff (file://) CSS-Ersatz grayscale contrast sepia",
     "folgen_lerp": "0.12 wie die Grundvariante",
     "knopf": "„Ganzes Foto zeigen“ blendet das Foto in 600 ms ease-in-out ein"
    }
   }
  ]
 }
}
