fix: make landing page animations more dramatic and noticeable
- Slower chat stagger (1.2s between lines, not 0.6s) so each message is clearly individual and watchable - Messages slide in from left (translateX -20px) not just fade up - Typing indicator is bigger with blue tinted background, border, and "FlowPilot is thinking..." label - Typing indicator holds for 3s before collapsing (was 1.8s) - App preview has cinematic entrance (scale 0.95 → 1 + translateY) - AI responses wait until typing indicator finishes, then cascade - Doc confirmation has extra pause before appearing (9.6s total) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -225,6 +225,7 @@ export default function LandingPage() {
|
||||
<div className="landing-chat-animated" style={{ '--chat-index': 1 } as React.CSSProperties}>
|
||||
<div className="landing-typing-indicator">
|
||||
<span /><span /><span />
|
||||
<span style={{ fontSize: '0.55rem', color: '#60a5fa', marginLeft: 4, fontWeight: 500, whiteSpace: 'nowrap' }}>FlowPilot is thinking...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="landing-chat-animated" style={{ '--chat-index': 2 } as React.CSSProperties}>
|
||||
|
||||
@@ -1510,58 +1510,70 @@
|
||||
============================================ */
|
||||
|
||||
/* ── A) ANIMATED CHAT MESSAGES ── */
|
||||
/* Each chat line fades in and slides up with staggered timing.
|
||||
The typing indicator appears between user message and AI response,
|
||||
then hides when the AI lines appear. */
|
||||
/* Deliberate, watchable conversation sequence.
|
||||
User types → thinking → AI responds line by line → doc confirmation */
|
||||
|
||||
.landing-chat-animated {
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
animation: landingChatReveal 0.4s ease-out both;
|
||||
/* Base delay: 1.5s (after hero entrance) + stagger per line */
|
||||
animation-delay: calc(1.5s + var(--chat-index, 0) * 0.6s);
|
||||
transform: translateX(-20px);
|
||||
animation: landingChatSlideIn 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||
/* Slower stagger: 1.2s per message so each line is clearly individual.
|
||||
Base delay 2s (after hero + preview entrance). */
|
||||
animation-delay: calc(2s + var(--chat-index, 0) * 1.2s);
|
||||
}
|
||||
|
||||
/* The typing indicator (index 1) appears, then fades out when index 2 appears */
|
||||
/* The typing indicator (index 1) has its own lifecycle: appear → hold → collapse */
|
||||
.landing-chat-animated:nth-child(2) {
|
||||
animation: landingTypingLifecycle 1.8s ease both;
|
||||
animation-delay: calc(1.5s + 0.6s);
|
||||
animation: landingTypingLifecycle 3s ease both;
|
||||
animation-delay: 3.2s; /* appears after user message */
|
||||
}
|
||||
|
||||
@keyframes landingChatReveal {
|
||||
/* AI responses start after typing indicator finishes (3.2s + 3s = 6.2s) */
|
||||
.landing-chat-animated:nth-child(3) { animation-delay: 6.2s; }
|
||||
.landing-chat-animated:nth-child(4) { animation-delay: 7.2s; }
|
||||
.landing-chat-animated:nth-child(5) { animation-delay: 8.2s; }
|
||||
/* Doc confirmation comes last with extra pause */
|
||||
.landing-chat-animated:nth-child(6) { animation-delay: 9.6s; }
|
||||
|
||||
@keyframes landingChatSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes landingTypingLifecycle {
|
||||
0% { opacity: 0; transform: translateY(8px); }
|
||||
15% { opacity: 1; transform: translateY(0); }
|
||||
70% { opacity: 1; transform: translateY(0); }
|
||||
100% { opacity: 0; transform: translateY(0); height: 0; padding: 0; margin: 0; overflow: hidden; }
|
||||
0% { opacity: 0; transform: translateX(-20px); }
|
||||
10% { opacity: 1; transform: translateX(0); }
|
||||
75% { opacity: 1; transform: translateX(0); }
|
||||
90% { opacity: 0; transform: translateX(0); }
|
||||
100% { opacity: 0; height: 0; padding: 0; margin: 0; overflow: hidden; }
|
||||
}
|
||||
|
||||
/* ── Typing indicator dots ── */
|
||||
/* ── Typing indicator dots — bigger, with label ── */
|
||||
.landing-typing-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 4px 8px;
|
||||
gap: 6px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 8px;
|
||||
background: rgba(96, 165, 250, 0.06);
|
||||
border: 1px solid rgba(96, 165, 250, 0.1);
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.landing-typing-indicator span {
|
||||
display: block;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background: #60a5fa;
|
||||
opacity: 0.4;
|
||||
animation: landingTypingBounce 1.2s ease-in-out infinite;
|
||||
opacity: 0.5;
|
||||
animation: landingTypingBounce 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.landing-typing-indicator span:nth-child(2) {
|
||||
@@ -1572,28 +1584,54 @@
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
/* The label text span — no bounce animation */
|
||||
.landing-typing-indicator span:nth-child(4) {
|
||||
width: auto;
|
||||
height: auto;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
opacity: 1;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
@keyframes landingTypingBounce {
|
||||
0%, 60%, 100% {
|
||||
transform: translateY(0);
|
||||
opacity: 0.4;
|
||||
}
|
||||
30% {
|
||||
transform: translateY(-4px);
|
||||
transform: translateY(-5px);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Sidebar items stagger in ── */
|
||||
.landing-preview-sidebar-item {
|
||||
opacity: 0;
|
||||
animation: landingChatReveal 0.3s ease-out both;
|
||||
/* ── App preview cinematic entrance ── */
|
||||
.landing-app-preview {
|
||||
animation: landingPreviewEntrance 1s cubic-bezier(0.22, 1, 0.36, 1) 0.75s both;
|
||||
}
|
||||
|
||||
.landing-preview-sidebar-item:nth-child(1) { animation-delay: 0.8s; }
|
||||
.landing-preview-sidebar-item:nth-child(2) { animation-delay: 0.9s; }
|
||||
.landing-preview-sidebar-item:nth-child(3) { animation-delay: 1.0s; }
|
||||
.landing-preview-sidebar-item:nth-child(4) { animation-delay: 1.1s; }
|
||||
.landing-preview-sidebar-item:nth-child(5) { animation-delay: 1.2s; }
|
||||
@keyframes landingPreviewEntrance {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(40px) scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Sidebar items stagger in with slide ── */
|
||||
.landing-preview-sidebar-item {
|
||||
opacity: 0;
|
||||
animation: landingChatSlideIn 0.35s cubic-bezier(0.22, 1, 0.36, 1) both;
|
||||
}
|
||||
|
||||
.landing-preview-sidebar-item:nth-child(1) { animation-delay: 1.2s; }
|
||||
.landing-preview-sidebar-item:nth-child(2) { animation-delay: 1.35s; }
|
||||
.landing-preview-sidebar-item:nth-child(3) { animation-delay: 1.5s; }
|
||||
.landing-preview-sidebar-item:nth-child(4) { animation-delay: 1.65s; }
|
||||
.landing-preview-sidebar-item:nth-child(5) { animation-delay: 1.8s; }
|
||||
|
||||
/* ── B) SCROLL-DRIVEN ENHANCEMENTS ── */
|
||||
/* Upgrade the basic reveal to use scroll-driven parallax where supported */
|
||||
@@ -1698,7 +1736,8 @@
|
||||
/* ── REDUCED MOTION ── */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.landing-chat-animated,
|
||||
.landing-preview-sidebar-item {
|
||||
.landing-preview-sidebar-item,
|
||||
.landing-app-preview {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
animation: none;
|
||||
|
||||
Reference in New Issue
Block a user