# Section Particles

> Adds particles.js animated backgrounds to Elementor Sections and Containers — 5 preset themes (default, nasa, bubble, snow, nyan_cat) plus a custom JSON theme option. Particles render as a `<canvas>` overlay positioned absolutely behind content.

**Class file:** `includes/Extensions/EAEL_Particle_Section.php` (239 lines)
**Slug:** `section-particles` (`config.php` `extensions` key)
**Public docs:** <https://essential-addons.com/elementor/docs/particle-section/>
**Pro-shared:** ✅ Pro-only (Lite has Promotion teaser)

## Overview

Adds a "Particles" panel under Section's Layout tab and Container's Layout tab. User enables particles, picks a preset theme (or pastes custom particles.js JSON), tweaks opacity / speed / mobile-disable.

Implementation is JS-driven — Pro emits data attributes during `before_render` (NOT after_render, as preview-mode data needs to be in DOM before particles.js scans), then `section-particles.min.js` reads them and calls `particlesJS(id, themes)`.

## Features

- **5 preset themes:** default, nasa, bubble, snow, nyan_cat (NyanCat references an external image via http://wiki.lexisnexis.com — note this is a placeholder image and the URL is HTTP not HTTPS)
- **Custom particles.js JSON** — paste your own theme
- **Opacity / speed override** — quick tweaks without editing JSON
- **Mobile disable** — toggle off on small screens
- **Z-index control** — particle layer's stack order
- **Container support** — works on both Sections and Containers

## Pro vs Lite

| Capability | Lite | Pro |
| --- | --- | --- |
| Panel visible in editor | Teaser only | ✅ |
| 5 preset themes | ❌ | ✅ |
| Custom JSON theme | ❌ | ✅ |
| Opacity/speed quick controls | ❌ | ✅ |

## File Map

| File | Role |
| --- | --- |
| `includes/Extensions/EAEL_Particle_Section.php` | Class — controls + `before_render`/`after_render` attribute injection |
| `includes/Extensions/particle-themes.php` | **Data file** — returns array of preset JSON theme strings. **Today not loaded** — `Enqueue.php` has a hardcoded duplicate |
| `src/css/view/section-particles.scss` → `assets/front-end/css/view/section-particles.min.css` | Canvas layer styling |
| `src/js/view/section-particles.js` → `assets/front-end/js/view/section-particles.min.js` | Frontend init |
| `assets/front-end/js/lib-view/particles/particles.min.js` | particles.js library |
| `includes/Traits/Enqueue.php` `script_localizer()` | Localizes `ParticleThemesData` (5 preset JSONs) onto every page |

## Architecture

Constructor wires 7 hooks (`EAEL_Particle_Section.php:15-23`):

```php
// Section
add_action( 'elementor/frontend/section/before_render',                       [ $this, 'before_render' ] );
add_action( 'elementor/element/section/section_layout/after_section_end',     [ $this, 'register_controls' ], 10 );
add_action( 'elementor/element/container/section_layout/after_section_end',   [ $this, 'register_controls' ], 10 );
add_action( 'elementor/frontend/section/after_render',                        [ $this, 'after_render' ] );

// Container
add_action( 'elementor/frontend/container/before_render',                     [ $this, 'before_render' ] );
add_action( 'elementor/element/container/section_layout/after_section_end',   [ $this, 'register_controls' ], 10 );
add_action( 'elementor/frontend/container/after_render',                      [ $this, 'after_render' ] );
```

(Note: `container/section_layout/after_section_end` is registered twice — once in each block. Verify intent; likely a duplicate.)

## Controls Reference

| Control id | Purpose |
| --- | --- |
| `eael_particle_switch` | Master switch |
| `eael_particle_theme_from` | `'presets' \| 'custom'` |
| `eael_particle_preset_themes` | Select among 5 presets (when `from = presets`) |
| `eael_particles_custom_style` | Raw JSON textarea (when `from = custom`) |
| `eael_particle_opacity` | Override preset opacity |
| `eael_particle_speed` | Override preset particle speed |
| `eael_particle_area_zindex` | z-index of the canvas overlay |
| `eael-particle-mobile-disabled` | Mobile disable toggle |

## Behavior Flow

1. **Editor:** user enables particles on a section. Picks preset or pastes JSON.
2. **Save:** settings persist.
3. **Frontend `before_render`:** Pro emits the particles `<canvas>` placeholder + data attributes (`data-id`, `data-particle_enable`, `data-preset_theme`, `data-custom_style`, `data-particle_opacity`, `data-particle_speed`, `data-eael_ptheme_source`).
4. **Frontend `after_render`:** closes wrapping HTML.
5. **Frontend JS init (`section-particles.min.js`):** scans for `.eael-section-particles-{id}` containers, reads preset theme from `localize.ParticleThemesData[<preset-name>]`, applies opacity / speed overrides, calls `particlesJS(id, themes)`.

## ParticleThemesData localizer

The 5 preset JSON strings are localized onto every page where Pro is active, via `Enqueue::script_localizer`:

```php
$object['ParticleThemesData'] = [
    'default'  => '{"particles":...}',  // ~3 KB
    'nasa'     => '...',
    'bubble'   => '...',
    'snow'     => '...',
    'nyan_cat' => '...',
];
```

**Size impact:** ~6 KB per page, regardless of whether particles are actually on the page. See [`docs/architecture/asset-loading.md`](../architecture/asset-loading.md) § "What's missing" #2.

**Duplication:** the same JSON exists in `includes/Extensions/particle-themes.php` but that file is NOT loaded today — `Enqueue.php` has a hardcoded copy. The PHP file is dead code until wired.

## Hooks & Filters

### Elementor hooks consumed

| Hook | Method |
| --- | --- |
| `elementor/frontend/{section,container}/before_render` | `before_render` |
| `elementor/element/{section,container}/section_layout/after_section_end` | `register_controls` |
| `elementor/frontend/{section,container}/after_render` | `after_render` |

### Pro / EA hooks emitted

None directly. Indirect: contributes `ParticleThemesData` to the global localizer.

## Behavior Quirks

- **NyanCat preset references an external image** at `http://wiki.lexisnexis.com/academic/images/f/fb/Itunes_podcast_icon_300.jpg`. HTTP, third-party image. Privacy footprint per page-view if NyanCat is used.
- **`particle-themes.php` is dead code** — never loaded; duplicate JSON in `Enqueue.php`
- **`ParticleThemesData` localizer is unconditional** — ships on every page even when particles aren't used
- **`isEditMode` branch in JS** — editor preview uses different logic than frontend (Elementor model traversal vs DOM data attributes)
- **Duplicate hook registration** — `container/section_layout/after_section_end` registered twice; verify intent

## Known Limitations / Gaps

1. NyanCat preset's external image dependency (HTTP, third-party) is a privacy + availability footprint
2. `ParticleThemesData` ships unconditionally — flagged in `asset-loading.md` § What's missing
3. `particle-themes.php` is unused; either wire it up or delete it
4. No `prefers-reduced-motion` honour
5. particles.js library is unmaintained upstream (last meaningful release ~2018)
6. Custom JSON has no validation — invalid input crashes particles.js silently
7. Duplicate `container/...` hook registration — code smell

## Code Pointers

- Constructor: `EAEL_Particle_Section.php:13-24`
- Controls: `:25-end of register_controls`
- `before_render` / `after_render`: bottom of file
- Localizer (data ships from): `includes/Traits/Enqueue.php:33-40`
- Unused data file: `includes/Extensions/particle-themes.php`

## Cross-References

- Architecture: [`docs/architecture/asset-loading.md`](../architecture/asset-loading.md) — ParticleThemesData duplication
- Shared patterns: [`_patterns.md`](_patterns.md)
