# How to Implement Magnetic Micro-Physics with Motion useMotionValue in Taste-Skill

> Learn to implement magnetic micro-physics using useMotionValue in Taste-Skill. Gain smooth cursor-following animations by avoiding useState and leveraging useSpring and useTransform.

- Repository: [Leon Lin/taste-skill](https://github.com/Leonxlnx/taste-skill)
- Tags: how-to-guide
- Published: 2026-06-01

---

**Use `useMotionValue` combined with `useSpring` and `useTransform` to drive cursor-following animations outside React's render cycle, strictly avoiding `useState` for continuous pointer tracking.**

The Taste-Skill repository by Leonxlnx leverages **Motion** (the modern `motion/react` entry point for Framer Motion) as its exclusive animation engine for UI micro-interactions. When building magnetic effects—interface elements that subtly pull toward the cursor—the codebase mandates a specific architectural pattern centered on **magnetic micro-physics with Motion useMotionValue** to ensure GPU-accelerated performance without layout thrashing.

## Why useMotionValue Beats useState for Magnetic Effects

According to [`skills/taste-skill/SKILL.md`](https://github.com/Leonxlnx/taste-skill/blob/main/skills/taste-skill/SKILL.md) lines 357-363, the repository explicitly bans React `useState` for any continuously-changing input such as mouse position or pointer physics. The performance difference is stark:

| Concern | `useState` | `useMotionValue` |
|---------|-----------|------------------|
| Re-render on every frame | Causes full React tree render | Updates only the animated element |
| Mobile performance | Poor (jank) | Excellent (GPU-accelerated) |
| Cleanup / lifecycle | Manual | Automatic when component unmounts |

Motion values live outside React's render cycle, writing directly to the DOM via refs rather than triggering state updates. This prevents layout thrashing and maintains 60fps even on constrained devices.

## The Taste-Skill Architecture for Magnetic Micro-Physics

The canonical implementation appears in two key files:

- **[`skills/taste-skill/SKILL.md`](https://github.com/Leonxlnx/taste-skill/blob/main/skills/taste-skill/SKILL.md)** (lines 357-363): "Implement EXCLUSIVELY with Motion's `useMotionValue` / `useTransform` outside the React render cycle. Never `useState`."
- **[`skills/taste-skill-v1/SKILL.md`](https://github.com/Leonxlnx/taste-skill/blob/main/skills/taste-skill-v1/SKILL.md)** (lines 69-71): Earlier version specifying the same requirement for buttons that pull toward the mouse cursor.

This architecture satisfies the repository's "Motion claimed = motion shown" rule for `MOTION_INTENSITY > 4`, ensuring that any advertised animation actually runs via Motion's optimized engine.

### Motion Values Outside the Render Cycle

The critical distinction is that **`useMotionValue`** creates mutable state that Motion manages internally. When you call `motionValue.set(newValue)`, Motion updates the DOM node directly without notifying React, bypassing the virtual DOM diffing entirely.

### The "Never useState" Rule

The [`SKILL.md`](https://github.com/Leonxlnx/taste-skill/blob/main/SKILL.md) files explicitly warn against using `useState` for cursor tracking. Setting React state on every `mousemove` event forces a component re-render on every frame, destroying performance for micro-interactions.

## Step-by-Step Implementation

Follow these architectural steps derived from the Taste-Skill source code:

### 1. Isolate the Client Component

Create a client-only leaf component to prevent server-side rendering conflicts with window-dependent logic.

```tsx
'use client';

import { motion, useMotionValue, useSpring, useTransform, useReducedMotion } from 'motion/react';

```

### 2. Instantiate Motion Values and Springs

Initialize raw motion values for cursor deltas, then pipe them through springs for physical smoothing.

```tsx
const mouseX = useMotionValue(0);
const mouseY = useMotionValue(0);

const springX = useSpring(mouseX, { stiffness: 400, damping: 30 });
const springY = useSpring(mouseY, { stiffness: 400, damping: 30 });

```

### 3. Calculate Magnetic Offset with useTransform

Map the spring values to limited translation ranges to create the "magnetic" pull effect.

```tsx
const translateX = useTransform(springX, [-100, 100], [-15, 15]);
const translateY = useTransform(springY, [-100, 100], [-15, 15]);

```

### 4. Attach Cursor Listeners (Direct Writes)

Update motion values directly in event handlers—no `setState` calls allowed.

```tsx
const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
  const rect = e.currentTarget.getBoundingClientRect();
  const offsetX = e.clientX - (rect.left + rect.width / 2);
  const offsetY = e.clientY - (rect.top + rect.height / 2);
  mouseX.set(offsetX);
  mouseY.set(offsetY);
}, [mouseX, mouseY]);

const handleMouseLeave = useCallback(() => {
  mouseX.set(0);
  mouseY.set(0);
}, [mouseX, mouseY]);

```

### 5. Respect Reduced Motion Preferences

Wrap logic with `useReducedMotion()` to provide static fallbacks for accessibility, as referenced in [`SKILL.md`](https://github.com/Leonxlnx/taste-skill/blob/main/SKILL.md) lines 372-384.

```tsx
const reduce = useReducedMotion();

if (reduce) {
  return <button className="static-button">{children}</button>;
}

```

## Complete Code Example

Here is the production-ready pattern implemented in [`skills/taste-skill/SKILL.md`](https://github.com/Leonxlnx/taste-skill/blob/main/skills/taste-skill/SKILL.md):

```tsx
'use client';

import { motion, useMotionValue, useSpring, useTransform, useReducedMotion } from 'motion/react';
import { useCallback } from 'react';

export const MagneticButton = ({ children }: { children: React.ReactNode }) => {
  const reduce = useReducedMotion();

  // Motion values live outside React's render cycle
  const mouseX = useMotionValue(0);
  const mouseY = useMotionValue(0);

  // Spring physics for smooth easing
  const springX = useSpring(mouseX, { stiffness: 400, damping: 30 });
  const springY = useSpring(mouseY, { stiffness: 400, damping: 30 });

  // Map pointer delta to limited translate range (±15px)
  const translateX = useTransform(springX, [-100, 100], [-15, 15]);
  const translateY = useTransform(springY, [-100, 100], [-15, 15]);

  // Update motion values directly—no state updates
  const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
    const rect = e.currentTarget.getBoundingClientRect();
    const offsetX = e.clientX - (rect.left + rect.width / 2);
    const offsetY = e.clientY - (rect.top + rect.height / 2);
    mouseX.set(offsetX);
    mouseY.set(offsetY);
  }, [mouseX, mouseY]);

  const handleMouseLeave = useCallback(() => {
    mouseX.set(0);
    mouseY.set(0);
  }, [mouseX, mouseY]);

  // Accessibility fallback
  if (reduce) {
    return <button className="static-button">{children}</button>;
  }

  return (
    <motion.button
      onMouseMove={handleMouseMove}
      onMouseLeave={handleMouseLeave}
      style={{
        translateX,
        translateY,
        scale: useTransform(springX, [-100, 0, 100], [1.02, 1, 1.02]),
      }}
      className="magnetic-button"
    >
      {children}
    </motion.button>
  );
};

```

## Key Source Files and References

- **[`skills/taste-skill/SKILL.md`](https://github.com/Leonxlnx/taste-skill/blob/main/skills/taste-skill/SKILL.md)** (lines 357-363): Defines the exclusive use of `useMotionValue` and the prohibition against `useState` for pointer physics.
- **[`skills/taste-skill-v1/SKILL.md`](https://github.com/Leonxlnx/taste-skill/blob/main/skills/taste-skill-v1/SKILL.md)** (lines 69-71): Original specification for magnetic hover implementations on buttons.
- **[`CHANGELOG.md`](https://github.com/Leonxlnx/taste-skill/blob/main/CHANGELOG.md)** (lines 69-75): Documents the repository-wide migration to `motion/react` and the "Motion claimed = motion shown" principle.

## Summary

- **Never use `useState`** for cursor position or continuous physics; use `useMotionValue` to avoid React re-renders on every frame.
- **Compose with `useSpring`** and **`useTransform`** to create smooth, physics-based magnetic pulls that map cursor distance to translation offsets.
- **Isolate animation logic** in `'use client'` components to prevent server-side rendering issues.
- **Respect accessibility** by checking `useReducedMotion()` and providing static fallbacks.
- **Cleanup is automatic**—`useMotionValue` handles unmounting, though manual DOM listeners should be cleaned in `useEffect` returns.

## Frequently Asked Questions

### Why does Taste-Skill ban useState for magnetic effects?

React `useState` triggers a full component re-render on every update. When tracking mouse movement, this creates 60 re-renders per second, causing layout thrashing and jank. `useMotionValue` updates the DOM directly without React's reconciliation cycle, maintaining GPU-accelerated 60fps performance as required by [`skills/taste-skill/SKILL.md`](https://github.com/Leonxlnx/taste-skill/blob/main/skills/taste-skill/SKILL.md) lines 357-363.

### How do I adjust the magnetic pull strength?

Modify the `stiffness` and `damping` parameters in `useSpring`. Higher stiffness (e.g., 500) creates a tighter, snappier pull toward the cursor, while lower damping (e.g., 15) increases the oscillation and "bouncy" feel. Map smaller input ranges in `useTransform` (e.g., `[-50, 50]` instead of `[-100, 100]`) to limit the maximum translation distance.

### Does this pattern work with server components in Next.js?

No—motion values require browser APIs like `window` and `document`. You must mark components using `useMotionValue` with `'use client'` at the top of the file. The Taste-Skill architecture specifically mandates isolating these as client-only leaf components to keep the server bundle free of animation logic.

### How do I handle reduced motion preferences correctly?

Import `useReducedMotion` from `motion/react` and call it at the top of your component. If it returns `true`, return a static element without motion values. This pattern appears in [`skills/taste-skill/SKILL.md`](https://github.com/Leonxlnx/taste-skill/blob/main/skills/taste-skill/SKILL.md) lines 372-384 and ensures compliance with accessibility standards while keeping the code path simple for users who prefer reduced motion.