Animations
ThesisLock uses small, consistent motion to make the app feel responsive: content fades in as it loads, lists reveal one row after another, statistics count up, and buttons and cards respond to your cursor. Nothing blocks you, and everything is built from plain CSS transitions with no animation library.
What moves
- Page sections fade in on load, sliding up slightly into place, with later sections following the earlier ones.
- Lists of anchors, feed entries, search results, activity, and groups reveal their rows in a quick staggered sequence.
- Headline numbers on the stats, dashboard, and profile pages count up from zero the first time they scroll into view.
- Buttons press in slightly when clicked, cards lift on hover, nav links grow an underline, and the copy button gives a small bounce when it succeeds.
Respecting reduced motion
Every animation honors the operating system prefers-reduced-motion setting. When reduced motion is requested, content appears immediately, numbers show their final value at once, and the hover and press effects are turned off, so the app stays usable and calm.
For contributors
Three small client components cover most cases. FadeIn fades and slides its children in on mount; StaggerList wraps a list and fades each child in after the last; and CountUp animates a number toward its value once it scrolls into view.
// Fade a section in on mount
<FadeIn delay={100} direction="up">
<section>...</section>
</FadeIn>
// Stagger a list of cards
<div className="space-y-3">
<StaggerList>
{items.map((item) => (
<div key={item.id}>...</div>
))}
</StaggerList>
</div>
// Count a stat up when it scrolls into view
<CountUp value={total} suffix=" anchors" />For a list rendered as a ul, pass as="li" to FadeIn so the row stays valid markup instead of nesting a div inside the list. The micro-interactions are utility classes you can add to any element: press-scale for buttons, hover-lift for cards, and nav-underline for links.