# @thecoderzeus/scroll-reveal-fx

[![NPM Version](https://img.shields.io/npm/v/@thecoderzeus/scroll-reveal-fx.svg)](https://www.npmjs.com/package/@thecoderzeus/scroll-reveal-fx)
[![License](https://img.shields.io/npm/l/@thecoderzeus/scroll-reveal-fx.svg)](https://github.com/thecoderzeus/scroll-reveal-fx/blob/main/LICENSE)

Suite de animações para scroll e mouse, sem dependências, focada em performance e API direta.

## O que mudou na v1.2.0

- Correção de gatilhos (`trigger`) no `revealOnScroll` para funcionar com múltiplos elementos.
- Correção de efeitos que falhavam em sequência (`wave`, `cascade`, `colorPulse`, `typewriter`, `magnetism`).
- Hardening de segurança/estabilidade com validação de seletor, cor CSS e valores numéricos.
- Todas as funções agora retornam controller com `destroy()` para limpar listeners/observers.
- Novos efeitos: `applyElasticReveal` e `applyGlowReveal`.
- Documentação reorganizada e simplificada.

## Instalação

```bash
npm install @thecoderzeus/scroll-reveal-fx
```

## Uso rápido

```js
import { revealOnScroll, applyElasticReveal } from '@thecoderzeus/scroll-reveal-fx';

revealOnScroll({
  selector: '.feature-card',
  effect: 'slide',
  direction: 'up',
  stagger: 120
});

applyElasticReveal({
  selector: '.hero-title',
  duration: 900
});
```

## Exportações

```js
import {
  revealOnScroll,
  animateText,
  drawSVG,
  applyParallax,
  scrubAnimation,
  createTimeline,
  createScrollSpy,
  applyTilt,
  applyMagnetism,
  applyWaveReveal,
  applyFlip3D,
  applyColorPulse,
  applyZoomBlur,
  applySkewReveal,
  applyMaskWipe,
  applyCascadeReveal,
  applyElasticReveal,
  applyGlowReveal
} from '@thecoderzeus/scroll-reveal-fx';
```

## API principal

### revealOnScroll(options)

Efeitos disponíveis em `effect`:

- `fade`
- `slide`
- `scale`
- `blur`
- `flip`
- `rotate`
- `roll`
- `flicker`
- `pop`
- `swing`
- `custom`

Opções:

| Opção | Tipo | Padrão |
| :--- | :--- | :--- |
| `selector` | `string` | `'.reveal'` |
| `trigger` | `string \| HTMLElement` | `null` |
| `effect` | `string` | `'fade'` |
| `direction` | `'up' \| 'down' \| 'left' \| 'right'` | `'up'` |
| `threshold` | `number` | `0.25` |
| `duration` | `number` | `800` |
| `delay` | `number` | `0` |
| `stagger` | `number` | `150` |
| `easing` | `string` | `'cubic-bezier(0.5, 0, 0, 1)'` |
| `once` | `boolean` | `true` |
| `reset` | `boolean` | `false` |
| `onReveal` | `(el: HTMLElement) => void` | `null` |
| `onComplete` | `(el: HTMLElement) => void` | `null` |
| `onReset` | `(el: HTMLElement) => void` | `null` |
| `customClassName` | `string` | `'is-visible'` |
| `indexAttribute` | `string \| null` | `null` |

Retorno:

```js
const controller = revealOnScroll({ selector: '.card' });
controller.destroy();
```

### animateText(options)

- Divide por `chars` ou `words`
- Suporta `randomOrder`
- Suporta modo especial `typewriter`

```js
animateText({
  selector: '.headline',
  splitType: 'chars',
  effect: 'pop',
  randomOrder: true,
  stagger: 25
});
```

```js
animateText({
  selector: '.terminal-line',
  effect: 'typewriter',
  typewriterSpeed: 32,
  once: false
});
```

### drawSVG(options)

```js
drawSVG({
  selector: '#logo',
  duration: 2200,
  stagger: 180,
  once: true
});
```

### applyParallax(options)

```js
applyParallax({
  selector: '.parallax-layer',
  intensity: 0.25,
  threshold: 120
});
```

### scrubAnimation(options)

```js
scrubAnimation({
  trigger: '#track',
  target: '.cube',
  from: { rotate: 0, scale: 0.7, opacity: 0.2 },
  to: { rotate: 180, scale: 1, opacity: 1 },
  startOffset: 100,
  endOffset: -50
});
```

### createTimeline(options)

```js
const tl = createTimeline({ trigger: '#hero', once: true });

tl
  .add({ selector: '.hero-title', effect: 'slide', direction: 'up' })
  .add({ selector: '.hero-subtitle', effect: 'fade', delay: 120 })
  .add({ selector: '.hero-cta', effect: 'pop', delay: 80 });
```

### createScrollSpy(options)

```js
createScrollSpy({
  links: '.nav-link',
  sections: '.content-section',
  activeClassName: 'is-active',
  rootMargin: '-45% 0px -45% 0px'
});
```

## Efeitos de elemento

Todos os efeitos abaixo seguem o mesmo padrão:

- `selector`
- `duration`
- `easing`
- `once`
- `reset`
- `threshold`

### applyWaveReveal

```js
applyWaveReveal({ selector: '.wave-item', stagger: 90 });
```

### applyFlip3D

```js
applyFlip3D({ selector: '.flip-card' });
```

### applyColorPulse

```js
applyColorPulse({ selector: '.pulse-box', pulseColor: '#14d9a6', once: false, reset: true });
```

### applyZoomBlur

```js
applyZoomBlur({ selector: '.zoom-item', blur: 6, scale: 0.84 });
```

### applySkewReveal

```js
applySkewReveal({ selector: '.skew-item', axis: 'x', angle: 8, distance: 24 });
```

### applyMaskWipe

```js
applyMaskWipe({ selector: '.wipe-item', direction: 'left' });
```

### applyCascadeReveal

```js
applyCascadeReveal({
  selector: '.list',
  childSelector: '.list-item',
  stagger: 110
});
```

### applyElasticReveal (novo)

```js
applyElasticReveal({
  selector: '.elastic-block',
  distance: 30,
  duration: 900
});
```

### applyGlowReveal (novo)

```js
applyGlowReveal({
  selector: '.neon-title',
  glowColor: 'rgba(80, 220, 255, 0.7)',
  glowSize: 28
});
```

## Efeitos de mouse

### applyTilt

```js
applyTilt({ selector: '.tilt-card', intensity: 14, perspective: 1200 });
```

### applyMagnetism

```js
applyMagnetism({ selector: '.magnetic-btn', intensity: 0.25, threshold: 120, scale: 1.08 });
```

## Segurança e robustez

- Seletores inválidos não quebram mais a execução da biblioteca.
- Valores numéricos críticos agora são normalizados e limitados.
- Cores customizadas passam por validação (`CSS.supports`) quando disponível.
- Typewriter usa `textContent` para evitar parsing HTML acidental.
- Cada módulo expõe `destroy()` para limpeza de observers/listeners.

## Contribuição

PRs e issues são bem-vindos.

1. Faça fork do projeto.
2. Crie uma branch (`feat/nome` ou `fix/nome`).
3. Adicione testes/exemplo de uso quando possível.
4. Abra PR com contexto objetivo do problema e solução.

## Licença

[MIT](https://github.com/TheCoderZeus/scroll-reveal-fx/blob/main/LICENSE)
