Spring

spring

Physics-based spring motion driven by mass, stiffness, and damping.

Preview

Installation

Terminal
flutter pub add nib_motion

Usage

dart
NibMotion(
  initial: NibAnim(opacity: 0, y: 16),
  animate: NibAnim(opacity: 1, y: 0),
  transition: NibTransition(
    spring: NibSpringDescription.wobbly,
  ),
  child: MyWidget(),
)

Examples

Spring Entrance

Physics-based spring entrance using mass, stiffness, and damping instead of a fixed duration.

dart
class SpringEntranceExample extends StatefulWidget {
  const SpringEntranceExample({super.key});

  @override
  State<SpringEntranceExample> createState() => _SpringEntranceExampleState();
}

class _SpringEntranceExampleState extends State<SpringEntranceExample> {
  final _signal = NibMotionReplaySignal();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF0D1117),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            NibMotionReplayScope(
              signal: _signal,
              child: NibMotion(
                initial: const NibAnim(y: 60),
                animate: const NibAnim(y: 0),
                transition: NibTransition.springGentle,
                child: Container(
                  width: 200,
                  height: 100,
                  decoration: BoxDecoration(
                    color: const Color(0xFF1C2537),
                    borderRadius: BorderRadius.circular(12),
                    border: Border.all(color: const Color(0xFF54C5F8).withAlpha(50)),
                  ),
                  child: const Center(
                    child: Text(
                      'Spring Gentle',
                      style: TextStyle(color: Color(0xFFEDF2F7), fontSize: 16, fontWeight: FontWeight.w600),
                    ),
                  ),
                ),
              ),
            ),
            const SizedBox(height: 24),
            TextButton.icon(
              onPressed: _signal.replay,
              icon: const Icon(Icons.replay, size: 16, color: Color(0xFF718096)),
              label: const Text('Replay', style: TextStyle(color: Color(0xFF718096), fontSize: 13)),
            ),
          ],
        ),
      ),
    );
  }
}

Wobbly Bounce

springWobbly overshoots and oscillates — great for playful UI like FABs or confirmations.

dart
class WobblyBounceExample extends StatefulWidget {
  const WobblyBounceExample({super.key});

  @override
  State<WobblyBounceExample> createState() => _WobblyBounceExampleState();
}

class _WobblyBounceExampleState extends State<WobblyBounceExample> {
  final _signal = NibMotionReplaySignal();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF0D1117),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            NibMotionReplayScope(
              signal: _signal,
              child: NibMotion(
                initial: const NibAnim(scale: 0.0),
                animate: const NibAnim(scale: 1.0),
                transition: NibTransition.springWobbly,
                child: Container(
                  width: 100,
                  height: 100,
                  decoration: BoxDecoration(
                    color: const Color(0xFF54C5F8),
                    borderRadius: BorderRadius.circular(20),
                  ),
                  child: const Center(
                    child: Icon(Icons.check_rounded, color: Color(0xFF07080D), size: 40),
                  ),
                ),
              ),
            ),
            const SizedBox(height: 24),
            TextButton.icon(
              onPressed: _signal.replay,
              icon: const Icon(Icons.replay, size: 16, color: Color(0xFF718096)),
              label: const Text('Replay', style: TextStyle(color: Color(0xFF718096), fontSize: 13)),
            ),
          ],
        ),
      ),
    );
  }
}

Custom Spring

Full control over mass, stiffness, and damping with NibSpringDescription.

dart
class CustomSpringExample extends StatefulWidget {
  const CustomSpringExample({super.key});

  @override
  State<CustomSpringExample> createState() => _CustomSpringExampleState();
}

class _CustomSpringExampleState extends State<CustomSpringExample> {
  final _signal = NibMotionReplaySignal();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF0D1117),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            NibMotionReplayScope(
              signal: _signal,
              child: NibMotion(
                initial: const NibAnim(y: 80),
                animate: const NibAnim(y: 0),
                transition: const NibTransition(
                  spring: NibSpringDescription(
                    mass: 1.0,
                    stiffness: 200.0,
                    damping: 16.0,
                  ),
                ),
                child: Container(
                  width: 200,
                  height: 100,
                  decoration: BoxDecoration(
                    color: const Color(0xFF1C2537),
                    borderRadius: BorderRadius.circular(12),
                    border: Border.all(color: const Color(0xFF54C5F8).withAlpha(50)),
                  ),
                  child: const Center(
                    child: Text(
                      'Custom Spring',
                      style: TextStyle(color: Color(0xFFEDF2F7), fontSize: 15, fontWeight: FontWeight.w600),
                    ),
                  ),
                ),
              ),
            ),
            const SizedBox(height: 8),
            const Text(
              'mass: 1.0  stiffness: 200  damping: 16',
              style: TextStyle(color: Color(0xFF718096), fontSize: 11, fontFamily: 'monospace'),
            ),
            const SizedBox(height: 16),
            TextButton.icon(
              onPressed: _signal.replay,
              icon: const Icon(Icons.replay, size: 16, color: Color(0xFF718096)),
              label: const Text('Replay', style: TextStyle(color: Color(0xFF718096), fontSize: 13)),
            ),
          ],
        ),
      ),
    );
  }
}

API Reference

API class

NibSpringDescription

API Properties

massstiffnessdamping