useFyskAnimation Hook

The centralized animation control system for Fysk. Provides pre-computed transitions and variants for consistent, professional animations across all components.

About useFyskAnimation

The useFyskAnimation hook is the bridge between your animation configuration (set in FyskProvider) and individual components. It provides:

  • Motion Access: Returns the framer-motion motion object or fallback HTML elements when animations are disabled.

  • Pre-computed Transitions: Ready-to-use transition objects based on your duration and easing configuration.

  • Pre-computed Variants: Animation variants (fadeSlide, iconPop, scaleIn, etc.) that respect your effects configuration.

  • Conditional Logic: Automatically handles the enabled/disabled state so components gracefully degrade.

Why Centralized Animations?

Without centralization, animation values are scattered across components—a 200ms here, an easeOut there. This leads to:

  • Inconsistency: Different components feel disconnected because of varying timings.

  • Maintenance Pain: Changing the "feel" of your app requires editing dozens of files.

  • Bundle Bloat: framer-motion is imported everywhere, even when animations might be disabled.

The useFyskAnimation hook solves all of these by:

  • Single Source of Truth: All timing and easing values come from one configuration.

  • Instant Global Updates: Tweak durations.normal once, and every component updates.

  • Tree-Shakeable: When enabled: false, framer-motion is never imported by components.

Usage

Import the hook and destructure what you need:

typescript
typescript
1
import { useFyskAnimation } from "@fysk/ui"
2
3
function MyComponent() {
4
const {
5
isEnabled,
6
motion,
7
AnimatePresence,
8
transitions,
9
variants
10
} = useFyskAnimation()
11
12
return (
13
<motion.div
14
{...(isEnabled ? {
15
layout: true,
16
transition: transitions?.layout
17
} : {})}
18
>
19
<AnimatePresence mode="wait">
20
<motion.span
21
key={someKey}
22
{...(isEnabled && variants ? variants.fadeSlide : {})}
23
>
24
Content
25
</motion.span>
26
</AnimatePresence>
27
</motion.div>
28
)
29
}

Return Values

The hook returns an object with everything you need for animations:

typescript
typescript
1
const {
2
// Core
3
isEnabled, // boolean - Are animations enabled?
4
motion, // The motion object (or fallback HTML tags)
5
AnimatePresence, // AnimatePresence component (or React.Fragment)
6
config, // Full FyskAnimationConfig object
7
8
// Pre-computed objects (null if disabled)
9
transitions, // Pre-configured transition presets
10
variants, // Pre-configured animation variants
11
12
// Direct access to config values
13
durations, // { instant, fast, normal, slow, layout }
14
easings, // { enter, exit, layout, hover, linear }
15
effects, // { blur, blurAmount, scale, scaleAmount, slide, slideDistance }
16
} = useFyskAnimation()

Transitions

Pre-computed transition objects based on your configuration. Each is optimized for its specific use case:

typescript
typescript
1
// Available transitions:
2
transitions.layout // For size/position changes
3
transitions.enter // For entering elements
4
transitions.exit // For exiting elements
5
transitions.hover // For hover micro-interactions
6
transitions.content // For content swapping (includes nested layout)
7
transitions.linear // For constant animations (spinners)
8
transitions.layoutEnter // Combined layout + enter
9
10
// Usage example:
11
<motion.div
12
layout
13
transition={transitions?.layout}
14
>
15
...
16
</motion.div>

Variants

Pre-computed animation variants that respect your effects configuration:

typescript
typescript
1
// Available variants:
2
variants.fadeSlide // Fade + blur/scale/slide (based on effects config)
3
variants.fade // Simple fade only
4
variants.iconPop // Scale + rotate pop for icons
5
variants.overlay // Overlay fade in/out
6
variants.slideUp // Slide up from bottom
7
variants.scaleIn // Scale in/out (modals, popovers)
8
9
// Usage example:
10
<AnimatePresence mode="wait">
11
<motion.div
12
key={state}
13
{...(isEnabled && variants ? variants.fadeSlide : {})}
14
>
15
Content
16
</motion.div>
17
</AnimatePresence>

Configuration

Animation behavior is configured through FyskProvider. The hook reads this configuration and computes transitions/variants accordingly:

typescript
typescript
1
// In your providers.tsx
2
<FyskProvider
3
animations={{
4
enabled: true,
5
motion: motion,
6
AnimatePresence: AnimatePresence,
7
8
// Customize durations (in seconds)
9
durations: {
10
instant: 0.1, // 100ms - micro-interactions
11
fast: 0.15, // 150ms - quick feedback
12
normal: 0.2, // 200ms - standard transitions
13
slow: 0.3, // 300ms - deliberate animations
14
layout: 0.4, // 400ms - size/position changes
15
},
16
17
// Customize easings (based on "The Easing Blueprint")
18
easings: {
19
enter: "easeOut", // Entering elements (responsive)
20
exit: "easeOut", // Exiting elements
21
layout: "easeInOut", // Size changes (natural)
22
hover: "easeOut", // Hover interactions
23
linear: "linear", // Constant animations
24
},
25
26
// Customize visual effects
27
effects: {
28
blur: true, // Enable blur on transitions
29
blurAmount: 4, // Blur intensity (px)
30
scale: true, // Enable scale on transitions
31
scaleAmount: 0.95, // Scale amount
32
slide: true, // Enable slide effect
33
slideDistance: 10, // Slide distance (px)
34
},
35
}}
36
>
37
{children}
38
</FyskProvider>

All values have sensible defaults based on The Easing Blueprint, so you can start with just { enabled: true, motion, AnimatePresence }.

Example: Custom Component

Here's how to build a custom animated component using the hook:

typescript
typescript
1
"use client"
2
import { useFyskAnimation } from "@fysk/ui"
3
import { cn } from "@/lib/utils"
4
5
interface AnimatedCardProps {
6
children: React.ReactNode
7
state?: "idle" | "loading" | "success"
8
className?: string
9
}
10
11
export function AnimatedCard({
12
children,
13
state = "idle",
14
className
15
}: AnimatedCardProps) {
16
const {
17
isEnabled,
18
motion,
19
AnimatePresence,
20
transitions,
21
variants
22
} = useFyskAnimation()
23
24
return (
25
<motion.div
26
{...(isEnabled ? {
27
layout: true,
28
transition: transitions?.layout
29
} : {})}
30
className={cn(
31
"rounded-lg border bg-card p-4",
32
state === "success" && "border-green-500",
33
className
34
)}
35
>
36
<AnimatePresence {...(isEnabled ? { mode: "wait" } : {})}>
37
<motion.div
38
key={state}
39
{...(isEnabled && variants ? variants.fadeSlide : {})}
40
>
41
{state === "loading" ? (
42
<div className="flex items-center gap-2">
43
<div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" />
44
Loading...
45
</div>
46
) : state === "success" ? (
47
<div className="flex items-center gap-2 text-green-600">
48
✓ Success!
49
</div>
50
) : (
51
children
52
)}
53
</motion.div>
54
</AnimatePresence>
55
</motion.div>
56
)
57
}

This component will animate smoothly when animations are enabled, and fall back to instant state changes when disabled—no extra code required.

Built with 💖 | Created by Yashraj