# Smooth Animation (Interactive Animations)

> Adds GSAP / ScrollTrigger / SplitText–driven interactive animations to any widget or container. Includes text-scroll animation (split-by-character reveal) plus event-driven animation hooks.

**Class file:** `includes/Extensions/Smooth_Animation.php` (1,748 lines)
**Slug:** `smooth-animation` (`config.php` `extensions` key)
**Public docs:** <https://essential-addons.com/elementor/docs/smooth-animation/> (verify URL)
**Pro-shared:** ✅ Pro-only (Lite has Promotion teaser as "Interactive Animations")

## Overview

Adds an "Interactive Animations" panel under widget and Container advanced tabs. Major sub-features:

- **Text Scroll Animation** — split text by character/word; animate reveal on scroll
- **Event-driven animations** — animation type selector ties to a GSAP timeline (configurable trigger, duration, easing, scrub)

Pro injects animation classes and data attributes during `before_render`, then `smooth-animation.min.js` reads them and creates GSAP timelines per element.

## Features

- **Text Scroll Animation** — character-by-character reveal driven by scroll position
- **Animation type selector** — multiple GSAP-backed animation presets
- **Trigger configuration** — when animation starts (scroll position, viewport intersection)
- **Duration / easing / scrub** — full GSAP timeline knobs

## Pro vs Lite

| Capability | Lite | Pro |
| --- | --- | --- |
| Panel visible in editor | Teaser only | ✅ |
| GSAP-backed animations | ❌ | ✅ |
| SplitText character-reveal | ❌ | ✅ |

## File Map

| File | Role |
| --- | --- |
| `includes/Extensions/Smooth_Animation.php` | Class — controls + `before_render` injection |
| `src/js/view/smooth-animation.js` → `assets/front-end/js/view/smooth-animation.min.js` | Frontend init |
| `assets/front-end/js/lib-view/gsap/gsap.min.js` | GSAP core |
| `assets/front-end/js/lib-view/gsap/ScrollTrigger.min.js` | Scroll-driven animations |
| `assets/front-end/js/lib-view/gsap/SplitText.min.js` | Character/word splitting |

## Architecture

Constructor wires 3 hooks (`Smooth_Animation.php:12-14`):

```php
add_action( 'elementor/element/common/_section_style/after_section_end',    [ $this, 'register_controls' ] );
add_action( 'elementor/element/container/section_layout/after_section_end', [ $this, 'register_controls' ] );
add_action( 'elementor/frontend/before_render',                              [ $this, 'before_render' ], 100, 1 );
```

**Applies to:** widgets (common) and containers. **Does NOT apply** to legacy sections or columns. Verify whether this is intentional — most other Pro extensions cover all 4 element types.

`before_render` at priority 100 — runs after most other render-time filters.

## Controls Reference (high-value)

| Control id | Purpose |
| --- | --- |
| `eael_smooth_animation_section_controls` | Section header |
| `eael_smooth_animation_section` | Master switch (`'Enable Interactive Animations'`) |
| Text-scroll animation controls | Sub-section via `$this->eael_text_scroll_animation( $element )` |
| `eael_smooth_animation_event_function` | Animation type select |
| Trigger, duration, easing, scrub | Full GSAP timeline configuration |

## Behavior Flow

1. **Editor:** user enables Interactive Animations on a widget/container. Picks animation type, configures.
2. **Save:** settings persist.
3. **Frontend `before_render` (priority 100):** Pro reads settings, appends animation class names + data attributes to the rendered element.
4. **Frontend JS init (`smooth-animation.min.js`):** scans for elements with animation data attributes. For each, creates a GSAP timeline (`gsap.timeline()`), configures ScrollTrigger if scroll-bound, plays.

## Hooks & Filters

### Elementor hooks consumed

| Hook | Method |
| --- | --- |
| `elementor/element/{common,container}/.../after_section_end` | `register_controls` (only 2 element types, not 4) |
| `elementor/frontend/before_render` (priority 100) | `before_render` |

### Pro / EA hooks emitted

None directly.

## Asset Dependencies

| Asset | Type | Notes |
| --- | --- | --- |
| `gsap.min.js` | `lib`, `view` | GSAP core (~70KB) |
| `ScrollTrigger.min.js` | `lib`, `view` | Scroll plugin |
| `SplitText.min.js` | `lib`, `view` | Text splitter |
| `smooth-animation.min.js` | `self`, `view` | EA glue code |

**No `self` CSS dep** — animation styles applied via JS inline or piggyback on widget's own CSS. Verify in code.

## Behavior Quirks

- **Applies to widgets and containers only** — not legacy sections / columns. Users with old layouts may not see the panel.
- **GSAP SplitText** is a paid premium GSAP plugin in normal distribution. Pro ships its own copy (verify license / version).
- **No `prefers-reduced-motion` honour** — accessibility regression
- **Animation timeline cleanup on element re-render** is implicit — GSAP creates new timelines but may not dispose old ones. Memory leak risk for SPA-heavy sites.
- **Editor preview** may run animations on every control change — pre-empt via `isEditMode` debounce in the JS

## Known Limitations / Gaps

1. **Element coverage** — section / column missing
2. **SplitText distribution / license** — confirm Pro can legally ship the file
3. **No `prefers-reduced-motion`** — a11y issue, shared with parallax / particles / cursor
4. **1,748 lines is large for an extension** — split per animation-type into strategy classes
5. **No documented animation-type allowlist** — `switch` cases in JS are the de-facto allowlist
6. **GSAP + ScrollTrigger + SplitText = ~150 KB** loaded together — heavy

## Code Pointers

- Constructor: `Smooth_Animation.php:11-15`
- Controls: `register_controls()` at `:17+`
- Text-scroll sub-section: `eael_text_scroll_animation()` method
- `before_render`: search for `public function before_render`

## Cross-References

- Architecture: [`docs/architecture/asset-loading.md`](../architecture/asset-loading.md) — GSAP shared with Custom_Cursor + Parallax
- Shared patterns: [`_patterns.md`](_patterns.md)
