# How LunaTV Implements Framer Motion Animations: A Technical Deep Dive

> Explore how LunaTV uses Framer Motion for dynamic UI animations. Discover variant-based state machines, component wrappers, and AnimatePresence for seamless transitions.

- Repository: [MoonTechLab/LunaTV](https://github.com/MoonTechLab/LunaTV)
- Tags: deep-dive
- Published: 2026-09-08

---

**LunaTV leverages Framer Motion v12.18.1 to drive fluid UI animations through variant-based state machines, motion component wrappers, and `AnimatePresence` orchestration for mount/unmount transitions.**

The MoonTechLab/LunaTV repository demonstrates production-grade React animation patterns using Framer Motion. This technical examination reveals how the codebase structures animation architecture, from dependency configuration in [`package.json`](https://github.com/MoonTechLab/LunaTV/blob/main/package.json) to the sophisticated multi-level selector implementation featuring dynamic transition controls.

## Framer Motion Configuration and Dependencies

According to the LunaTV source code, Framer Motion is registered as a core dependency in the project's [`package.json`](https://github.com/MoonTechLab/LunaTV/blob/main/package.json) manifest. The library is pinned to version **12.18.1**, ensuring consistent animation behavior across development and production environments.

Components throughout the application import animation primitives from the `framer-motion` package:

```tsx
import { motion, AnimatePresence } from 'framer-motion'

```

This import pattern appears in key UI components, including the multi-level selector located at [`src/components/MultiLevelSelector.tsx`](https://github.com/MoonTechLab/LunaTV/blob/main/src/components/MultiLevelSelector.tsx).

## Core Animation Architecture

### Motion Component Wrappers

LunaTV implements animations by wrapping standard JSX elements with Framer Motion's `motion` factory. This transformation converts static DOM elements into animatable entities capable of responding to gesture and state changes.

In [`src/components/MultiLevelSelector.tsx`](https://github.com/MoonTechLab/LunaTV/blob/main/src/components/MultiLevelSelector.tsx), standard `div` and `ul` elements become `motion.div` and `motion.ul`, enabling the component to accept animation-specific props like `variants`, `initial`, and `animate`.

### Variant-Based State Machines

The repository employs **variants**—declarative state objects that define visual appearances for different animation phases. Each variant specifies target CSS properties for states including `initial`, `animate`, and `exit`.

```tsx
const listVariants = {
  hidden: { opacity: 0, y: -10 },
  visible: { 
    opacity: 1, 
    y: 0, 
    transition: { staggerChildren: 0.05 } 
  }
}

```

This pattern allows LunaTV to orchestrate complex, multi-element animations through single state changes, with the parent variant automatically coordinating child element transitions via `staggerChildren` timing.

## Multi-Level Selector Implementation

### Animated Dropdown Transitions

The primary demonstration of LunaTV's Framer Motion implementation appears in the multi-level selector component. This UI element handles selection changes through sliding transitions with smooth easing curves.

The component structure utilizes `AnimatePresence` to manage the lifecycle of dropdown lists, ensuring elements animate out gracefully before unmounting:

```tsx
<AnimatePresence>
  <motion.ul
    variants={listVariants}
    initial="hidden"
    animate="visible"
    exit="hidden"
  >
    {options.map(opt => (
      <motion.li
        key={opt.value}
        whileHover={{ scale: 1.05 }}
        onClick={() => onSelect(opt.value)}
      >
        {opt.label}
      </motion.li>
    ))}
  </motion.ul>
</AnimatePresence>

```

### Stop Motion Toggle Feature

A distinctive feature within the LunaTV selector is the "stop motion" option (Chinese: **定格动画**), which provides users control over animation playback. This functionality toggles between fluid animated transitions and static state changes.

The implementation switches between variant states based on a boolean flag:

```tsx
const variants = {
  moving: { 
    rotate: 360, 
    transition: { repeat: Infinity, duration: 2 } 
  },
  still: { rotate: 0 }
}

<motion.div
  animate={stop ? 'still' : 'moving'}
  variants={variants}
/>

```

When `stop` is true, the component immediately settles to the `still` variant, bypassing transition animations entirely.

## Advanced Animation Patterns

### Gesture-Based Interactions

Beyond entrance and exit animations, LunaTV incorporates interactive feedback through Framer Motion's gesture props. The `whileHover` and `whileTap` properties provide immediate visual response to user input without requiring explicit state management:

```tsx
<motion.li
  whileHover={{ scale: 1.05 }}
  whileTap={{ scale: 0.95 }}
>
  Interactive Item
</motion.li>

```

These props accept transform values that apply temporarily during user interaction, reverting automatically when the gesture ends.

### Staggered List Orchestration

For multi-element reveals, the codebase leverages `staggerChildren` within variant definitions. This property delays the animation start of each child element by a specified duration (0.05 seconds in the selector implementation), creating sequential rather than simultaneous entrance effects.

The parent container defines the stagger timing, while child elements reference simplified variants that inherit the delay sequence:

```tsx
const containerVariants = {
  visible: {
    transition: { staggerChildren: 0.05 }
  }
}

const itemVariants = {
  hidden: { opacity: 0, y: 10 },
  visible: { opacity: 1, y: 0 }
}

```

## Summary

- **LunaTV** uses **Framer Motion v12.18.1** as specified in [`package.json`](https://github.com/MoonTechLab/LunaTV/blob/main/package.json) to handle all UI animations
- The **multi-level selector** at [`src/components/MultiLevelSelector.tsx`](https://github.com/MoonTechLab/LunaTV/blob/main/src/components/MultiLevelSelector.tsx) serves as the primary implementation reference
- **Variant-based state machines** manage animation phases (`initial`, `animate`, `exit`) declaratively
- **`AnimatePresence`** wraps components requiring mount/unmount animations to enable exit transitions
- **Gesture props** (`whileHover`, `whileTap`) provide immediate interactive feedback without complex state logic
- **Staggered children** timing creates sequential reveal effects for lists and multi-element components
- The **"stop motion"** feature demonstrates dynamic variant switching to disable animations conditionally

## Frequently Asked Questions

### What version of Framer Motion does LunaTV use?

LunaTV specifies Framer Motion version **12.18.1** in its [`package.json`](https://github.com/MoonTechLab/LunaTV/blob/main/package.json) dependency manifest. This version provides the variant system, `AnimatePresence` component, and gesture handling utilized throughout the application's animation architecture.

### How does the multi-level selector handle list animations?

The selector uses `motion.ul` with `variants` defining `hidden` and `visible` states, wrapped in `AnimatePresence` for exit animations. It implements `staggerChildren: 0.05` in the parent variant to create sequential item reveals, while individual `motion.li` elements use `whileHover` for interactive scaling effects.

### What is the "stop motion" feature in LunaTV?

The "stop motion" option (定格动画) allows users to disable fluid animations, switching components to static state changes instead. Implemented in the multi-level selector, this feature conditionally selects between `moving` and `still` variants based on user preference, effectively setting `animate={stop ? 'still' : 'moving'}` on motion components.

### Where is the main animation logic located in the repository?

The primary animation implementation resides in [`src/components/MultiLevelSelector.tsx`](https://github.com/MoonTechLab/LunaTV/blob/main/src/components/MultiLevelSelector.tsx), which demonstrates Framer Motion patterns including variant definitions, `AnimatePresence` usage, and gesture props. Additional components throughout the repository follow this pattern by importing `{ motion }` from `framer-motion` and applying similar wrapper-based animation strategies.