From 8c3900b9980cbdef20840be0d5bcd1993376cab7 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Thu, 28 May 2026 19:01:04 -0400 Subject: [PATCH] =?UTF-8?q?feat(showcase):=20dramatic=203D=20cascade=20ent?= =?UTF-8?q?ry=20=E2=80=94=20tiles=20tip=20back=20then=20settle=20into=20pl?= =?UTF-8?q?ace?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaced the subtle 12px fade with a perspective rotateX(-28deg) tilt that flips up and settles flat with a slight overshoot, staggered 70ms so tiles cascade in one at a time. Makes the showcase read as an experience rather than a quiet fade. Tunable (tilt/stagger/duration); reduced-motion safe. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../src/components/discovery/MasonryGrid.vue | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/discovery/MasonryGrid.vue b/frontend/src/components/discovery/MasonryGrid.vue index ecc43dc..7375be6 100644 --- a/frontend/src/components/discovery/MasonryGrid.vue +++ b/frontend/src/components/discovery/MasonryGrid.vue @@ -117,22 +117,35 @@ onUnmounted(() => observer && observer.disconnect()) } .fc-masonry__end { text-align: center; padding: 32px 0; } -/* IR-parity stagger fade-in for showcase entry / shuffle. 60ms between - items, 250ms each — matches IR's `itemFadeIn` keyframe (style.css - ~line 1834). Honors prefers-reduced-motion. */ +/* Cascade entry: each tile flips up out of a backward tilt and settles + into place, one at a time — more pronounced than a plain fade so the + showcase reads as an "experience" (operator-flagged 2026-05-28). The + `both` fill holds the hidden/tilted 0% state until each tile's staggered + turn; the cubic-bezier overshoots slightly past flat then settles. + Honors prefers-reduced-motion. Tunables: tilt (-28deg), stagger (70ms), + duration (0.6s). */ @keyframes fc-masonry-item-in { - from { opacity: 0; transform: translateY(12px); } - to { opacity: 1; transform: translateY(0); } + 0% { + opacity: 0; + transform: perspective(1000px) rotateX(-28deg) translateY(26px) scale(0.95); + } + 55% { opacity: 1; } + 100% { + opacity: 1; + transform: perspective(1000px) rotateX(0deg) translateY(0) scale(1); + } } .fc-masonry__item--anim { - animation: fc-masonry-item-in 0.25s ease forwards; - animation-delay: calc(var(--stagger-index, 0) * 60ms); - opacity: 0; + transform-origin: center top; + backface-visibility: hidden; + animation: fc-masonry-item-in 0.6s cubic-bezier(0.34, 1.45, 0.64, 1) both; + animation-delay: calc(var(--stagger-index, 0) * 70ms); } @media (prefers-reduced-motion: reduce) { .fc-masonry__item--anim { animation: none; opacity: 1; + transform: none; } .fc-masonry__item img { transition: none; } .fc-masonry__item:hover img { transform: none; }