AgentSkillsCN

Matrix Effects

矩阵效果

SKILL.md
skill
---
name: matrix-effects
description: Matrix-themed visual effects including digital rain, glitch effects, terminal animations, and cyberpunk aesthetics. Apply when creating Matrix-inspired UI components, implementing digital rain backgrounds, adding glitch animations, or building terminal/hacker-style interfaces.
license: MIT
metadata:
  author: all-the-vibes
  version: "1.0.0"
---

# Matrix Effects Skill

Comprehensive guide for implementing Matrix-themed visual effects in React/Next.js applications. Includes patterns for digital rain, glitch effects, terminal animations, and cyberpunk UI elements optimized for performance.

## When to Apply

Reference these guidelines when:
- Implementing digital rain / matrix rain backgrounds
- Adding glitch or distortion effects to text/images
- Creating terminal/hacker-style UI elements
- Building cyberpunk-themed interfaces
- Adding scan line or CRT monitor effects
- Implementing typewriter/code typing animations

## Core Effect Categories

| Category | Impact | Primary Use |
|----------|--------|-------------|
| Digital Rain | HIGH | Background atmosphere |
| Glitch Effects | MEDIUM | Text/image emphasis |
| Terminal UI | HIGH | Interactive elements |
| Scan Lines | LOW | Atmospheric overlay |
| Data Stream | MEDIUM | Decorative elements |

## Quick Reference

### 1. Digital Rain (Canvas-Based)

#### Performance Rules
- `rain-canvas-offscreen` - Use OffscreenCanvas for heavy animations
- `rain-requestAnimationFrame` - Never use setInterval for animations
- `rain-column-pooling` - Reuse column objects instead of creating new ones
- `rain-character-cache` - Pre-render character sprites to avoid text rendering

#### Implementation Pattern

```tsx
// High-performance matrix rain with column pooling
const MatrixRain = () => {
  const canvasRef = useRef<HTMLCanvasElement>(null)
  
  useEffect(() => {
    const canvas = canvasRef.current
    if (!canvas) return
    
    const ctx = canvas.getContext('2d')
    if (!ctx) return
    
    // Use device pixel ratio for sharp rendering
    const dpr = window.devicePixelRatio || 1
    canvas.width = window.innerWidth * dpr
    canvas.height = window.innerHeight * dpr
    ctx.scale(dpr, dpr)
    
    const fontSize = 16
    const columns = Math.floor(window.innerWidth / fontSize)
    
    // Column pool - reuse objects
    const drops: number[] = Array(columns).fill(1)
    const speeds: number[] = Array.from({ length: columns }, () => Math.random() * 0.5 + 0.5)
    
    // Character set - Matrix-style
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン0123456789'
    
    let animationId: number
    
    const draw = () => {
      // Fade effect - creates trail
      ctx.fillStyle = 'rgba(0, 0, 0, 0.05)'
      ctx.fillRect(0, 0, window.innerWidth, window.innerHeight)
      
      ctx.fillStyle = '#0f0'
      ctx.font = `${fontSize}px monospace`
      
      for (let i = 0; i < drops.length; i++) {
        const char = chars[Math.floor(Math.random() * chars.length)]
        const x = i * fontSize
        const y = drops[i] * fontSize
        
        // Head character brighter
        ctx.fillStyle = '#fff'
        ctx.fillText(char, x, y)
        
        // Trail characters
        ctx.fillStyle = '#0f0'
        ctx.fillText(chars[Math.floor(Math.random() * chars.length)], x, y - fontSize)
        
        if (y > window.innerHeight && Math.random() > 0.975) {
          drops[i] = 0
        }
        drops[i] += speeds[i]
      }
      
      animationId = requestAnimationFrame(draw)
    }
    
    draw()
    return () => cancelAnimationFrame(animationId)
  }, [])
  
  return <canvas ref={canvasRef} className="fixed inset-0 z-0" />
}
```

### 2. Glitch Effects (CSS-Based)

#### Effect Types
- `glitch-text` - Text distortion with clip-path animation
- `glitch-image` - Image channel separation
- `glitch-screen` - Full screen flicker effect
- `glitch-hover` - Trigger on interaction

#### Text Glitch Pattern

```css
/* Performant glitch using CSS only */
@keyframes glitch {
  0% {
    clip-path: inset(40% 0 61% 0);
    transform: translate(-2px, 2px);
  }
  20% {
    clip-path: inset(92% 0 1% 0);
    transform: translate(1px, -1px);
  }
  40% {
    clip-path: inset(43% 0 1% 0);
    transform: translate(-1px, 1px);
  }
  60% {
    clip-path: inset(25% 0 58% 0);
    transform: translate(2px, -2px);
  }
  80% {
    clip-path: inset(54% 0 7% 0);
    transform: translate(-2px, 2px);
  }
  100% {
    clip-path: inset(58% 0 43% 0);
    transform: translate(1px, -1px);
  }
}

.glitch-text {
  position: relative;
}

.glitch-text::before,
.glitch-text::after {
  content: attr(data-text);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.glitch-text::before {
  left: 2px;
  text-shadow: -2px 0 #ff00ff;
  animation: glitch 0.3s infinite linear alternate-reverse;
}

.glitch-text::after {
  left: -2px;
  text-shadow: 2px 0 #00ffff;
  animation: glitch 0.3s infinite linear alternate-reverse;
  animation-delay: 0.1s;
}
```

#### React Component

```tsx
const GlitchText = ({ children, className = '' }: { children: string; className?: string }) => (
  <span className={`glitch-text ${className}`} data-text={children}>
    {children}
  </span>
)
```

### 3. Terminal UI Patterns

#### Typing Animation

```tsx
const TypewriterText = ({ text, speed = 50 }: { text: string; speed?: number }) => {
  const [displayedText, setDisplayedText] = useState('')
  const [cursorVisible, setCursorVisible] = useState(true)
  
  useEffect(() => {
    let index = 0
    const timer = setInterval(() => {
      if (index < text.length) {
        setDisplayedText(text.slice(0, index + 1))
        index++
      } else {
        clearInterval(timer)
      }
    }, speed)
    
    return () => clearInterval(timer)
  }, [text, speed])
  
  // Cursor blink
  useEffect(() => {
    const cursor = setInterval(() => setCursorVisible(v => !v), 500)
    return () => clearInterval(cursor)
  }, [])
  
  return (
    <span className="font-mono text-green-400">
      {displayedText}
      <span className={cursorVisible ? 'opacity-100' : 'opacity-0'}>█</span>
    </span>
  )
}
```

#### Terminal Container

```tsx
const TerminalWindow = ({ children }: { children: React.ReactNode }) => (
  <div className="bg-black/80 border border-green-500/30 rounded-lg overflow-hidden backdrop-blur-sm">
    {/* Title bar */}
    <div className="flex items-center gap-2 px-4 py-2 bg-green-500/10 border-b border-green-500/20">
      <div className="w-3 h-3 rounded-full bg-red-500" />
      <div className="w-3 h-3 rounded-full bg-yellow-500" />
      <div className="w-3 h-3 rounded-full bg-green-500" />
      <span className="ml-2 text-green-400 text-sm font-mono">terminal</span>
    </div>
    {/* Content */}
    <div className="p-4 font-mono text-green-400 text-sm">
      {children}
    </div>
  </div>
)
```

### 4. Scan Line Overlay

```css
.scanlines {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 100;
  background: repeating-linear-gradient(
    0deg,
    transparent,
    transparent 2px,
    rgba(0, 255, 255, 0.03) 2px,
    rgba(0, 255, 255, 0.03) 4px
  );
}

/* Animated scan line */
.scanline-moving {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 4px;
  background: linear-gradient(
    to bottom,
    transparent,
    rgba(0, 255, 255, 0.3),
    transparent
  );
  animation: scanline 6s linear infinite;
  pointer-events: none;
  z-index: 101;
}

@keyframes scanline {
  0% { top: 0; }
  100% { top: 100%; }
}
```

### 5. Data Stream Effect

```tsx
const DataStream = ({ text = '01', speed = 20 }: { text?: string; speed?: number }) => {
  const [stream, setStream] = useState<string[]>([])
  
  useEffect(() => {
    const chars = text.split('')
    const interval = setInterval(() => {
      setStream(prev => {
        const newStream = [...prev, chars[Math.floor(Math.random() * chars.length)]]
        if (newStream.length > 50) newStream.shift()
        return newStream
      })
    }, speed)
    
    return () => clearInterval(interval)
  }, [text, speed])
  
  return (
    <div className="font-mono text-cyan-400/50 text-xs whitespace-nowrap overflow-hidden">
      {stream.join('')}
    </div>
  )
}
```

## Color Palette

| Color | Hex | Usage |
|-------|-----|-------|
| Matrix Green | `#00ff00` | Primary text, highlights |
| Cyan Glow | `#00ffff` | Accents, UI elements |
| Deep Black | `#050010` | Backgrounds |
| Purple Accent | `#a855f7` | Secondary elements |
| Warning Red | `#ff0000` | Alerts, glitch effects |
| Digital Blue | `#0066ff` | Links, interactive |

## Performance Guidelines

1. **Canvas animations**: Use `requestAnimationFrame`, never `setInterval`
2. **CSS over JS**: Prefer CSS animations for simple effects
3. **GPU acceleration**: Use `transform` and `opacity` for animations
4. **Lazy loading**: Dynamic import heavy effect components
5. **Visibility API**: Pause animations when tab is hidden
6. **Memory management**: Clean up intervals/RAF in useEffect cleanup

## Anti-Patterns

- ❌ Using `setInterval` for animations (causes jank)
- ❌ Animating `width`, `height`, `top`, `left` (triggers reflow)
- ❌ Creating new objects in animation loops
- ❌ Text rendering in canvas on every frame without caching
- ❌ Not cleaning up animation frames on unmount

## Full Implementation Guide

See `AGENTS.md` for complete implementation examples and advanced patterns.