diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index d8c5c9caeba..dbd8e6a3731 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -104,6 +104,7 @@ jobs: - name: Deploy to Firebase (PR preview) if: env.firebaseToken != '' && github.event_name == 'pull_request' && github.actor == 'matteobruni' + continue-on-error: true uses: FirebaseExtended/action-hosting-deploy@v0 with: repoToken: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 381c7a2f5bd..7adb4c76eaf 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -1,28 +1,23 @@ -# ROADMAP: tsParticles (replaced) +# ROADMAP: tsParticles ## Overview -Single focused phase per owner's request. - -| # | Phase | Goal | -| --- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- | -| 1 | External Interaction: Drag & Drop Particle | Implement an external interaction allowing users to drag-and-drop particles one at a time into a canvas and interact with them. | +| # | Phase | Version | Goal | +|---|-------|---------|------| +| 1 | GIF Shape, Background Canvas, BgMask Dynamic, Draw Layer System, Particle Modifier, HDR Precision | 4.3.0 | ✅ Released | +| 2 | Fluid Particle Interaction (DDR-based liquid simulation) | 4.4.0 | In progress — see `.planning/handovers/4.4.0_PLAN.md` | ## Phase Details -### Phase 1: External Interaction: Drag & Drop Particle - -Goal: Provide an external interaction that lets a user drag and drop single particles into the canvas, interact with them (select, move, drop), and expose a minimal API for external consumers to trigger and listen to these interactions. - -Requirements: (derived from owner request) +### Phase 2: Fluid Particle Interaction (4.4.0) -- UI-01: Users can drag a particle from an external palette and drop it onto the canvas. Only one particle is dragged per interaction. -- UI-02: Dropped particle becomes interactive (can be selected and moved) until deselected. -- API-01: Emit events on drag-start, drag-end, drop, select, and move with particle identifiers and positions. -- QA-01: Add automated usability tests that simulate drag-and-drop and assert events fired. +**Target:** `@tsparticles/interaction-particles-fluid` -Success criteria: +New particles interactor implementing position-only DDR (Density Displacement Resolution) +for real-time liquid simulation. Single-pass Gauss-Seidel solver with symmetric displacement. -1. Functional demo shows drag-and-drop of one particle at a time into `demo/vanilla`. -2. Events are emitted and documented in a short API doc snippet. -3. Acceptance tests simulate a drag-and-drop and pass in CI. +**Constraints:** +- Zero modifications to `@tsparticles/engine` +- Follows `collisions` package pattern +- No per-particle state storage +- Relies on MovePlugin for baseline advection diff --git a/.planning/STATE.md b/.planning/STATE.md index 4f0b241823b..dc1393f2d6a 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -4,12 +4,26 @@ See: .planning/PROJECT.md (initialized) **Core value:** Provide a small, high-performance, and extensible particle engine that developers can integrate into web projects with minimal configuration. -**Current focus:** Phase 1 — Developer Experience & Docs +**Current focus:** Phase 2 — 4.4.0 Fluid Interaction -## Session Status — 2026-06-14 +## Session Status — 2026-06-27 -### Objective -Plan and implement wrapper reactivity (options/url/theme prop changes) across Vue 3, Vue 2, Angular, Solid, Qwik, and Astro wrappers, plus fix Vue 3 docs describing nonexistent `:init`/`@particles-init` features. +### 4.3.0 — Released ✅ + +All 6 features implemented and gate checks passed: +- A: GIF Shape — new `@tsparticles/shape-gif` package +- B: Background Canvas — layered background pipeline +- C: Background Mask Dynamic — `cover.element` + `cover.draw` +- D: Draw Layer System — 8 named layers replacing 11 arrays +- E: Particle Modifier System — generic `IParticleModifier` API +- F: HDR Precision — floating-point RGB pipeline + +Build: 461 projects ✅ | Tests: 152/152 ✅ | Issue aperti: nessun blocco. + +### 4.4.0 — Fluid Interaction (next) + +**Target:** `@tsparticles/interaction-particles-fluid` — DDR-based liquid simulation. +See `.planning/handovers/4.4.0_PLAN.md`. ### Outcome **S1 (Vue 3 wrapper) completed**: wrapper reactivity implemented (`id`/`options`/`url` → destroy+reload, `theme` → safe `loadTheme`), demo aligned with reactive config switching, README fully documented. Plan remaining steps on `.planning/handovers/WRAPPER_REACTIVITY_PLAN.md`. diff --git a/.planning/handovers/4.3.0_PLAN.md b/.planning/handovers/4.3.0_PLAN.md deleted file mode 100644 index 0bae76f1f8e..00000000000 --- a/.planning/handovers/4.3.0_PLAN.md +++ /dev/null @@ -1,369 +0,0 @@ -# tsParticles 4.3.0 — Master Coordination Plan - -## Overview - -This plan coordinates **3 independent features** targeting the `4.3.0` release. -Each feature has its own detailed handover plan. This document manages sequencing, dependencies, -conflict areas, and release readiness. - ---- - -## Hard Rule: Master Plan First, Feature Plans After - -All validation steps defined in **this** document (see "Step 0: Baseline Validation" below) **must be executed and passing before any feature-specific plan** (i.e. before `BACKGROUND_CANVAS_PLAN.md`, `FLUID_INTERACTION_PLAN.md`, `GIF_SHAPE_PLAN.md`) is worked on. Even if new feature plans are added to the 4.3.0 scope mid-cycle, run this master plan's checks first, then proceed to the feature plan's steps. - -This rule exists because the 4.2.0 release was burned by a `workspace:*` → hardcoded version regression discovered only at CI publish time. Running the master gate first establishes a baseline so feature work doesn't mask or introduce regressions. - ---- - -## Step 0: Baseline Validation (run BEFORE any feature work) - -Before touching any feature plan, execute these checks on the current `main` state: - -### 0.1 — Workspace `@tsparticles/` deps use `workspace:*` - -✅ **Risolto nella 4.2.1** — ora automatico via `scripts/post-version-fix.js`. - -Il comando `pnpm run version:patch` (e gli altri `version:*`) esegue: -1. `lerna version` (bump versioni, genera commit + tag) -2. `pnpm run postversion:fix` → `scripts/post-version-fix.js` - - ripristina eventuali `workspace:*` riscritti da lerna in versioni hardcoded - - sincronizza la versione del root `package.json` con `engine/package.json` - - se ci sono fix: `git commit --amend --no-edit` + spostamento tag - -Nota: il controllo manuale via script non serve più, il fix è automatico nello stesso commit del tag. - -### 0.2 — `pnpm run build:ci` passes on clean state - -```bash -pnpm run build:ci -``` - -If either check fails, fix the regression first before starting any feature work. Log the fix commit hash in the dashboard. - ---- - -## Progress Dashboard - -Checklist riassuntiva di tutte le attività del piano. Da tenere aggiornata durante l'esecuzione. - -``` -## 4.3.0 Dashboard — [date] - -### A: Background Canvas -- [ ] Phase 0: hook points identified -- [ ] Phase 1: size delta measured, path chosen -- [ ] Phase 1b: release target decided -- [ ] Phase 2: API/types exported -- [ ] Phase 3: frame hook integrated -- [ ] Phase 4: context cache + fallback integrated -- [ ] Phase 5: warning/error policy integrated -- [ ] Phase 6: tests added and passing -- [ ] Phase 7: docs/examples updated -- [ ] Phase 8: validation commands passing - -### B: Fluid Interaction -- [ ] Step 0: conventions aligned, naming frozen -- [ ] Step 1: package skeleton + noop interactor -- [ ] Step 2: options contract + loaders + tests -- [ ] Step 3: baseline DDR solver -- [ ] Step 4: boundaries + caps + stability -- [ ] Step 5: viscosity + pointer stirring -- [ ] Step 6: interoperability validated -- [ ] Step 7: performance + soak passed -- [ ] Step 8: docs + presets finalized -- [ ] Step 9: (optional) plugin orchestration - -### C: GIF Shape -- [ ] Step 1: scaffold shapes/gif/ (17 files) -- [ ] Step 2: copy + adapt GifUtils (10 files) -- [ ] Step 3: remove GIF from shape-image (9 files) -- [ ] Step 4: add to @tsparticles/all (2 files) -- [ ] Step 5: build + verify -- [ ] Step 6: demo config updated - -### Release Gate (4.3.0) -- [x] ~~Step 0.1~~ — Workspace `@tsparticles/` deps use `workspace:*` (✅ automatico via `post-version-fix.js` dalla 4.2.1) -- [ ] Step 0.2 — `pnpm run build:ci` passes -- [x] ~~Root `package.json` version matches packages~~ (✅ automatico via `post-version-fix.js` dalla 4.2.1) -- [ ] Integration tests pass -- [ ] Demo server smoke-tested -``` - ---- - -## Feature Inventory - -| # | Feature | Package(s) Affected | Type | Plan | -|---|---------|--------------------|------|------| -| A | Background Canvas programmable hook | `@tsparticles/engine` | Engine enhancement | `BACKGROUND_CANVAS_PLAN.md` | -| B | Fluid Particle Interaction | `@tsparticles/interaction-particles-fluid` | New package | `FLUID_INTERACTION_PLAN.md` | -| C | Separate GIF Shape from Image Shape | `@tsparticles/shape-gif` (new), `@tsparticles/shape-image` (modified), `@tsparticles/all` (modified) | Refactor + new package | `GIF_SHAPE_PLAN.md` | - ---- - -## Dependency Graph - -``` -A (Background Canvas) B (Fluid Interaction) C (GIF Shape) - engine only new package only shape-image refactor - no deps on B/C no deps on A/C shape-gif (new) - all bundle update - no deps on A/B - -All three are INDEPENDENT — no shared files, no conflicting changes. -They can be implemented in any order or in parallel. -``` - -### Conflict matrix - -| Area | A ∩ B | A ∩ C | B ∩ C | -|------|-------|-------|-------| -| Files | None | None | None | -| Types | None | None | None | -| Engine | A modifies engine; B, C only use engine types | Same | None | -| Bundle `all` | Not affected | C touches `bundles/all/` | Not affected | -| Risk | None isolated | None isolated | None isolated | - -**Verdict:** All three are fully parallelizable. No merge conflicts expected. -The only integration point is `@tsparticles/all` (feature C adds a dependency). - ---- - -## Sequencing Strategy - -Since all features are independent, the recommended execution is **parallel**: - -``` -Week 1-2: - Agent A: Background Canvas (Phases 0-4) - Agent B: Fluid Interaction (Steps 0-5) - Agent C: GIF Shape (Steps 1-4) - -Week 2-3: - Agent A: Background Canvas (Phases 5-8) - Agent B: Fluid Interaction (Steps 6-9) - Agent C: GIF Shape (Steps 5-6) - -Week 3-4: - Integration: build all, integration tests, soak tests - Release prep: changelog, docs, version bump to 4.3.0 -``` - -If resources are limited, priority order: -1. **Feature C (GIF Shape)** — simplest, lowest risk, unblocks the image shape cleanup -2. **Feature A (Background Canvas)** — moderate, needs bundle-size measurement gate -3. **Feature B (Fluid Interaction)** — most complex, new simulation code, needs tuning - ---- - -## Cross-feature Concerns - -### Per-Feature Verification (run during/after each feature implementation) - -- [ ] **A:** Bundle impact decision recorded (engine vs plugin path) and within accepted threshold -- [ ] **A:** Zero regressions on legacy background behavior -- [ ] **B:** No NaN/Infinity in standard presets after 20k+ frame soak -- [ ] **B:** Fluid visual effect clearly distinguishable from plain attract/repulse -- [ ] **C:** `@tsparticles/shape-image` builds with zero GIF references -- [ ] **C:** `@tsparticles/shape-gif` builds and registers as `type: "gif"` -- [ ] **C:** GIF demo config (`utils/configs/src/g/gifs.ts`) works with new shape - -### Pre-Release Gate (run before cutting release branch) - -- [ ] **ALL:** `pnpm run build:ci` passes -- [ ] **ALL:** No high-severity open issues targeting 4.3.0 -- [x] **ALL:** Workspace `@tsparticles/` deps use `workspace:*` — automatico via `scripts/post-version-fix.js` (integrato in tutti i comandi `version:*`, corregge eventuali regressioni dopo lerna version e amenda lo stesso commit) -- [x] **ALL:** Root `package.json` version matches packages — automatico via `scripts/post-version-fix.js` (letto da `engine/package.json`, scritto nel root e incluso nel commit del tag) -- [ ] **ALL:** Integration tests pass (see below) -- [ ] **ALL:** Demo server smoke-tested (see below) - -### Integration testing - -After individual feature verification, run combined scenarios: - -```bash -pnpm run build:ci -pnpm exec vitest run -``` - -Then smoke-test the demo server: - -```bash -cd demo/vanilla && pnpm start -``` - -### Changelog entries (draft) - -Each feature produces its own changelog section: - -``` -## 4.3.0 - -### New Features -- Background Canvas: programmable `background.draw` callback + `background.element` target (#A) -- Fluid Interaction: new `@tsparticles/interaction-particles-fluid` package with DDR-based - liquid simulation, pointer stirring, and presets (#B) -- GIF Shape: new `@tsparticles/shape-gif` shape extracted from image shape. - Use `type: "gif"` instead of `type: "image"` with `gif: true` (#C) - -### Breaking Changes -- `@tsparticles/shape-image`: removed animated GIF support (`gif` option no longer available). - Migrate to `@tsparticles/shape-gif` with `type: "gif"`. - -### Bundle Changes -- `@tsparticles/all`: now includes `@tsparticles/shape-gif` -``` - ---- - -## Feature A — Background Canvas (from `BACKGROUND_CANVAS_PLAN.md`) - -**Target:** `@tsparticles/engine` -**Load function:** N/A (built into engine) -**Plan phases:** 0-8 - -### Key decisions (from plan) - -1. **Bundle impact gate** (Phase 1): measure delta; if LOW/MEDIUM → keep in engine; if HIGH → extract plugin -2. **Release target gate** (Phase 1b): feature-gate passes → target 4.3.0 - -### Implementation phases - -| Phase | Description | Verification | -|-------|-------------|-------------| -| 0 | Baseline scan — identify insertion points | Short notes | -| 1 | Bundle impact measurement + decision | Size delta block | -| 1b | Release target decision | Go/No-go for 4.3.0 | -| 2 | Type contract — add `element`, `draw`, `BackgroundDrawContext` | Compile passes | -| 3 | Runtime hook in `RenderManager.drawParticles` after `clear()` | Callback runs in order | -| 4 | Target context resolution + caching | Deterministic selection | -| 5 | Error/warning handling (once-per-key, try/catch) | No log flood | -| 6 | Tests — load, precedence, fallback, resilience | Tests green | -| 7 | Docs/examples | No ambiguity | -| 8 | Validation gate | Final checklist complete | - -### Critical files - -| File | Change | -|------|--------| -| `engine/src/Options/Interfaces/Background/IBackground.ts` | Add `element`, `draw` | -| `engine/src/Options/Classes/Background/Background.ts` | Add properties + load | -| `engine/src/Core/Utils/RenderManager.ts` | Add callback call after `clear()` | -| `engine/src/export-types.ts` | Export `BackgroundDrawContext` | - ---- - -## Feature B — Fluid Interaction (from `FLUID_INTERACTION_PLAN.md`) - -**Target:** `@tsparticles/interaction-particles-fluid` -**Load function:** `loadParticlesFluidInteraction(engine)` -**Plan steps:** 0-9 - -### Execution governance - -- Agent must NOT create commits or PRs -- Agent must leave changes uncommitted for maintainer review - -### Implementation steps - -| Step | Description | Verification | -|------|-------------|-------------| -| 0 | Repository alignment — inspect conventions, freeze naming | Checklist | -| 1 | Package skeleton — scaffold + noop `FluidInteractor` | Build passes | -| 2 | Options contract — `IFluid` + classes + loaders + unit tests | Tests pass | -| 3 | Baseline DDR solver — density, pressure, displacement, velocity reconstruction | Visual blob, no NaN | -| 4 | Constraints — boundary clamp/bounce, maxNeighbors, stability | Stable at edges | -| 5 | Viscosity + pointer stirring | Local deformation + recovery | -| 6 | Interoperability — validate with move/emitters/repulse/collisions | Matrix validated | -| 7 | Performance + soak — benchmark 300/600/1000 particles | Meets thresholds | -| 8 | Docs + presets — README, 3 presets, changelog | No undocumented options | -| 9 | Optional advanced path (plugin orchestration) — only if ordering artifacts | Before/after evidence | - -### Critical options (defaults) - -```json -{ - "particles": { - "fluid": { - "enable": false, - "radius": 34, "stiffness": 0.45, "nearStiffness": 0.8, - "restDensity": 3, "viscosity": 0.08, "iterations": 2, - "maxForce": 2.5, "maxNeighbors": 64, - "boundaryBounce": 0.2, "boundaryClamp": true, - "gravity": { "enable": true, "acceleration": 0.01 }, - "pointer": { "enable": false, "radius": 90, "strength": 0.45, "mode": "push" } - } - } -} -``` - ---- - -## Feature C — GIF Shape (from `GIF_SHAPE_PLAN.md`) - -**Target:** `@tsparticles/shape-gif` (new), `@tsparticles/shape-image` (modified), `@tsparticles/all` (modified) -**Load function:** `loadGifShape(engine)` -**Plan substeps:** 1.1 through 6.1 - -### Implementation steps - -| Step | Description | Verification | -|------|-------------|-------------| -| 1 | Scaffold `shapes/gif/` — 17 new files | Directory exists | -| 2 | Copy `GifUtils/` from image shape — adapt `drawGif`, remove `loadGifImage` | Imports resolve | -| 3 | Remove GIF from `@tsparticles/shape-image` — 9 files modified | `grep` zero matches | -| 4 | Add `@tsparticles/shape-gif` to `@tsparticles/all` bundle | Build passes | -| 5 | Build + verify — `pnpm run build:ci` | `dist/` output OK | -| 6 | Update demo config `utils/configs/src/g/gifs.ts` | Demo works | - -### Critical files - -| File | Change | Type | -|------|--------|------| -| `shapes/gif/src/GifDrawer.ts` | New — IShapeDrawer with GIF cache | New | -| `shapes/gif/src/GifUtils/Utils.ts` | Copied + adapted (drawGif, no loadGifImage) | Copy+edit | -| `shapes/image/src/Utils.ts` | Remove 7 gif fields + import | Modify | -| `shapes/image/src/ImageDrawer.ts` | Remove drawGif branch, gif fields | Modify | -| `bundles/all/src/index.ts` | Add loadGifShape import + call | Modify | - -### User-facing config change - -```jsonc -// Before (4.2.x): -{ "shape": { "type": "image", "options": { "image": { "gif": true, "src": "...", "width": 200, "height": 200 } } } } - -// After (4.3.0): -{ "shape": { "type": "gif", "options": { "gif": { "src": "...", "width": 200, "height": 200 } } } } -``` - ---- - -## Release Infrastructure - -### Root `package.json` version sync - -✅ **Risolto nella 4.2.1** — integrato in `scripts/post-version-fix.js`. - -`post-version-fix.js` viene eseguito da `pnpm run postversion:fix` dopo ogni `lerna version`: -1. Legge `engine/package.json` → `version` -2. Se il root `package.json` è diverso, lo sovrascrive -3. `git add -A && git commit --amend --no-edit` lo include nello stesso commit del tag - ---- - -## Rollback Plan - -If any feature is not ready at the 4.3.0 freeze date: - -| Scenario | Action | -|----------|--------| -| A not ready | Ship B + C as 4.3.0, defer A to 4.4.0 | -| B not ready | Ship A + C as 4.3.0, defer B to 4.4.0 | -| C not ready | Ship A + B as 4.3.0, defer C to 4.4.0 | -| A+B not ready | Ship C alone as 4.3.0 | -| A+B+C not ready | No 4.3.0 — reassess scope | - -Each feature's branch must be independent so partial shipping is trivial. - - diff --git a/.planning/handovers/4.4.0_PLAN.md b/.planning/handovers/4.4.0_PLAN.md new file mode 100644 index 00000000000..83706a9c7e2 --- /dev/null +++ b/.planning/handovers/4.4.0_PLAN.md @@ -0,0 +1,293 @@ +# tsParticles 4.4.0 — Fluid Interaction Plan + +## Overview + +**Feature H: Fluid Particle Interaction** — originally planned for 4.3.0 but deferred. +This release delivers the new `@tsparticles/interaction-particles-fluid` package with a +position-only DDR (Density Displacement Resolution) solver for real-time liquid simulation. + +This plan supersedes `FLUID_INTERACTION_PLAN.md` as the active execution document. + +--- + +## Feature Inventory + +| # | Feature | Package | Type | Plan | +|---|---------|---------|------|------| +| H | Fluid Particle Interaction | `@tsparticles/interaction-particles-fluid` (new) | New package | `FLUID_INTERACTION_PLAN.md` | + +--- + +## Sequencing Strategy + +Single feature, single agent. Steps are sequential. + +``` +Step 0: Repository alignment (1h) +Step 1: Package skeleton (2h) +Step 2: Options contract + loaders (3h) +Step 3: Baseline DDR solver (6h) +Step 4: Constraints + stabilization (4h) +Step 5: Interoperability + tuning (4h) +Step 6: Docs, presets, release readiness (4h) +``` + +--- + +## Step 0 — Repository Alignment + +1. Inspect `interactions/particles/collisions/` as template +2. Confirm naming: + - Load function: `loadParticlesFluidInteraction(engine)` + - Interactor key: `"particlesFluid"` + - Package: `@tsparticles/interaction-particles-fluid` + - Option key: `particles.fluid` +3. Verify build: `pnpm nx build @tsparticles/interaction-particles-collisions` + +--- + +## Step 1 — Package Skeleton + +Scaffold `interactions/particles/fluid/` following collisions structure: + +| File | Source | +|------|--------| +| `package.json` | Copy from collisions, update name/description/keywords | +| `tsconfig.base.json` | Copy from collisions | +| `tsconfig.json` | Copy from collisions | +| `tsconfig.types.json` | Copy from collisions | +| `src/index.ts` | Pattern collisions, no OverlapPlugin | +| `src/index.lazy.ts` | Pattern collisions | +| `src/browser.ts` | Pattern collisions | +| `src/FluidInteractor.ts` | Extend `ParticlesInteractorBase` (noop) | + +**Dependencies:** + +| Dependency | Type | +|---|---| +| `@tsparticles/engine` | peer + dev | +| `@tsparticles/plugin-interactivity` | peer + dev | +| `@tsparticles/cli-build` | dev | + +### Files NOT to create + +vs earlier v2 spec: no `FluidGravity`, `FluidPointer`, `FluidDebug`, `FluidMath`, `FluidState`, `FluidPlugin`. + +--- + +## Step 2 — Options Contract + +### Interfaces + +```ts +// Options/Interfaces/IFluid.ts +export interface IFluid { + enable?: boolean; + radius?: number; // default: 30 + stiffness?: number; // default: 0.5 + nearStiffness?: number; // default: 0.5 + restDensity?: number; // default: 3 + maxNeighbors?: number; // default: 64 + maxForce?: number; // default: 2.5 +} +``` + +### Classes + +```ts +// Options/Classes/Fluid.ts +export class Fluid implements IFluid { + enable: boolean; + radius: number; + stiffness: number; + nearStiffness: number; + restDensity: number; + maxNeighbors: number; + maxForce: number; + + constructor(); + load(data?: RecursivePartial): void; +} +``` + +### Types + +```ts +// Types.ts +export type IParticlesFluidOptions = IInteractivityParticlesOptions & { fluid?: IFluid }; +export type ParticlesFluidOptions = InteractivityParticlesOptions & { fluid?: Fluid }; +export type FluidParticle = InteractivityParticle & { options: ParticlesFluidOptions }; +``` + +### Loader + +`FluidInteractor.loadParticlesOptions()` using `loadOptionProperty`. + +--- + +## Step 3 — Baseline DDR Solver + +### Algorithm + +``` +interact(particle, data, delta): + if particle.destroyed or particle.spawning: return + opts = particle.options.fluid + if not opts.enable: return + + // 1. Query neighbors + neighbors = container.particles.grid.queryCircle(particle.position, opts.radius) + + // 2. Density accumulation + pressure = 0, presnear = 0 + store = [] + + for each other in neighbors: + if other is particle or other.destroyed or other.spawning: continue + dx = other.position.x - particle.position.x + dy = other.position.y - particle.position.y + dist = sqrt(dx*dx + dy*dy) + if dist >= opts.radius or dist < epsilon: continue + q = 1 - dist / opts.radius + pressure += q * q + presnear += q * q * q + store.push({ other, q, dx: dx/dist, dy: dy/dist }) + if store.length >= opts.maxNeighbors: break + + // 3. Pressure + P = (pressure - opts.restDensity) * opts.stiffness + Pnear = presnear * opts.nearStiffness + + // 4. Symmetric displacement + for each neighbor in store: + force = P + Pnear * neighbor.q + force = clamp(force, -opts.maxForce, opts.maxForce) + dx = neighbor.dx * force * 0.5 + dy = neighbor.dy * force * 0.5 + particle.position.x -= dx + particle.position.y -= dy + neighbor.other.position.x += dx + neighbor.other.position.y += dy +``` + +### Constants + +- `epsilon = 1e-6` + +### Stability rules + +1. Never divide by `dist < epsilon` +2. Clamp force with `maxForce` +3. Skip destroyed/spawning particles +4. Deterministic cap at `maxNeighbors` +5. Do not reuse neighbor data between frames + +--- + +## Step 4 — Constraints + Stabilization + +1. `maxNeighbors` cap for performance safety +2. Boundary containment via existing `outModes` (no custom boundary logic) +3. Soak test: 600 particles, moveSpeed 2, 5000+ frames + +--- + +## Step 5 — Interoperability + +Test and document combinations: + +| System | Interaction | +|--------|-------------| +| move plugin | Fluid relies on MovePlugin for baseline advection | +| collisions | Can coexist; collisions handles overlap, fluid adds cohesion | +| attract/repulse | Attract creates flows; fluid preserves local coherence | +| external repulse | User uses `interactivity.modes.repulse` for pointer | +| emitters | Spawned particles skipped via `spawning` flag | +| gravity (move) | Already in MovePlugin, no fluid gravity needed | + +--- + +## Step 6 — Docs, Presets, Release Readiness + +### README + +- Install: `pnpm add @tsparticles/interaction-particles-fluid` +- Load: `loadParticlesFluidInteraction(engine)` +- Options table with defaults and semantics +- Caveats: + - Requires `particles.move.enable: true` + - No pointer interaction built-in (use external repulse) + - Boundary via `outModes`, not fluid options + +### Preset + +One functional default preset config in `utils/configs/`: + +```json +{ + "particles": { + "move": { "enable": true, "speed": 2 }, + "fluid": { + "enable": true, + "radius": 30, + "stiffness": 0.5, + "nearStiffness": 0.5, + "restDensity": 3, + "maxForce": 2.5 + }, + "number": { "value": 300 } + } +} +``` + +### Pre-Release Gate + +- [ ] `pnpm run build:ci` passes +- [ ] `pnpm exec vitest run` — all tests green +- [ ] Demo smoke test: `cd demo/vanilla && pnpm start` +- [ ] Workspace deps use `workspace:*` +- [ ] Root `package.json` version matches packages + +### Acceptance Criteria + +1. Visual effect clearly fluid (local clusters, incompressibility) — not simple attract/repulse +2. No NaN/Infinity in positions after 20k+ frame soak +3. Defaults stable with 300-600 particles on desktop +4. Zero modifications to `@tsparticles/engine` +5. README with options, caveats, and migration notes + +--- + +## Changelog Entry (draft) + +```markdown +## 4.4.0 + +### New Features +- Fluid Interaction: new `@tsparticles/interaction-particles-fluid` package with DDR-based + liquid simulation (#H) + - `particles.fluid.enable`: enable fluid interaction + - `particles.fluid.radius`: interaction radius (default: 30) + - `particles.fluid.stiffness`: pressure coefficient (default: 0.5) + - `particles.fluid.nearStiffness`: near-pressure coefficient (default: 0.5) + - `particles.fluid.restDensity`: target density (default: 3) + - `particles.fluid.maxNeighbors`: performance cap (default: 64) + - `particles.fluid.maxForce`: safety clamp (default: 2.5) + - Load via `loadParticlesFluidInteraction(engine)` +``` + +--- + +## Rollback Plan + +Only one feature — if Fluid Interaction is not ready, skip 4.4.0 entirely and reassess. + +--- + +## Key Constraints + +- DON'T touch engine — zero modifications to `@tsparticles/engine` +- DON'T create commits or PRs during implementation +- Follow collisions pattern for package structure +- No per-particle state storage (no `prevPosition`, no density cache) +- Single-pass DDR, no multi-pass or container plugin orchestration diff --git a/.planning/handovers/BACKGROUND_CANVAS_PLAN.md b/.planning/handovers/BACKGROUND_CANVAS_PLAN.md deleted file mode 100644 index 125477011b1..00000000000 --- a/.planning/handovers/BACKGROUND_CANVAS_PLAN.md +++ /dev/null @@ -1,548 +0,0 @@ -# Background Canvas Plan (v5.0 Agent-Ready) - -## Summary - -| | | -|---|---| -| **Target** | `@tsparticles/engine` | -| **Phases** | 8 (0–8) | -| **Type** | Engine enhancement | -| **Load function** | N/A (built into engine) | -| **Key decision gate** | Phase 1: bundle impact → engine vs plugin; Phase 1b: 4.2.0 vs 4.3.0 | - -### Progress - -- [ ] Phase 0: Baseline scan -- [ ] Phase 1: Bundle impact + decision -- [ ] Phase 1b: Release target decision -- [ ] Phase 2: Type contract -- [ ] Phase 3: Runtime hook -- [ ] Phase 4: Target resolution/cache -- [ ] Phase 5: Error/warning handling -- [ ] Phase 6: Tests -- [ ] Phase 7: Docs/examples -- [ ] Phase 8: Validation gate - ---- - -## Context - -Current `background` support is CSS-style only and applied to the particles DOM canvas style (`color`, `image`, `position`, `repeat`, `size`, `opacity`). - -That path is stable and must remain unchanged. - -This proposal adds an opt-in programmable background hook for advanced JS/TS users while preserving strict backward compatibility. - -## Product Goal - -Add two optional fields under `background`: - -- `background.element`: optional target canvas (`string` selector or `HTMLCanvasElement`) -- `background.draw`: optional callback called each frame with drawing context + delta - -The goal is custom background rendering (procedural, animated, layered) without rewriting the existing rendering pipeline. - -## Hard Product Constraints (non-negotiable) - -1. Use `background.element` only. Do not introduce `background.canvas`. -2. Both new options are optional and `undefined` by default. -3. Explicit precedence: - - highest: `background.draw` - - fallback target: `background.element` -4. Existing CSS `background.color` (and style background options) must continue working exactly as today. -5. If `draw` exists, do not add any automatic compose/copy step between external and internal canvases. - -## Scope and Non-Goals - -### In scope - -- Options/types additions for `element` and `draw` -- Runtime draw callback execution in the frame loop -- Target context resolution with fallback -- Warnings and safety guards -- Tests + docs/examples - -### Out of scope (for this version) - -- New lifecycle hooks (`init`, `resize`, `destroy`) for callback backgrounds -- New clear modes API -- Automatic sync/composition between multiple canvases -- Re-architecting plugin draw pipeline - -## Bundle Size and Architecture Decision (engine vs plugin) - -Because `background` lives in `@tsparticles/engine` today, we need an explicit decision gate before implementation finalization. - -### Current baseline (from existing dist artifacts) - -- `@tsparticles/engine` minified UMD: ~68,025 bytes (`engine/dist/tsparticles.engine.min.js`) -- Existing reference plugin (`@tsparticles/plugin-background-mask`) minified UMD: ~5,730 bytes (`plugins/backgroundMask/dist/tsparticles.plugin.background-mask.min.js`) - -These values are only reference points; they are not direct apples-to-apples for the new feature. - -### Why this matters - -- Implementing in engine keeps UX simple (no extra package) but increases base payload for everyone. -- Implementing as plugin keeps engine lean but adds integration and migration complexity. - -### Decision thresholds (pragmatic) - -After implementing a prototype (or spike) and measuring delta: - -- `LOW impact`: `< 1.0 KB` minified **and** `< 1.5%` engine minified growth - - Decision: keep in engine for now. -- `MEDIUM impact`: `1.0-2.5 KB` minified **or** `1.5-3.5%` growth - - Decision: keep in engine now, but open follow-up RFC for plugin extraction. -- `HIGH impact`: `> 2.5 KB` minified **or** `> 3.5%` growth - - Decision: strongly prefer extraction into `@tsparticles/plugin-background`. - -If thresholds conflict, prioritize percentage on `engine` minified artifact. - -### Measurement protocol (mandatory) - -1. Build baseline from current main/branch state. -2. Record size of: - - `engine/dist/tsparticles.engine.min.js` - - `engine/dist/tsparticles.engine.js` -3. Apply feature changes (spike or full). -4. Rebuild and record same files. -5. Compute byte and percentage deltas. -6. Add result table in PR/notes and take architecture decision using thresholds above. - -### Decision output format (for agent) - -Agent must produce a short block like: - -- `baseline_min`: X bytes -- `candidate_min`: Y bytes -- `delta_min`: +Z bytes (+N%) -- `decision`: engine-now | engine-now-with-followup | extract-plugin -- `rationale`: 2-4 bullets - -## Plugin extraction option (`@tsparticles/plugin-background`) - pros/cons - -### Pros - -- Smaller core payload for users not needing programmable backgrounds. -- Feature can evolve independently (hooks/lifecycle/diagnostics) with lower engine risk. -- Cleaner separation between core particle runtime and optional background rendering strategies. - -### Cons - -- Higher integration complexity (new plugin package, registration path, docs updates across bundles/wrappers). -- Potentially awkward split because style background options currently belong to engine core. -- More migration/documentation burden to avoid user confusion (`background` base vs plugin-enhanced behavior). -- Plugin ordering/interaction edge cases may appear and require extra tests. - -### Recommended strategy now - -- Keep base CSS background in engine regardless. -- Implement programmable callback path in engine first **only if** measured impact is LOW/MEDIUM. -- If impact is HIGH, pivot to plugin extraction where plugin owns `draw`/`element` behavior while engine retains style background fields. - -## Release Suitability (4.2.0 vs 4.3.0) - -This feature is additive and can be semver-minor **only if** risk remains controlled. - -### Semver classification for this feature - -- `minor-safe` when all are true: - - API is additive only (`background.element`, `background.draw` optional) - - existing behavior remains identical when options are not used - - no existing option semantics are changed - - no wrapper mandatory changes -- `not minor-safe` if any existing default/behavior changes for current users. - -### Branch-level release pressure (current repository state) - -From `v4.1.3..HEAD` (current `v4` branch snapshot): - -- commits: `98` -- changed files: `2019` -- diff stats: `+177,718 / -43,016` - -Interpretation: this is a large aggregate delta for a single minor train, independent of this specific feature. - -### Decision framework - -Use two independent gates: - -1. `Feature gate` (this background work): - - pass if additive + backward-compatible + tests green + bundle threshold decision recorded -2. `Release train gate` (overall 4.2.0 scope): - - pass if cumulative 4.2 changeset is still acceptable for a minor from maintainer risk tolerance - -Final release target: - -- `Ship in 4.2.0` only if **both** gates pass. -- `Move to 4.3.0` if feature gate passes but release-train gate fails (too much aggregate churn). - -### Go/No-Go checklist (explicit) - -Use this checklist before locking milestone. - -#### GO for `4.2.0` only if all are true - -- [ ] feature remains strictly additive (`background.element`/`background.draw` optional) -- [ ] zero regressions on legacy background behavior (automated + manual smoke) -- [ ] bundle impact decision completed and within accepted threshold for chosen path -- [ ] docs/examples updated with no ambiguity -- [ ] no blocker/high-severity open issues related to engine render loop from the 4.2 train -- [ ] release-train churn accepted by maintainer (explicit yes) - -#### NO-GO for `4.2.0` (defer to `4.3.0`) if any is true - -- [ ] implementation requires semantic tweaks that can surprise existing users -- [ ] unresolved instability in render loop / canvas layering paths -- [ ] bundle impact classified HIGH but plugin path not completed -- [ ] verification window is too short for confidence across wrappers/bundles -- [ ] aggregate 4.2 train is considered too broad/risky at freeze time - -### Practical recommendation for current situation - -Given current branch volume, default recommendation is: - -- keep implementation ready and mergeable, -- but be prepared to defer public release to `4.3.0` unless 4.2.0 scope is trimmed/frozen. - -Reason: even minor-safe features become risky when packed into a high-churn train. - -Additional evidence snapshot: - -- `engine/src` files changed since `v4.1.3`: `47` -- `engine/src/Core` changed: `9` -- `engine/src/Options` changed: `28` -- `wrappers` changed: `77` -- `plugins` changed: `96` -- `bundles` changed: `24` - -Recommendation right now: **provisionally target `4.3.0`**, and only pull into `4.2.0` if a hard freeze/triage confirms low residual risk. - -## Final API Proposal - -### `background.element` - -- Type: `string | HTMLCanvasElement` -- Optional: yes -- Default: `undefined` -- Semantics: - - `string`: CSS selector resolved in DOM-capable environments - - `HTMLCanvasElement`: direct reference - -### `background.draw` - -- Type: `(context: BackgroundDrawContext, delta: IDelta) => void` -- Optional: yes -- Default: `undefined` -- Semantics: callback executed each frame in the background phase - -### Supporting exported type - -Introduce and export a type alias for clarity and Offscreen support: - -- `type BackgroundDrawContext = OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D` - -Reason: internal engine rendering uses Offscreen contexts in many environments; callback typing must reflect runtime reality. - -### Serialization note - -- `element` can be expressed in JSON (selector string) -- `draw` is function-only and therefore JS/TS runtime config only - -## Behavior and Precedence - -1. No `draw`, no `element` - - unchanged behavior only (CSS background + standard particles rendering) - -2. `element` only - - no background callback execution - - no implicit rendering/compositing - - CSS background behavior unchanged - -3. `draw` only - - callback runs on internal render context - - CSS background behavior unchanged - -4. `draw` + `element` - - callback runs on resolved `element` context if valid - - otherwise callback falls back to internal render context - - no extra copy/composition between contexts - - CSS background behavior unchanged - -### Key interpretation - -`element` is only target selection. `draw` is rendering logic. There is no hidden strategy beyond that. - -## Engine Integration Design - -## 1) Options and type surface - -Target files: - -- `engine/src/Options/Interfaces/Background/IBackground.ts` -- `engine/src/Options/Classes/Background/Background.ts` -- `engine/src/export-types.ts` -- `engine/src/exports.ts` (only if a runtime type/class export is needed) - -Changes: - -- Add optional `element` and `draw` to `IBackground` -- Keep both undefined by default in class implementation -- Add exported callback context alias + callback type (or inline signature with alias) - -Rule: do not change existing background fields defaults or semantics. - -## 2) Runtime placement in frame loop (critical) - -Implement background callback in `RenderManager.drawParticles(delta)` with this order: - -1. `clear()` -2. Execute background callback phase (new) -3. Continue existing draw pipeline (`drawSettingsSetup`, plugin `draw`, particles, cleanup) - -This keeps background visuals behind particles/effects and avoids changing current plugin contract semantics. - -Important clarification: - -- CSS background style (`CanvasManager.initBackground`) is not a per-frame operation today and should remain so. -- Do not move CSS style writes into the hot loop. - -## 3) Context resolution and caching - -Resolve target context once and cache it; do not resolve selectors per frame. - -Resolution rules: - -1. If `element` is `HTMLCanvasElement`, try `getContext("2d")` -2. If `element` is `string` and DOM is available, resolve `document.querySelector` -3. If selected node is not a canvas, treat as invalid target -4. On any invalid/missing target, fallback to internal render context - -Cache invalidation events: - -- container init/start -- options reload/reset/refresh -- explicit background options change path (if applicable) - -No per-frame allocations from this feature. - -## 4) Safety and diagnostics - -### Callback exception handling - -- Wrap callback invocation in `try/catch` -- Keep animation loop alive -- Warn with deterministic message - -### Warning policy (must avoid log spam) - -- Warn once per container per warning key -- Suggested keys: - - `background-element-selector-not-found` - - `background-element-not-canvas` - - `background-element-context-unavailable` - - `background-draw-error` - -Implementation can use a small `Set` attached to container/render state. - -## 5) Environment constraints - -- In non-DOM environments, selector resolution is skipped safely. -- If an external canvas context cannot be obtained, fallback to internal context. -- No assumptions that external canvas size or DPR match internal canvas. -- External canvas sizing remains user responsibility (document this clearly). - -## Compatibility Model - -## Backward compatibility guarantees - -- Existing configs remain behavior-identical when new options are not used. -- Existing background style path remains unchanged. -- Feature is fully opt-in. - -## Wrapper compatibility - -- Engine type exports must include new types/options. -- No required runtime wrapper changes for baseline JS object configs. - -## JSON vs JS/TS expectations - -- JSON: `element` only -- JS/TS: `element` and `draw` -- Docs/examples must show both to avoid false expectations. - -## Test Plan - -## Unit tests - -1. Options loading - - new fields accepted - - defaults remain `undefined` - - legacy fields unchanged - -2. Resolution logic - - valid selector -> canvas context - - selector missing -> fallback + once warning - - non-canvas match -> fallback + once warning - - direct canvas without context -> fallback + once warning - -3. Precedence logic - - no `draw` -> callback never runs (even if `element` exists) - - `draw` only -> internal context used - - `draw` + valid `element` -> external context used - - `draw` + invalid `element` -> internal fallback - -4. Error resilience - - throwing callback does not break next frame - - warning is throttled (once-key behavior) - -5. Performance guard - - feature disabled path adds no measurable overhead in smoke benchmark - -## Integration/manual smoke - -1. Legacy style-only background visually unchanged -2. JS `draw` only renders animated background on internal canvas -3. JS `draw` + external `element` renders on external target -4. Invalid selector + `draw` safely falls back -5. Large particle count + lightweight callback remains stable - -## Acceptance Criteria (Definition of Done) - -1. API - - `background.element` and `background.draw` available and optional - - no `background.canvas` alias - -2. Behavior - - `draw` is the only trigger for custom background rendering - - `element` only selects callback target context - - no implicit compose/copy between canvases - - CSS style background path remains active and unchanged - -3. Stability - - invalid target gracefully falls back - - callback exceptions do not stop rendering - - warnings are deterministic and non-spammy - -4. Performance/compatibility - - unchanged behavior for legacy configs - - no meaningful overhead when callback is disabled - -5. Architecture decision - - bundle-size delta has been measured and documented - - decision (engine vs plugin path) follows defined thresholds - - final implementation matches recorded decision - -6. Release target decision - - feature-level minor-safety checklist completed - - release-train gate explicitly evaluated (`4.2.0` vs `4.3.0`) - - final target version documented with rationale - -## Execution Plan for Build Agent (phase-based) - -### Phase 0 - Baseline scan - -- Identify exact insertion points in `IBackground`, `Background`, `RenderManager` -- Confirm current draw order and options load flow -- Output: short notes with chosen hook points - -### Phase 1 - Bundle impact baseline and decision gate - -- Capture baseline engine artifact sizes -- Implement minimal spike (or use completed implementation) and capture candidate sizes -- Compute delta bytes/% and classify LOW/MEDIUM/HIGH -- Choose path: - - Path A: engine implementation (LOW/MEDIUM) - - Path B: plugin extraction (HIGH) -- Output: decision block with measurements and rationale - -### Phase 1b - Release-target gate (`4.2.0` vs `4.3.0`) - -- Evaluate feature-level semver safety checklist -- Evaluate branch/release-train risk (aggregate churn, open regressions, pending risky work) -- Propose target: - - `4.2.0` if both gates pass - - `4.3.0` if release-train gate fails -- Output: short release recommendation block with evidence - -### Phase 2 - Type contract - -- Add `element` + `draw` options types -- Add and export `BackgroundDrawContext` alias (and callback type if introduced) -- Output: compile passes for type surface - -Path note: - -- Path A (engine): change engine option surface directly. -- Path B (plugin): keep engine base types stable, add plugin options/types and plugin registration API. - -### Phase 3 - Runtime hook - -- Add background callback execution method in `RenderManager` -- Invoke it in `drawParticles` immediately after `clear()` -- Keep existing draw flow unchanged otherwise -- Output: callback runs in intended order - -Path note: - -- Path A: implement in engine render loop. -- Path B: implement via plugin container hooks (`canvasPaint`/`draw` strategy) without breaking existing plugin contracts. - -### Phase 4 - Target resolution/cache - -- Implement resolver + cached target context -- Implement fallback to internal context -- Hook cache refresh in init/refresh-reload paths -- Output: deterministic context selection without per-frame selector calls - -### Phase 5 - Error/warning handling - -- Add once-per-key warning mechanism -- Guard callback invocation -- Output: safe loop on callback errors, no log flood - -### Phase 6 - Tests - -- Add/update tests for load, precedence, fallback, warnings, resilience -- Output: tests green for new behavior and no regressions - -Path note: - -- Path B must include plugin integration tests and plugin-not-loaded behavior tests. - -### Phase 7 - Docs/examples - -- Update docs for API semantics, JSON limits, JS callback usage -- Add minimal examples for each mode -- Output: no ambiguity around `element` vs `draw` - -Path note: - -- Path B docs must clearly explain plugin installation/registration requirement. - -### Phase 8 - Validation gate - -- Run targeted engine tests and affected build/lint tasks -- Verify no behavior regressions in legacy background config -- Output: final checklist complete - -## Progress Checklist Template (for agent status updates) - -- [ ] Phase 0 complete: hook points identified -- [ ] Phase 1 complete: size delta measured and path chosen -- [ ] Phase 1b complete: release target (`4.2.0`/`4.3.0`) decided -- [ ] Phase 2 complete: API/types exported -- [ ] Phase 3 complete: frame hook integrated -- [ ] Phase 4 complete: context cache + fallback integrated -- [ ] Phase 5 complete: warning/error policy integrated -- [ ] Phase 6 complete: tests added and passing -- [ ] Phase 7 complete: docs/examples updated -- [ ] Phase 8 complete: validation commands passing - -## Notes for Build Agent - -- Keep the implementation additive and minimal. -- Do not alter existing CSS background semantics. -- Do not add hidden auto-composition behavior. -- Prefer explicit fallback logic over magic. -- If a choice is ambiguous, choose least-surprising behavior and document it in PR notes. diff --git a/.planning/handovers/FLUID_INTERACTION_PLAN.md b/.planning/handovers/FLUID_INTERACTION_PLAN.md index 7edcab52b29..8fbc4a32303 100644 --- a/.planning/handovers/FLUID_INTERACTION_PLAN.md +++ b/.planning/handovers/FLUID_INTERACTION_PLAN.md @@ -1,14 +1,14 @@ -# Fluid Particle Interaction - Deep Technical Specification (Draft v2) +# Fluid Particle Interaction - Deep Technical Specification (v3) ## Summary -| | | -|---|---| -| **Target** | `@tsparticles/interaction-particles-fluid` | -| **Steps** | 10 (0–9) | -| **Type** | New package | -| **Load function** | `loadParticlesFluidInteraction(engine)` | -| **Key constraints** | Don't touch engine; agent must NOT commit/PR | +| | | +|---------------------|----------------------------------------------| +| **Target** | `@tsparticles/interaction-particles-fluid` | +| **Steps** | 7 (0–6) | +| **Type** | New package (particles interactor) | +| **Load function** | `loadParticlesFluidInteraction(engine)` | +| **Key constraints** | Don't touch engine; no commit/PR | ### Progress @@ -16,398 +16,198 @@ - [ ] Step 1: Package skeleton (noop) - [ ] Step 2: Options contract + loaders - [ ] Step 3: Baseline DDR solver -- [ ] Step 4: Constraints + boundary behavior -- [ ] Step 5: Viscosity + pointer stirring -- [ ] Step 6: Interoperability hardening -- [ ] Step 7: Performance + soak validation -- [ ] Step 8: Docs, presets, release readiness -- [ ] Step 9: (optional) Advanced path +- [ ] Step 4: Constraints + stabilization +- [ ] Step 5: Interoperability + tuning +- [ ] Step 6: Docs, presets, release readiness --- -## Document status +## What changed from v2 -- Scope: planning only (no implementation in this session) -- Target package: `interactions/particles/fluid` -- Engine policy: do not touch `engine` unless a missing extension point is proven -- Audience: implementation agent and maintainers -- Goal: convert a CodePen-style liquid behavior into a tsParticles-native interaction - -## Execution governance (critical) - -This plan is executed by an implementation agent under strict handoff control. - -Mandatory rule: - -- the implementation agent must NOT create commits; -- the implementation agent must NOT open PRs; -- the implementation agent must leave changes uncommitted so the maintainer can review and commit manually. - -Reason: - -- maintain full maintainer control over change review, commit boundaries, and final PR composition. - -## Versioning gate (blocking) - -Current baseline considered in this plan: - -- current line: `4.1.3` -- candidate target: `4.2.0` - -Semver assessment for this feature (default path): - -- expected classification: **minor** (`4.2.0`) because it introduces a new optional interaction/package without requiring breaking API changes; -- expected non-breaking behavior: existing configs continue to work unchanged when `particles.fluid` is not enabled. - -When this would become major instead: - -- any required engine API break; -- removal/rename/incompatible change of existing public contracts; -- mandatory behavior changes that alter existing scenes without opt-in. - -Blocking rule: - -- implementation can proceed only under the approved target version line; -- if during implementation evidence suggests this is not suitable for `4.2.0`, work must stop and the agent must request explicit maintainer confirmation before continuing on a new minor/major strategy; -- no "implicit go" is allowed. +| Change | Reason | +|--------|--------| +| Removed `FluidGravity`, `FluidPointer`, `FluidDebug` sub-options | Gravity già in Move plugin, mouse repulse già come external interaction, debug non richiesto | +| Rimosso velocity reconstruction dopo DDR | Inconsistente col modello velocity-based di tsparticles; il particle-particle repulse modifica position senza aggiornare velocity | +| Rimosso `iterations` | Single-pass DDR è sufficiente; multi-pass richiederebbe container plugin che aggiunge complessità ingiustificata nel v1 | +| Rimosso `boundaryBounce`/`boundaryClamp` come opzioni | tsparticles ha già `outModes` per i bordi; la fluid interaction non deve reintrodurre boundary handling | +| Rimosso `viscosity` dal v1 | Opzione da rivalutare dopo baseline funzionante | +| Semplificata la struttura package | Niente FluidMath/FluidState/FluidPlugin separati; tutto nell'interactor | +| Semplificato il type design | Niente `FluidParticle.fluid.prevX/prevY` (non serve senza velocity reconstruction) | +| Rimossi preset multipli | Un preset di default sufficiente per v1 | +| Allineato pattern con Collider/Attractor esistenti | `maxDistance` come field pubblico, `clear()` noop, `reset()` noop | --- -## Why this document exists - -The requested feature is not just another visual mode. It changes how particles move and how they influence each other every frame. That means we need: - -- simulation intent clearly defined; -- architectural boundaries (interaction vs plugin) explicit; -- constraints and fallback plans documented before coding; -- tuning ranges and test criteria ready to avoid endless trial-and-error. - -This spec turns the initial idea (fluid-like particles from the referenced CodePen) into a concrete and staged implementation plan that can be executed by another agent with minimal ambiguity. - ---- - -## Product intent - -Create a new `fluid` interaction where particles exhibit cohesive liquid-like behavior: - -- local clustering into blobs/streams; -- soft incompressibility (they should not collapse into one point); -- smooth collective motion under external forces; -- stable behavior with existing tsParticles interactions. - -Non-goals: +## Execution governance (critical) -- physically exact fluid dynamics; -- pressure projection on a continuous Eulerian grid; -- hard requirement for perfect determinism across all devices. +- implementation agent must NOT create commits; +- implementation agent must NOT open PRs; +- all changes left uncommitted for maintainer review. --- -## Source inspiration and extraction - -The provided CodePen sample is a particle-based visco-elastic fluid style simulation using: +## Strategy: Position-Only DDR -- a spatial hashing grid, -- three passes (`pass1`, `pass2`, `pass3`), -- double density relaxation, -- boundary clamping, -- velocity reconstruction from corrected positions. +La differenza fondamentale col reference code: -Important: we should **extract behavior**, not copy architecture blindly. - -### What to keep from the example - -- multi-pass frame approach; -- neighborhood-limited interactions (radius); -- pressure and near-pressure terms; -- symmetrical pair displacement; -- velocity rebuilt from position delta; -- optional pointer impulse. - -### What to adapt for tsParticles - -- use existing particle grid (`container.particles.grid`) instead of custom cell arrays; -- use existing interactor/plugin lifecycles; -- avoid per-frame re-allocation heavy buffers where possible; -- integrate with existing options model (`load` patterns, interfaces/classes); -- support compatibility with move/collisions/emitters/interactivity plugins. - ---- - -## CodePen to tsParticles mapping - -This section maps the conceptual phases from the source snippet to expected tsParticles behavior. - -| Source phase | Source intent | tsParticles counterpart | -|--------------|---------------|--------------------------| -| `pass1` | predict position from velocity + gravity + pointer force | pre-relaxation step in `FluidInteractor.interact(...)` or plugin-orchestrated frame step | -| `pass2` | density/near-density + displacement + bounds | main fluid relaxation loop using `queryCircle` neighbors | -| `pass3` | recalc velocity from corrected position | velocity correction pass; possibly integrated after displacement | - -### Source logic excerpt (trimmed and annotated) - -```js -// pass1: predict -particles_pprevx[n] = px; -particles_pprevy[n] = py; -particles_x[n] += particles_velx[n]; -particles_y[n] += particles_vely[n]; - -// pass2: density and pressure -var q = 1 - (vlen / rad); -pressure += q * q; -presnear += q * q * q; - -pressure = (pressure - 3) * 0.5; -presnear *= 0.5; - -// pair displacement -var p = pressure + presnear * particles_q[np]; -var dx = (particles_vxl[np] * p) * 0.5; -var dy = (particles_vyl[np] * p) * 0.5; -particles_x[np] += dx; -particles_y[np] += dy; -particles_x[n] -= dx; -particles_y[n] -= dy; - -// pass3: velocity reconstruction -particles_velx[n] = particles_x[n] - particles_pprevx[n]; -particles_vely[n] = particles_y[n] - particles_pprevy[n]; +``` +Reference code: tsparticles Fluid: + pass1: predict (vel → pos) → MovePlugin (vel → pos) + pass2: DDR (position correction) → FluidInteractor.interact() (position correction ONLY) + pass3: velocity extraction → SKIP (velocity non aggiornata) ``` -Interpretation: - -- position-based correction is the heart of the fluid effect; -- velocity is derived from corrected positions, not only from forces; -- near-pressure makes short-range incompressibility feel "thicker". - ---- - -## Architecture decision - -### Preferred initial shape - -Implement as an interaction package under: - -- `interactions/particles/fluid` - -Publishing target: - -- `@tsparticles/interaction-particles-fluid` - -Option key: - -- `particles.fluid` - -Loader: - -- `loadParticlesFluidInteraction(engine)` - -Rationale: - -- semantically aligned with `interactions/particles/*` packages; -- lower integration burden for users; -- likely enough API surface in v4 already. - -### Escalation strategy - -If sequencing or shared frame-state becomes problematic: +Nel reference, la velocity reconstruction è necessaria perché il loop successivo usa velocity per advect. In tsparticles, il MovePlugin usa già la velocity memorizzata sul particle per advect. La correzione DDR è puramente posizionale — modifica `particle.position` direttamente, come già fa il particle-particle repulse (`p2.position.addTo(...)`). -1. keep package in `interactions/particles/fluid`, -2. add internal plugin instance for orchestration, -3. only then evaluate migration to `plugins/fluid`. +**Vantaggi**: +- Pattern già consolidato (particle repulse modifica position senza velocity) +- Nessun conflitto col MovePlugin +- Nessuna necessità di estendere Particle con `fluidPrevPosition` +- Stabile: DDR corregge ogni frame, eventuale drift dell'advect viene compensato -Escalate only with evidence (reproducible instability, persistent order artifacts, or inability to run required passes safely). +**Rischio accettato**: La velocity non aggiornata può causare oscillazioni sottili se moveSpeed è alta rispetto a stiffness. Mitigazione: default conservativi, utente può abbassare moveSpeed. --- -## v4 readiness check - -Based on existing patterns (`collisions`, `attract`, `infection`, `move`), v4 appears ready for first implementation. - -Capabilities already present: - -- neighbor query via `container.particles.grid.queryCircle(...)`; -- particle mutation in interactors; -- container plugin `update(delta)` if needed; -- options loading and typed extension patterns. - -Potential gap to watch: - -- deterministic ordering between fluid correction and move integration. - -Proposed rule: - -- do not request engine changes up front; -- instrument first implementation; -- request minimal hook ordering support only if artifacts remain after interactor/plugin orchestration. +## Architecture decision ---- +### Package -## Entry points and package contracts +``` +interactions/particles/fluid +``` -### Must-have public API +Publishing target: `@tsparticles/interaction-particles-fluid` -```ts -export async function loadParticlesFluidInteraction(engine: Engine): Promise; -``` +Option key: `particles.fluid` -### Must-have option contract +Loader: `loadParticlesFluidInteraction(engine)` -`particles.fluid` should support enable + tuning options with safe defaults. +### Interactor type -### Should-have exports +`ParticlesInteractorBase` (particles interactor, non external) -- `IFluid` and sub-interfaces; -- enum/string union types if modes are introduced; -- option classes consistent with repo style. +Registrato come `"particlesFluid"` via `pluginManager.addInteractor` --- -## Proposed options model (detailed) +## Proposed options model (v3 simplified) ```ts -export type FluidPointerMode = "push" | "pull"; - -export interface IFluidGravity { - enable?: boolean; - acceleration?: number; -} - -export interface IFluidPointer { - enable?: boolean; - radius?: number; - strength?: number; - mode?: FluidPointerMode; -} - -export interface IFluidDebug { - enable?: boolean; - drawRadius?: boolean; - drawDensity?: boolean; - drawNeighbors?: boolean; -} - export interface IFluid { enable?: boolean; - radius?: number; - stiffness?: number; - nearStiffness?: number; - restDensity?: number; - viscosity?: number; - iterations?: number; - maxForce?: number; - maxNeighbors?: number; - boundaryBounce?: number; - boundaryClamp?: boolean; - gravity?: IFluidGravity; - pointer?: IFluidPointer; - debug?: IFluidDebug; + radius?: number; // default: 30 + stiffness?: number; // default: 0.5 (k) + nearStiffness?: number; // default: 0.5 (k̃) + restDensity?: number; // default: 3 (ρ₀) + maxNeighbors?: number; // default: 64 + maxForce?: number; // default: 2.5 } ``` -### Defaults (candidate) +### Defaults ```json { "particles": { "fluid": { "enable": false, - "radius": 34, - "stiffness": 0.45, - "nearStiffness": 0.8, + "radius": 30, + "stiffness": 0.5, + "nearStiffness": 0.5, "restDensity": 3, - "viscosity": 0.08, - "iterations": 2, - "maxForce": 2.5, "maxNeighbors": 64, - "boundaryBounce": 0.2, - "boundaryClamp": true, - "gravity": { - "enable": true, - "acceleration": 0.01 - }, - "pointer": { - "enable": false, - "radius": 90, - "strength": 0.45, - "mode": "push" - }, - "debug": { - "enable": false, - "drawRadius": false, - "drawDensity": false, - "drawNeighbors": false - } + "maxForce": 2.5 } } } ``` -### Option semantics +### Semantics + +- **radius**: distanza di interazione tra particelle. Più alto → più smooth ma più costoso. +- **stiffness**: coefficiente di pressione k in P = k(ρ - ρ₀). Più alto → più rigido. +- **nearStiffness**: coefficiente di near-pressione k̃ in P̃ = k̃·ρ̃. Più alto → anti-compressione locale (blob effect). +- **restDensity**: densità target ρ₀. Valori più alti → particelle più compresse. +- **maxNeighbors**: safety cap per performance. +- **maxForce**: clamp di sicurezza per evitare esplosioni numeriche. + +### Nota sui valori -- `radius`: interaction support radius; larger means smoother but slower. -- `stiffness`: pressure response to density above `restDensity`. -- `nearStiffness`: near-field anti-compression; key for "liquid blob" feel. -- `restDensity`: target neighbor density equilibrium. -- `viscosity`: velocity blending/smoothing. -- `iterations`: correction loops per frame (1-4 reasonable). -- `maxForce`: hard clamp to avoid numerical explosions. -- `maxNeighbors`: perf safety cap. -- `boundaryBounce` + `boundaryClamp`: containment behavior near canvas edges. +I default sono presi direttamente dal reference code e dovrebbero produrre un effetto fluido stabile su 300-600 particelle con moveSpeed 1-2. --- -## Package structure (target) +## DDR Algorithm (implementation-grade) + +### Per-frame pseudo-code -```text -interactions/particles/fluid/ - .browserslistrc - .npmignore - CHANGELOG.md - LICENSE - README.md - eslint.config.js - package.dist.json - package.json - rollup.config.js - tsconfig.base.json - tsconfig.browser.json - tsconfig.json - tsconfig.module.json - tsconfig.types.json - typedoc.json - src/ - browser.ts - index.lazy.ts - index.ts - Types.ts - FluidInteractor.ts - FluidMath.ts - FluidState.ts - Options/ - Classes/ - Fluid.ts - FluidDebug.ts - FluidGravity.ts - FluidPointer.ts - Interfaces/ - IFluid.ts - IFluidDebug.ts - IFluidGravity.ts - IFluidPointer.ts +``` +interact(particle, data, delta): + if particle.destroyed or particle.spawning: + return + + opts = particle.options.fluid + if not opts.enable: + return + + // 1. Query neighbors via spatial hash grid + neighbors = container.particles.grid.queryCircle(particle.position, opts.radius) + + // 2. Density accumulation + pressure = 0 + presnear = 0 + neighborCount = 0 + + for each other in neighbors: + if other is particle or other.destroyed or other.spawning: + continue + + dx = other.position.x - particle.position.x + dy = other.position.y - particle.position.y + dist = sqrt(dx*dx + dy*dy) + + if dist < opts.radius and dist > epsilon: + q = 1 - dist / opts.radius + pressure += q * q // quadratic kernel + presnear += q * q * q // cubic kernel + store neighbor info (other, q, dx/dist, dy/dist) + neighborCount++ + if neighborCount >= opts.maxNeighbors: + break + + // 3. Pressure computation (DDR formula from reference) + P = (pressure - opts.restDensity) * opts.stiffness + Pnear = presnear * opts.nearStiffness + + // 4. Symmetric displacement + for each stored neighbor: + force = P + Pnear * neighbor.q + force = clamp(force, -opts.maxForce, opts.maxForce) + dx = neighbor.dx * force * 0.5 + dy = neighbor.dy * force * 0.5 + + particle.position.x -= dx + particle.position.y -= dy + neighbor.other.position.x += dx + neighbor.other.position.y += dy ``` -Optional only-if-needed additions: +### Constants -```text - FluidPlugin.ts - FluidPluginInstance.ts -``` +- `epsilon = 1e-6` + +### Stability rules + +1. Mai dividere per distanza < epsilon +2. Clampare force con maxForce +3. Skippare particle destroyed/spawning +4. Cap deterministico a maxNeighbors per truncation (non random sample) +5. Non riusare dati di neighbor tra frame diversi --- -## Type design proposal +## Type design ```ts import type { @@ -418,17 +218,6 @@ import type { import type { Fluid } from "./Options/Classes/Fluid.js"; import type { IFluid } from "./Options/Interfaces/IFluid.js"; -export type FluidParticle = InteractivityParticle & { - options: ParticlesFluidOptions; - fluid?: { - prevX?: number; - prevY?: number; - density?: number; - nearDensity?: number; - neighborCount?: number; - }; -}; - export type IParticlesFluidOptions = IInteractivityParticlesOptions & { fluid?: IFluid; }; @@ -436,1033 +225,293 @@ export type IParticlesFluidOptions = IInteractivityParticlesOptions & { export type ParticlesFluidOptions = InteractivityParticlesOptions & { fluid?: Fluid; }; -``` - -Implementation note: - -- keep per-particle temp state compact; -- avoid wide object graphs allocated each frame; -- consider typed scratch buffers if profile justifies. - ---- - -## Loader and registration pattern - -Follow collision-style interactor registration. -```ts -import { type InteractivityEngine, ensureInteractivityPluginLoaded } from "@tsparticles/plugin-interactivity"; -import { type Engine } from "@tsparticles/engine"; -import { FluidInteractor } from "./FluidInteractor.js"; - -declare const __VERSION__: string; - -export async function loadParticlesFluidInteraction(engine: Engine): Promise { - engine.checkVersion(__VERSION__); - - await engine.pluginManager.register((e: InteractivityEngine) => { - ensureInteractivityPluginLoaded(e); - - e.pluginManager.addInteractor?.("particlesFluid", container => { - return Promise.resolve(new FluidInteractor(container)); - }); - }); -} +export type FluidParticle = InteractivityParticle & { + options: ParticlesFluidOptions; +}; ``` -If plugin orchestration is required, same loader can additionally register `FluidPlugin`. +Nessuno stato per-particle richiesto (no prevPosition, no density cache). Ogni frame ricalcola da zero. --- -## Simulation model - -We model fluid cohesion with position-based relaxation inspired by DDR. - -### Phase A - pre-step - -For each eligible particle: - -- store previous position (`prevX`, `prevY`); -- apply optional fluid gravity; -- apply optional pointer impulse; -- optionally predict position (`x += vx`, `y += vy`) when using explicit prediction mode. - -### Phase B - density accumulation - -For each particle `i`: - -- query neighbors within `radius`; -- for each neighbor `j`: - - `r = distance(i, j)`; - - if `r < radius`, compute `q = 1 - r/radius`; - - accumulate: - - `density += q^2` - - `nearDensity += q^3` - -### Phase C - pressure solve - -Compute: - -- `pressure = stiffness * (density - restDensity)` -- `nearPressure = nearStiffness * nearDensity` - -Apply symmetric displacement along normalized neighbor direction: +## Package structure -- displacement factor `D = pressure * q + nearPressure * q^2` -- split half-half between pair to preserve momentum-like behavior. - -### Phase D - constraints - -- clamp to canvas bounds when enabled; -- optional boundary bounce damping. - -### Phase E - velocity reconstruction - -- `vx = x - prevX` -- `vy = y - prevY` -- optional viscosity blend toward neighborhood average velocity. - -### Phase F - iteration - -Repeat phases B-E `iterations` times for improved stability. - ---- - -## Detailed pseudo-code (implementation-grade) - -```ts -for each particle p: - if !isFluidEnabled(p): continue - p.fluid.prevX = p.position.x - p.fluid.prevY = p.position.y - - if fluid.gravity.enable: - p.velocity.y += fluid.gravity.acceleration - - if fluid.pointer.enable and pointer.active: - applyPointerForce(p) - -for iter in [0..fluid.iterations): - for each particle p: - density = 0 - nearDensity = 0 - neighbors = queryCircle(p.position, fluid.radius) - - for each n in neighbors: - if n === p or !isFluidEnabled(n): continue - d = distance(p.position, n.position) - if d <= 0 or d >= fluid.radius: continue - q = 1 - d / fluid.radius - density += q * q - nearDensity += q * q * q - cacheNeighbor(p, n, q, direction) - - pressure = fluid.stiffness * (density - fluid.restDensity) - nearPressure = fluid.nearStiffness * nearDensity - - for each cached neighbor entry: - q = entry.q - dir = entry.direction - force = pressure * q + nearPressure * q * q - force = clamp(force, -fluid.maxForce, fluid.maxForce) - dx = dir.x * force * 0.5 - dy = dir.y * force * 0.5 - entry.neighbor.position.x += dx - entry.neighbor.position.y += dy - p.position.x -= dx - p.position.y -= dy - - applyBounds(p) - -for each particle p: - vx = p.position.x - p.fluid.prevX - vy = p.position.y - p.fluid.prevY - if fluid.viscosity > 0: - [vx, vy] = blendWithNeighborVelocity(p, vx, vy, fluid.viscosity) - p.velocity.x = vx - p.velocity.y = vy ``` - ---- - -## Numerical stability rules - -Hard constraints for implementation: - -1. never divide by near-zero distance without epsilon checks; -2. clamp pressure displacement; -3. skip destroyed/spawning particles; -4. cap neighbors per particle with deterministic truncation; -5. avoid accumulating stale neighbor cache between frames. - -Suggested constants: - -- `epsilon = 1e-6` -- `maxNeighbors = 64` default -- `iterations = 2` default -- `maxForce = 2.5` default - ---- - -## Interactions with existing tsParticles systems - -### `particles.move` - -Fluid should complement movement, not replace it. - -- move gives baseline motion; -- fluid modifies local coherence; -- reconstruction step should not permanently zero stylistic move vectors. - -### `particles.collisions` - -Potential over-constraint when both are strong. - -Recommendations: - -- reduce collision aggressiveness when fluid enabled; -- keep `fluid.stiffness` conservative; -- document presets for coexistence. - -### `particles.attract` - -Attract can create macro-flow direction while fluid preserves body coherence. - -Risk: - -- high attract + high nearStiffness can produce jitter/compression spikes. - -Mitigation: - -- clamp force; -- increase radius moderately; -- lower attract rotation force. - -### External interactivity (`repulse`, `grab`, `push`, `trail`) - -- repulse should produce local wave-like deformation in blob; -- push (new particles) must not break solver when density spikes; -- trail visuals should still render from particle motion deltas. - -### Emitters - -Emitters can feed fluid streams. Need spawn stabilization: - -- newly spawned particles may skip fluid for first frames (`spawning` guard); -- or start with reduced fluid influence ramp. - ---- - -## Bounds behavior - -From source snippet, boundary handling was critical. - -Required behavior when `boundaryClamp` is true: - -- keep particles inside canvas; -- apply soft displacement near edges; -- optional bounce damping on impact. - -Proposed logic: - -```ts -if (x < minX) { - x = minX; - vx *= -boundaryBounce; -} -if (x > maxX) { - x = maxX; - vx *= -boundaryBounce; -} -// same for y +interactions/particles/fluid/ + package.json + tsconfig.base.json + tsconfig.json + tsconfig.types.json + src/ + index.ts + index.lazy.ts + browser.ts + Types.ts + FluidInteractor.ts + Options/ + Classes/ + Fluid.ts + Interfaces/ + IFluid.ts ``` -Optional future option: +### Scaffold notes -- `boundaryMode: "clamp" | "wrap"` (not required v1) - ---- +- `package.json` identico a collisions (solo nome e descrizione diversi) +- `tsconfig.base.json` identico a collisions +- `src/index.ts` segue pattern collisions ma SENZA registrazione OverlapPlugin +- `src/FluidInteractor.ts` estende `ParticlesInteractorBase` -## Pointer coupling (fluid-specific) +### Files NOT to create (vs v2) -The source sample used pointer force to "stir" the fluid. - -We should support a fluid pointer mode independent from standard interactivity mode toggles, so users can get fluid stirring even without repulse config complexity. - -Pointer impulse candidate: - -```ts -const dx = p.x - pointer.x; -const dy = p.y - pointer.y; -const d = Math.hypot(dx, dy); - -if (d > 1 && d < pointerRadius) { - const inv = 1 / d; - const signed = pointerMode === "pull" ? -1 : 1; - p.velocity.x += signed * pointerStrength * dx * inv * (1 - d / pointerRadius); - p.velocity.y += signed * pointerStrength * dy * inv * (1 - d / pointerRadius); -} -``` +| File in v2 | Perché rimosso | +|------------|----------------| +| `Options/Classes/FluidGravity.ts` | Gestito da MovePlugin | +| `Options/Classes/FluidPointer.ts` | Gestito da external repulse | +| `Options/Classes/FluidDebug.ts` | Non richiesto | +| `FluidMath.ts` | Matematica inline nell'interactor | +| `FluidState.ts` | Nessuno stato per-frame necessario | +| `FluidPlugin.ts` / `FluidPluginInstance.ts` | Non serve orchestrazione plugin | +| `rollup.config.js`, `typedoc.json`, `.browserslistrc`, `.npmignore`, `eslint.config.js` | Non servono per package standard | --- -## Option loading classes (pattern) - -Mirror existing packages: - -- interface files in `Options/Interfaces/*` -- classes in `Options/Classes/*` -- `load(...)` methods with null checks and property loaders. - -Example class skeleton: +## FluidInteractor class skeleton ```ts -export class Fluid implements IFluid, IOptionLoader { - enable = false; - radius = 34; - stiffness = 0.45; - nearStiffness = 0.8; - restDensity = 3; - viscosity = 0.08; - iterations = 2; - maxForce = 2.5; - maxNeighbors = 64; - boundaryBounce = 0.2; - boundaryClamp = true; - readonly gravity = new FluidGravity(); - readonly pointer = new FluidPointer(); - readonly debug = new FluidDebug(); - - load(data?: RecursivePartial): void { - if (isNull(data)) { - return; - } +export class FluidInteraction extends ParticlesInteractorBase { + readonly maxDistance: number; - loadProperty(this, "enable", data.enable); - loadNumeric(this, "radius", data.radius); - loadNumeric(this, "stiffness", data.stiffness); - loadNumeric(this, "nearStiffness", data.nearStiffness); - loadNumeric(this, "restDensity", data.restDensity); - loadNumeric(this, "viscosity", data.viscosity); - loadNumeric(this, "iterations", data.iterations); - loadNumeric(this, "maxForce", data.maxForce); - loadNumeric(this, "maxNeighbors", data.maxNeighbors); - loadNumeric(this, "boundaryBounce", data.boundaryBounce); - loadProperty(this, "boundaryClamp", data.boundaryClamp); - - this.gravity.load(data.gravity); - this.pointer.load(data.pointer); - this.debug.load(data.debug); + constructor(container: Container) { + super(container); + this.maxDistance = 0; } -} -``` - ---- - -## `FluidInteractor` responsibilities - -The interactor should do exactly these things: - -1. `isEnabled(particle)` checks `particle.options.fluid?.enable`. -2. `loadParticlesOptions(...)` merges fluid options. -3. `interact(...)` executes fluid pass logic. -4. `maxDistance` returns active radius max for optimization. -5. `clear/init/reset` remain no-op unless internal caches require reset. - -Avoid adding rendering concerns here (no drawing), except debug hooks if plugin architecture requires it. - ---- - -## Per-frame orchestration decision tree - -### Path A (preferred): interactor-only - -Use interactor callbacks with local pass loops. - -Use when: - -- no frame-order artifact is visible; -- performance remains acceptable. - -### Path B: interactor + plugin instance - -Add plugin instance `update(delta)` to manage shared frame state and coordinated passes. - -Use when: - -- we need one global "frame pre-step" and "frame finalize" across all particles; -- interactor call order creates bias. - -### Path C: dedicated plugin package - -Use only when package needs persistent cross-system hooks not fitting interactions domain. - ---- - -## Engine extension policy - -Engine must remain untouched unless a concrete blocker exists. - -Possible blocker patterns: -- no reliable pre-move/post-move ordering; -- no safe way to run one global fluid phase per frame; -- lifecycle missing for reset/resize coordination. + clear(): void { /* noop */ } -If blocker confirmed, propose minimal extension only: - -- deterministic hook ordering labels, or -- one optional frame callback phase. - -No broad refactor request. - ---- - -## Performance budget and profiling plan - -Target scenarios: - -1. 300 particles, desktop: excellent (> 100 fps where possible) -2. 600 particles, desktop: smooth (~60 fps) -3. 1000 particles, desktop: acceptable with low iterations -4. 300 particles, mobile-ish profile: still fluid and stable - -Profile metrics: - -- average frame time; -- 95th percentile frame time; -- neighbor checks per frame; -- allocations per frame; -- NaN incidence (should be zero). - -Guardrails: - -- if `neighborsAvg > 50`, suggest lower radius; -- if frame time spikes > 16ms at 600 particles, degrade via iteration fallback. - -Potential adaptive fallback (optional): - -- dynamic `iterations` reduction when frame load exceeds threshold. - ---- - -## Memory and allocation policy - -Avoid these anti-patterns: - -- creating new arrays inside every neighbor loop; -- storing full neighbor objects for all particles persistently; -- repeated object literal allocation for vector temp math. - -Prefer: - -- reusable scratch arrays; -- fixed temporary vector structs reused per function; -- compact per-particle fluid state fields. - ---- - -## Compatibility matrix (expanded) - -| Feature | Expected status | Notes | -|---------|------------------|-------| -| `move.enable` | Required | Fluid is most meaningful with baseline movement | -| `collisions.enable` | Supported with caveats | May over-constrain; tune both systems | -| `attract.enable` | Supported | Useful for directional flow | -| `links.enable` | Visual only | Can reveal structure, may look non-fluid if too rigid | -| `emitters` | Supported | Great for fluid streams, validate spawn bursts | -| `infection` plugin | Untested initially | Should not conflict logically, but both mutate behavior | -| `trail` plugin | Supported | Good visual enhancement | -| `poisson` plugin | Depends | Sampling pattern may change initial fluid convergence | - ---- + init(): void { /* noop */ } -## Risks and mitigations (expanded) - -### Risk 1 - instability explosions - -Symptoms: - -- particles shoot to infinity; -- velocity spikes and NaN. - -Mitigation: - -- epsilon checks; -- force clamp; -- conservative defaults; -- iterative correction instead of one huge correction. - -### Risk 2 - mushy/no-fluid look - -Symptoms: - -- particles just look like attract/repulse; -- no blob coherence. - -Mitigation: - -- increase near-pressure role; -- add velocity reconstruction; -- tune restDensity and radius balance. - -### Risk 3 - over-clumping - -Symptoms: - -- one giant rigid blob; -- no dynamic deformation. - -Mitigation: - -- lower stiffness/nearStiffness; -- increase baseline move speed slightly; -- add mild viscosity only. - -### Risk 4 - order-dependent anisotropy - -Symptoms: - -- flow bias in iteration order direction. - -Mitigation: - -- pairwise symmetric displacement; -- optional pass randomization or alternate traversal; -- plugin-level orchestration if needed. - -### Risk 5 - perf collapse at high density - -Symptoms: - -- sudden frame drops with emitters or large radius. - -Mitigation: - -- `maxNeighbors` cap; -- reduce iterations; -- optional adaptive degradation. - ---- - -## Test strategy - -### Unit tests - -1. option class loading: - - defaults; - - partial load merge; - - nested gravity/pointer/debug load. -2. helper math: - - `q` computation boundaries; - - force clamp; - - epsilon-safe normalization. -3. guard behavior: - - disabled fluid returns early; - - destroyed/spawning skipped. - -### Integration tests - -1. fluid-only baseline scene: - - no NaN after N frames; - - visible local clustering metrics. -2. fluid + move + emitters: - - stable stream behavior. -3. fluid + collisions: - - no catastrophic jitter. -4. fluid + pointer stirring: - - localized deformation and recovery. - -### Soak test - -- run 20k+ frames simulation in headless mode (where feasible); -- assert no memory trend growth and no invalid values. - ---- - -## Acceptance criteria - -Feature is acceptable for first release when: - -1. visual effect clearly resembles fluid clustering (not plain attraction); -2. no NaN/Infinity positions or velocities under standard presets; -3. defaults are stable with 300-600 particles on common desktop browser; -4. docs include tuning guidance and caveats; -5. no engine changes required, or minimal engine change is justified by reproducible issue. - ---- - -## Suggested presets - -### Water-like - -```json -{ - "particles": { - "fluid": { - "enable": true, - "radius": 30, - "stiffness": 0.32, - "nearStiffness": 0.62, - "restDensity": 2.8, - "viscosity": 0.06, - "iterations": 2, - "maxForce": 2.1 - } + interact(p1: FluidParticle, _interactivityData: IInteractivityData, delta: IDelta): void { + // DDR implementation } -} -``` - -### Gel-like -```json -{ - "particles": { - "fluid": { - "enable": true, - "radius": 36, - "stiffness": 0.52, - "nearStiffness": 1.0, - "restDensity": 3.4, - "viscosity": 0.14, - "iterations": 3, - "maxForce": 2.8 - } + isEnabled(particle: FluidParticle): boolean { + return particle.options.fluid?.enable ?? false; } -} -``` - -### Performance-first -```json -{ - "particles": { - "fluid": { - "enable": true, - "radius": 24, - "stiffness": 0.28, - "nearStiffness": 0.45, - "restDensity": 2.2, - "viscosity": 0.04, - "iterations": 1, - "maxNeighbors": 32, - "maxForce": 1.8 - } + loadParticlesOptions( + options: ParticlesFluidOptions, + ...sources: (RecursivePartial | undefined)[] + ): void { + loadOptionProperty(options, "fluid", Fluid, ...sources); } + + reset(): void { /* noop */ } } ``` ---- +### Why `maxDistance` is a public field (not getter) -## Example usage in tsParticles config - -```ts -import { tsParticles } from "@tsparticles/engine"; -import { loadInteractivityPlugin } from "@tsparticles/plugin-interactivity"; -import { loadParticlesFluidInteraction } from "@tsparticles/interaction-particles-fluid"; - -await loadInteractivityPlugin(tsParticles); -await loadParticlesFluidInteraction(tsParticles); - -await tsParticles.load({ - id: "tsparticles", - options: { - fpsLimit: 120, - particles: { - number: { value: 600 }, - color: { value: "#6ec6ff" }, - size: { value: 2 }, - move: { enable: true, speed: 1.2 }, - collisions: { enable: false }, - fluid: { - enable: true, - radius: 32, - stiffness: 0.4, - nearStiffness: 0.75, - restDensity: 3, - viscosity: 0.1, - iterations: 2, - maxForce: 2.4, - gravity: { enable: true, acceleration: 0.01 }, - pointer: { enable: true, radius: 100, strength: 0.4, mode: "push" } - } - }, - interactivity: { - events: { - onHover: { enable: true, mode: "repulse" } - } - } - } -}); -``` +Follows Collider pattern (`readonly maxDistance`). Set once during interact when options are read. The InteractionManager uses this for spatial grid cell sizing. --- -## Implementation sequence (execution roadmap, non-monolithic) - -This section is intentionally task-oriented so an implementation agent can execute in small, reviewable chunks. - -### Step 0 - repository alignment and constraints - -Goal: - -- confirm package conventions before writing code. - -Actions: - -1. inspect one mature interaction package under `interactions/particles/*` and mirror its file/layout conventions; -2. confirm required build/lint/test commands for that project in Nx; -3. capture exact naming (`particlesFluid`, package name, loader export) and freeze it; -4. confirm semver target remains `4.2.0` under non-breaking assumptions. - -Done when: - -- a short checklist is written in the implementation PR description and naming is no longer changing. -- a short semver note states why the change is still minor and does not require major. - -Stop condition (hard gate): - -- if this step reveals probable breaking changes, STOP before Step 1 and request explicit maintainer confirmation for version strategy change. - -### Step 1 - package skeleton only (no behavior) - -Goal: - -- create package scaffolding and registration entry points without simulation logic. - -Actions: - -1. scaffold `interactions/particles/fluid` with standard package files; -2. add `src/index.ts`, `src/index.lazy.ts`, `src/browser.ts`; -3. implement `loadParticlesFluidInteraction(engine)` with interactor registration; -4. add a noop `FluidInteractor` that compiles and returns early. - -Files expected: - -- package metadata/config files; -- loader files; -- `src/FluidInteractor.ts` placeholder. - -Verification gate: - -- package build passes; -- no runtime errors when loader is called in a minimal demo. - -### Step 2 - options contract and loaders - -Goal: - -- establish stable typed options before solver work. - -Actions: - -1. add interfaces under `Options/Interfaces/*`; -2. add classes under `Options/Classes/*` with `load(...)` semantics aligned to repo patterns; -3. wire `particles.fluid` option merge path in interactor option loading; -4. add unit tests for defaults + partial loading behavior. - -Verification gate: - -- option loader tests pass; -- options are reachable from particle options at runtime. - -### Step 3 - baseline fluid solver (DDR core) - -Goal: - -- implement the minimal useful fluid effect. - -Actions: +## Lifecycle mapping -1. add per-particle transient fluid state (`prevX`, `prevY`, density fields); -2. implement density/near-density accumulation with neighbor query radius; -3. implement pressure + near-pressure pair displacement (symmetric split); -4. reconstruct velocity from corrected position deltas. +| Hook | Called when | Action | +|------|-------------|--------| +| `init()` | Container init | Noop (options read lazily) | +| `isEnabled(p)` | Per-particle, per-frame | `particle.options.fluid?.enable` | +| `interact(p, data, delta)` | Phase 2, per-particle | DDR density → pressure → displacement | +| `clear(p, delta)` | Phase 2, per-particle (always) | Noop | +| `reset(data, p)` | Phase 1, per-particle (if enabled) | Noop | +| `loadParticlesOptions(...)` | Options loading | Load `fluid` key via `loadOptionProperty` | -Hard rules for this step: - -- epsilon-safe normalization; -- clamp force by `maxForce`; -- skip invalid particles (`destroyed`/`spawning` guards). - -Verification gate: - -- visual blob coherence appears in a simple scene; -- no NaN/Infinity in short run (manual + automated assertion). - -### Step 4 - constraints and boundary behavior - -Goal: - -- make solver robust at edges and under high local density. - -Actions: - -1. add `boundaryClamp` and `boundaryBounce` behavior; -2. apply deterministic `maxNeighbors` cap; -3. ensure stale neighbor data is not reused between frames/iterations; -4. add tests for boundary handling and neighbor cap behavior. - -Verification gate: - -- edge collisions do not explode; -- behavior remains stable under emitter bursts near boundaries. - -### Step 5 - viscosity and pointer stirring - -Goal: - -- improve fluid feel and user interaction controls. - -Actions: - -1. add viscosity blend path (configurable by `viscosity`); -2. add fluid-specific pointer push/pull impulse; -3. ensure pointer logic is independent from standard interactivity mode complexity; -4. add integration test scenarios for pointer stirring. - -Verification gate: - -- stirring produces local deformation and smooth recovery; -- default settings remain stable with pointer disabled. - -### Step 6 - interoperability hardening - -Goal: - -- verify coexistence with existing systems and avoid regressions. - -Actions: - -1. validate combinations: fluid+move, fluid+emitters, fluid+repulse, fluid+collisions; -2. document known caveats and safe tuning ranges; -3. if ordering artifacts appear, document evidence and evaluate Path B (plugin instance orchestration). +--- -Verification gate: +## Interaction with existing systems -- compatibility matrix is validated and updated with real observations (not assumptions). +### move plugin -### Step 7 - performance and soak validation +Fluid si basa sul MovePlugin per l'advezione baseline. MovePlugin esegue in Phase 1 (position += velocity * speed), DDR corregge in Phase 2. Consigliato moveSpeed 1-3 per fluid. -Goal: +### collisions -- prove first-release viability under target particle counts. +Possono coesistere. Se entrambi abilitati: +- Collisions gestisce overlap fisici (bounce/absorb/destroy) +- Fluid aggiunge coesione e incompressibilità +- Rischio: over-constraint se stiffness alta. Default conservativo. -Actions: +### attract / repulse (particle-particle) -1. benchmark target scenarios (300/600/1000 desktop, 300 mobile-ish profile); -2. collect frame time, p95, neighbor counts, and allocation trends; -3. run long soak test and assert no NaN + no memory trend drift; -4. tune defaults only after measurements. +Attract può creare flussi macroscopicamente direzionati mentre fluid preserva coerenza locale. Risk: jitter se attract + fluid stiffness sono entrambi alti. -Verification gate: +### external repulse -- default preset meets acceptance thresholds or documented fallback tuning is provided. +Già presente come external interaction. Non serve pointer impulse nel fluid — l'utente usa `interactivity.modes.repulse` per interagire col fluido. -### Step 8 - docs, presets, and release readiness +### gravity (move plugin) -Goal: +Già presente. Non serve gravity nel fluid. -- make feature consumable and maintainable. +### emitters -Actions: +Supportato. Particelle spawnate hanno `spawning = true` → saltate da DDR fino al frame successivo. -1. finalize README (install/load/options/presets/troubleshooting); -2. include three tested presets (water-like, gel-like, performance-first); -3. update changelog/package metadata as required by repo policy; -4. ensure examples compile with the published loader name. +--- -Verification gate: +## Per-frame orchestration -- docs match implemented options exactly; -- no undocumented options remain. +Il DDR è un algoritmo single-pass Gauss-Seidel. Ogni particella, quando `interact()` viene chiamata: +1. Query i vicini nella griglia +2. Accumula densità +3. Applica spostamento simmetrico (modifica sé E il vicino) -### Step 9 - optional advanced path (only with evidence) +Poiché `ParticlesManager.update()` itera le particelle in ordine d'array, quando particle j viene elaborata, particle i (già processata) potrebbe essere già stata spostata. Questo è esattamente il comportamento Gauss-Seidel desiderato. -Goal: +**Non c'è necessità di container plugin per orchestrazione multi-pass** nel v1. -- handle architecture escalation without destabilizing v1. +--- -Actions: +## Performance budget -1. introduce plugin-level orchestration only if Step 6 shows reproducible ordering bias; -2. consider adaptive iterations if Step 7 proves necessary; -3. keep engine changes as last resort with minimal, reproducible justification. +| Scenario | Target | +|----------|--------| +| 300 particles, desktop | > 100 fps | +| 600 particles, desktop | ~ 60 fps | +| 1000 particles, desktop | Accettabile con radius ridotto | +| 300 particles, mobile | > 30 fps | -Verification gate: +### Allocations -- escalation PR includes before/after evidence and does not change public options unexpectedly. +- Zero allocazioni nel main loop: il queryCircle ritorna array esistente della griglia +- Per-particle temporanei su variabili locali (nessun oggetto allocato) +- `maxNeighbors` cap evita array grandi --- -## Logical slicing strategy (recommended) - -To avoid monolithic changes, implementation should be split into clearly isolated logical slices aligned with the steps above. +## Implementation sequence -Important: +### Step 0 — Repository alignment -- these slices are planning/review units only; -- the implementation agent must not commit them and must not open a PR. +1. Ispezionare interactions/particles/collisions come template +2. Confermare naming: `particlesFluid`, `@tsparticles/interaction-particles-fluid`, `loadParticlesFluidInteraction` +3. Verificare comandi build: `pnpm nx build interaction-particles-fluid` -Suggested slices: +### Step 1 — Package skeleton -1. `feat(fluid): scaffold package and loader` -2. `feat(fluid): add options contracts and loader tests` -3. `feat(fluid): implement baseline DDR solver` -4. `feat(fluid): add boundaries, caps, and stability tests` -5. `feat(fluid): add viscosity and pointer stirring` -6. `docs(fluid): presets, compatibility notes, troubleshooting` +1. Scaffold `interactions/particles/fluid/` (package.json, tsconfig.*, src/index.ts, src/index.lazy.ts, src/browser.ts) +2. `FluidInteractor.ts` noop che estende ParticlesInteractorBase +3. Build deve passare -Each slice must include: +### Step 2 — Options contract -- what changed; -- how it was verified; -- measurable impact (visual/perf/stability) when relevant. +1. `Options/Interfaces/IFluid.ts` +2. `Options/Classes/Fluid.ts` con load() +3. `Types.ts` con type extensions +4. `loadParticlesOptions()` nel FluidInteractor ---- - -## Debug and observability proposal +### Step 3 — Baseline DDR solver -Optional debug mode (off by default): +1. Implementare `interact()` con density accumulation + pressure displacement +2. Epsilon safety, force clamp, skip destroyed/spawning +3. Aggiornare `maxDistance` in base a `particle.options.fluid.radius` -- draw support radius around selected particles; -- color by local density; -- show neighbor count in dev logs (sampled); -- periodic warning when clamps trigger excessively. +### Step 4 — Constraints + stabilization -Possible internal counters (dev only): +1. maxNeighbors cap +2. Boundary containment (optional: soft edge repulsion via outModes) +3. Test con 600 particelle, moveSpeed 2 -- `framesWithClampOveruse` -- `maxNeighborsObserved` -- `nanRecoveries` - ---- +### Step 5 — Interoperability -## Documentation deliverables +1. Test combinazioni: fluid+move, fluid+collisions, fluid+emitters, fluid+repulse +2. Documentare caveat trovati -When implementation happens, README should include: +### Step 6 — Docs + presets -1. package intro and purpose; -2. install/load snippets (CDN + ESM/CJS pattern used in repo); -3. option reference table; -4. three presets; -5. compatibility caveats; -6. troubleshooting guide: - - jitter, - - no fluid effect, - - low performance. +1. README con install/load/options +2. Un preset di default funzionante +3. Troubleshooting: "nessun effetto fluido", "jitter", "performance bassa" --- -## Open technical questions (to validate during implementation) - -1. Is interactor callback order stable enough for multi-pass behavior? -2. Should velocity reconstruction happen every iteration or only final pass? -3. Do we need per-particle temporary arrays, or can we compute on the fly cheaply? -4. Is z-layer filtering required to avoid cross-depth fluid coupling? -5. Does collisions + fluid need an explicit "integration mode" option? +## Acceptance criteria -These are not blockers for starting, but should be tracked during implementation. +1. Effetto visivo chiaramente fluido (cluster locali, incompressibilità) — non semplice attract/repulse +2. Nessun NaN/Infinity in posizioni/velocity +3. Default stabili con 300-600 particelle su desktop +4. Nessuna modifica a engine +5. README con opzioni e caveat --- -## Migration fallback criteria to `plugins/fluid` - -Move from interaction package to plugin package only if one or more is true after prototyping: +## Open questions (da validare in implementazione) -1. interactor-only path cannot enforce stable frame sequencing; -2. shared state lifecycle is awkward/impossible in interaction boundary; -3. solver quality strongly depends on global pre/post passes unavailable in current setup. - -If migration is needed, maintain compatibility: - -- keep same option key (`particles.fluid` where possible); -- keep same loader name if feasible; -- provide clear changelog migration notes. +1. Single-pass DDR è sufficiente, o serve multi-pass con plugin? +2. maxNeighbors=64 è un buon default o va alzato/abbassato? +3. Le opzioni di default producono un effetto fluido visualmente distinto? +4. Serve un `minRadius` per evitare interazioni con particelle troppo piccole? --- -## Final considerations and improvement ideas - -This section lists forward-looking enhancements beyond v1. - -### Improvement 1 - adaptive solver quality - -Automatically reduce/increase `iterations` based on frame time budget. - -Benefit: +## Rimosso dal v2: motivazioni dettagliate -- keeps interaction smooth under variable load. +### FluidGravity rimosso -### Improvement 2 - viscosity kernels +La gravity è già gestita dal MovePlugin come opzione built-in (`particles.move.gravity`). Aggiungere una seconda gravity nel fluid causerebbe: +- Doppia applicazione (se entrambe enable) +- Confusione nell'utente (quale gravity usare?) +- Complessità ingiustificata -Introduce selectable viscosity kernels (`linear`, `quadratic`) for different liquid feel. +### FluidPointer rimosso -Benefit: +L'interazione con mouse/pointer è già coperta da: +- `interaction.external.repulse` → spinge via +- `interaction.external.attract` → attrae +- `interaction.external.push` → aggiunge particelle -- broader artistic control without major architecture changes. +Il fluid non deve reimplementare il pointer handling. L'utente configura l'interazione esterna desiderata e il fluid reagisce naturalmente perché le posizioni delle particelle vengono modificate dall'interazione esterna prima che il fluid le corregga. -### Improvement 3 - flow fields coupling +### FluidDebug rimosso -Integrate fluid correction with move path generators (where available). +Non richiesto dall'utente. Se servirà debugging in futuro, si può aggiungere come enhancement separato. -Benefit: +### Velocity reconstruction rimossa -- fluid streams can follow custom paths naturally. +Come analizzato nella sezione "Strategy", la velocity non viene aggiornata dopo DDR. Questo è coerente col pattern del particle-particle repulse. La posizione corretta determina il rendering, e il frame successivo riparte dalla velocity memorizzata (che riflette solo la componente di movimento non-fluid). -### Improvement 4 - vorticity-style enhancement +### boundaryBounce/boundaryClamp rimossi -Add optional swirl preservation term to avoid over-damped look. +tsparticles gestisce già i bordi tramite `particles.move.outModes`. Non serve reimplementare. Se l'utente vuole particelle confinate, usa `outModes: "bounce"` o `"clamp"`. -Benefit: +### Viscosity rimossa dal v1 -- richer visual turbulence at low extra cost. - -### Improvement 5 - density-aware rendering hooks - -Expose local density for color/opacity modulation in compatible plugins. - -Benefit: - -- more convincing liquid visuals without changing physics core. - -### Improvement 6 - deterministic benchmark scene pack - -Ship internal benchmark configs to validate regressions quickly. - -Benefit: - -- easier long-term maintenance and tuning. +La viscosità (media della velocità coi vicini) è un'enhancement che migliora la coesione ma non è necessaria per un primo rilascio funzionante. Sarà rivalutata post-v1. --- -## Go/No-Go for implementation start - -### Go now if - -- we accept interaction-first architecture; -- we accept DDR-inspired approximation over full fluid sim; -- we prioritize stability and integration over perfect physical accuracy. +## Appendice: DDR Formula Reference -### Pause and redesign if +La formula esatta dal reference code (adattata per tsparticles): -- requirement changes to physically accurate CFD-like behavior; -- hard deterministic sync across environments becomes mandatory; -- engine-level ordering guarantees are required before any prototype. +``` +q = 1 - dist / radius -Current recommendation: **Go with `interactions/particles/fluid` prototype path immediately**. +density += q² // density ρ +nearDensity += q³ // near-density ρ̃ ---- +P = (density - restDensity) * 0.5 // pressure (stiffness=0.5) +Pnear = nearDensity * 0.5 // near-pressure (nearStiffness=0.5) -## Quick checklist for the implementing agent +force = P + Pnear * q +dx = (vx / dist) * force * 0.5 // symmetric displacement +dy = (vy / dist) * force * 0.5 +``` -1. Build package skeleton matching existing interactions conventions. -2. Add options contracts and loaders with conservative defaults. -3. Implement baseline DDR-inspired solver with clamps and epsilon safety. -4. Verify with move + emitters + repulse + collisions scenarios. -5. Add README docs and presets. -6. Add tests for loading, guards, and numeric stability. -7. Profile and tune radius/iterations/maxNeighbors defaults. -8. Escalate architecture only if measurable blockers remain. +Dove `(vx, vy) = neighbor.position - particle.position`. -This spec intentionally front-loads analysis so implementation can proceed with fewer architectural reversals. +Lo spostamento è simmetrico: +- particle.position -= (dx, dy) +- neighbor.position += (dx, dy) diff --git a/.planning/handovers/GIF_SHAPE_PLAN.md b/.planning/handovers/GIF_SHAPE_PLAN.md deleted file mode 100644 index d7aafafb5c2..00000000000 --- a/.planning/handovers/GIF_SHAPE_PLAN.md +++ /dev/null @@ -1,1146 +0,0 @@ -# Plan: Separate Animated GIF from Image Shape - -## Summary - -| | | -|---|---| -| **Target** | `@tsparticles/shape-gif` (new), `@tsparticles/shape-image` (modified), `@tsparticles/all` (modified) | -| **Steps** | 6 (1–6) | -| **Type** | Refactor + new package | -| **Load function** | `loadGifShape(engine)` | -| **Files** | ~17 new (shape-gif), ~9 modified (shape-image), ~2 modified (all bundle) | - -### Progress - -- [ ] Step 1: Scaffold `shapes/gif/` (17 files) -- [ ] Step 2: Copy `GifUtils/` from image shape — adapt `drawGif`, remove `loadGifImage` -- [ ] Step 3: Remove GIF from `@tsparticles/shape-image` (9 files) -- [ ] Step 4: Add `@tsparticles/shape-gif` to `@tsparticles/all` bundle -- [ ] Step 5: Build + verify -- [ ] Step 6: Update demo config (`utils/configs/src/g/gifs.ts`) - ---- - -## Goal - -Extract all animated GIF handling from `@tsparticles/shape-image` into a new `@tsparticles/shape-gif` package. -`@tsparticles/shape-image` loses GIF support entirely (static images only — including `.gif` files loaded as static `` elements, without animation decoding). -`@tsparticles/shape-gif` is included in `@tsparticles/all` only (not in slim/full). - -## Architecture - -``` -@tsparticles/shape-image @tsparticles/shape-gif - src/ src/ - Utils.ts (IImage, IParticleImage, IGifShape.ts (shape options) - ImageParticle — NO gif*) types.ts (GifParticle) - ImageDrawer.ts (NO drawGif) GifDrawer.ts (with GIF cache Map) - ImagePreloader.ts GifUtils/ - index.ts (NO loadGifImage) Utils.ts (decodeGIF, drawGif, getGIFLoopAmount) - Options/Classes/Preload.ts ByteStream.ts - (NO gif flag) Constants.ts - Enums/DisposalMethod.ts - Types/GIF.ts, Frame.ts, ... - (*: all gif* fields removed) -``` - -**Key differences in `drawGif` in the copy:** -- Original (in shape-image): reads `particle.image.gifData`, `particle.image.gifLoopCount`, `particle.image.gif` -- New (in shape-gif): reads `particle.gifData` directly, writes `particle.gifFrame/gifTime/gifLoopCount` directly -- The `gifParticle` has `gifData` at the top level, not nested under `image` - ---- - -## Step 1 — Create `shapes/gif/` package scaffold - -### Sub-step 1.1 — Create directory structure - -```bash -mkdir -p shapes/gif/src -``` - ---- - -### Sub-step 1.2 — Create `shapes/gif/package.json` - -```json -{ - "name": "@tsparticles/shape-gif", - "version": "4.2.0", - "description": "tsParticles shape for rendering particles as animated GIFs", - "homepage": "https://particles.js.org", - "scripts": { - "build": "tsparticles-build", - "version": "tsparticles-build -d && git add package.dist.json && tsparticles-build -p -l && git add .", - "prepack": "pnpm run build" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/tsparticles/tsparticles.git", - "directory": "shapes/gif" - }, - "keywords": [ - "front-end", "frontend", "tsparticles", "particles", "particle", - "canvas", "animation", "web", "html5", "css3", "animated", - "background", "confetti", "fireworks", "typescript", "javascript", - "tsparticles-shape", "gif", "animated-gif" - ], - "author": "Matteo Bruni ", - "license": "MIT", - "bugs": { "url": "https://github.com/tsparticles/tsparticles/issues" }, - "prettier": "@tsparticles/prettier-config", - "files": ["dist"], - "sideEffects": false, - "browser": "dist/browser/index.js", - "main": "dist/cjs/index.js", - "module": "dist/esm/index.js", - "types": "dist/types/index.d.ts", - "exports": { - ".": { - "types": "./dist/types/index.d.ts", - "browser": "./dist/browser/index.js", - "import": "./dist/esm/index.js", - "require": "./dist/cjs/index.js", - "default": "./dist/esm/index.js" - }, - "./lazy": { - "types": "./dist/types/index.lazy.d.ts", - "browser": "./dist/browser/index.lazy.js", - "import": "./dist/esm/index.lazy.js", - "require": "./dist/cjs/index.lazy.js", - "default": "./dist/esm/index.lazy.js" - }, - "./package.json": "./dist/package.json" - }, - "peerDependencies": { "@tsparticles/engine": "workspace:*" }, - "devDependencies": { - "@tsparticles/cli-build": "workspace:*", - "@tsparticles/engine": "workspace:*" - }, - "publishConfig": { "access": "public", "directory": "dist", "linkDirectory": true }, - "type": "module" -} -``` - ---- - -### Sub-step 1.3 — Create `shapes/gif/package.dist.json` - -```json -{ - "name": "@tsparticles/shape-gif", - "version": "4.2.0", - "description": "tsParticles gif shape", - "homepage": "https://particles.js.org", - "repository": { "type": "git", "url": "git+https://github.com/tsparticles/tsparticles.git", "directory": "shapes/gif" }, - "keywords": [ - "front-end", "frontend", "tsparticles", "particles", "particle", - "canvas", "jsparticles", "xparticles", "particles-js", "particles.js", - "particles-ts", "particles.ts", "typescript", "javascript", - "animation", "web", "html5", "web-design", "webdesign", - "css", "html", "css3", "animated", "background", "tsparticles-shape" - ], - "author": "Matteo Bruni ", - "license": "MIT", - "bugs": { "url": "https://github.com/tsparticles/tsparticles/issues" }, - "sideEffects": false, - "jsdelivr": "tsparticles.shape.gif.min.js", - "unpkg": "tsparticles.shape.gif.min.js", - "browser": "browser/index.js", - "main": "cjs/index.js", - "module": "esm/index.js", - "types": "types/index.d.ts", - "exports": { - ".": { - "types": "./types/index.d.ts", "browser": "./browser/index.js", - "import": "./esm/index.js", "require": "./cjs/index.js", - "default": "./esm/index.js" - }, - "./lazy": { - "types": "./types/index.lazy.d.ts", "browser": "./browser/index.lazy.js", - "import": "./esm/index.lazy.js", "require": "./cjs/index.lazy.js", - "default": "./esm/index.lazy.js" - }, - "./package.json": "./package.json" - }, - "peerDependencies": { "@tsparticles/engine": "4.2.0" }, - "publishConfig": { "access": "public" }, - "type": "module" -} -``` - ---- - -### Sub-step 1.4 — Create `shapes/gif/.browserslistrc` - -``` -extends @tsparticles/browserslist-config -``` - ---- - -### Sub-step 1.5 — Create `shapes/gif/eslint.config.js` - -```javascript -import tsParticlesESLintConfig from "@tsparticles/eslint-config"; -import { defineConfig } from "eslint/config"; - -export default defineConfig([ - tsParticlesESLintConfig, -]); -``` - ---- - -### Sub-step 1.6 — Create `shapes/gif/rollup.config.js` - -```javascript -import { loadParticlesShape } from "@tsparticles/rollup-plugin"; -import { fileURLToPath } from "node:url"; -import fs from "fs-extra"; -import path from "node:path"; - -const __filename = fileURLToPath(import.meta.url), - __dirname = path.dirname(__filename), - rootPkgPath = path.join(__dirname, "package.json"), - pkg = await fs.readJson(rootPkgPath), - version = pkg.version; - -export default loadParticlesShape({ - moduleName: "gif", - shapeName: "Gif", - version, - dir: __dirname, - progress: false, -}); -``` - ---- - -### Sub-step 1.7 — Create TypeScript config files - -Create `shapes/gif/tsconfig.base.json`: -```json -{ - "extends": "@tsparticles/tsconfig/dist/tsconfig.base.json", - "compilerOptions": { "rootDir": "./src" }, - "include": ["./src"] -} -``` - -Create `shapes/gif/tsconfig.json`: -```json -{ - "extends": ["./tsconfig.base.json", "@tsparticles/tsconfig/dist/tsconfig.json"], - "compilerOptions": { "outDir": "./dist/cjs" } -} -``` - -Create `shapes/gif/tsconfig.browser.json`: -```json -{ - "extends": ["./tsconfig.base.json", "@tsparticles/tsconfig/dist/tsconfig.browser.json"], - "compilerOptions": { "outDir": "./dist/browser" } -} -``` - -Create `shapes/gif/tsconfig.module.json`: -```json -{ - "extends": ["./tsconfig.base.json", "@tsparticles/tsconfig/dist/tsconfig.module.json"], - "compilerOptions": { "outDir": "./dist/esm" } -} -``` - -Create `shapes/gif/tsconfig.types.json`: -```json -{ - "extends": ["./tsconfig.base.json", "@tsparticles/tsconfig/dist/tsconfig.types.json"], - "compilerOptions": { "outDir": "./dist/types" } -} -``` - ---- - -### Sub-step 1.8 — Create `shapes/gif/typedoc.json` - -```json -{ - "projectDocuments": ["../markdown/**/*.md"], - "entryPoints": ["./src/"], - "entryPointStrategy": "expand", - "name": "tsParticles GIF Shape", - "includeVersion": true, - "hideGenerator": true, - "out": "./docs", - "validation": { "invalidLink": true, "notDocumented": true } -} -``` - ---- - -### Sub-step 1.9 — Create `shapes/gif/src/IGifShape.ts` - -```typescript -import type { IShapeValues } from "@tsparticles/engine"; - -export interface IGifShape extends IShapeValues { - height: number; - loopCount?: number; - name?: string; - src: string; - width: number; -} -``` - ---- - -### Sub-step 1.10 — Create `shapes/gif/src/types.ts` - -```typescript -import type { Particle } from "@tsparticles/engine"; -import type { GIF } from "./GifUtils/Types/GIF.js"; - -export type GifParticle = Particle & { - gifData?: GIF; - gifFrame: number; - gifLoopCount: number; - gifTime: number; -}; -``` - ---- - -### Sub-step 1.11 — Create `shapes/gif/src/GifDrawer.ts` - -```typescript -import type { Container, IShapeDrawData, IShapeDrawer } from "@tsparticles/engine"; -import { getGIFLoopAmount } from "./GifUtils/Utils.js"; -import type { GifParticle } from "./types.js"; -import type { IGifShape } from "./IGifShape.js"; -import { decodeGIF, drawGif } from "./GifUtils/Utils.js"; -import type { GIF } from "./GifUtils/Types/GIF.js"; - -export class GifDrawer implements IShapeDrawer { - readonly #container: Container; - readonly #gifCache: Map; - - constructor(container: Container) { - this.#container = container; - this.#gifCache = new Map(); - } - - async draw(data: IShapeDrawData): Promise { - const { context, opacity } = data; - - if (!data.particle.gifData) return; - - context.globalAlpha = opacity; - await drawGif(data, this.#container.canvas.render.settings); - context.globalAlpha = 1; - } - - async particleInit(container: Container, particle: GifParticle): Promise { - const shapeData = particle.shapeData as IGifShape | undefined; - - if (!shapeData?.src) return; - - let gifData = this.#gifCache.get(shapeData.src); - - if (!gifData) { - particle.gifData = undefined; - particle.gifFrame = 0; - particle.gifTime = 0; - particle.gifLoopCount = 0; - - gifData = await decodeGIF(shapeData.src, { colorSpace: "srgb" }); - this.#gifCache.set(shapeData.src, gifData); - } - - particle.gifData = gifData; - particle.gifFrame = 0; - particle.gifTime = 0; - particle.gifLoopCount = getGIFLoopAmount(gifData); - - if (particle.gifLoopCount === 0) { - particle.gifLoopCount = Number.POSITIVE_INFINITY; - } - - if (shapeData.loopCount !== undefined) { - particle.gifLoopCount = shapeData.loopCount; - } - } - - destroy(): void { - this.#gifCache.clear(); - } -} -``` - ---- - -### Sub-step 1.12 — Create `shapes/gif/src/index.ts` - -```typescript -import type { Engine } from "@tsparticles/engine"; -import { GifDrawer } from "./GifDrawer.js"; - -export async function loadGifShape(engine: Engine): Promise { - engine.checkVersion("4.2.0"); - - await engine.pluginManager.register(e => { - e.pluginManager.addShape(["gif", "gifs"], container => - Promise.resolve(new GifDrawer(container)), - ); - }); -} -``` - ---- - -### Sub-step 1.13 — Create `shapes/gif/src/index.lazy.ts` - -```typescript -import type { Engine } from "@tsparticles/engine"; - -export async function loadGifShape(engine: Engine): Promise { - engine.checkVersion("4.2.0"); - - await engine.pluginManager.register(async e => { - const { GifDrawer } = await import("./GifDrawer.js"); - - e.pluginManager.addShape(["gif", "gifs"], container => - Promise.resolve(new GifDrawer(container)), - ); - }); -} -``` - ---- - -### Sub-step 1.14 — Create `shapes/gif/src/browser.ts` - -```typescript -import { loadGifShape } from "./index.js"; - -const globalObject = globalThis as typeof globalThis & { - __tsParticlesInternals?: Record; - loadGifShape?: typeof loadGifShape; -}; -globalObject.__tsParticlesInternals = globalObject.__tsParticlesInternals ?? {}; -globalObject.loadGifShape = loadGifShape; - -export * from "./index.js"; -``` - ---- - -## Step 2 — Copy `GifUtils/` from `shapes/image/src/GifUtils/` to `shapes/gif/src/GifUtils/` - -### Sub-step 2.1 — Copy all files (preserve directory tree) - -Copy the entire `GifUtils/` directory from `shapes/image/src/GifUtils/` to `shapes/gif/src/GifUtils/`: - -```bash -cp -r shapes/image/src/GifUtils/ shapes/gif/src/GifUtils/ -``` - -Files copied: -``` -GifUtils/ - ByteStream.ts - Constants.ts - Utils.ts - Enums/DisposalMethod.ts - Types/GIF.ts - Types/Frame.ts - Types/ApplicationExtension.ts - Types/GIFDataHeaders.ts - Types/GIFProgressCallbackFunction.ts - Types/PlainTextData.ts -``` - ---- - -### Sub-step 2.2 — Fix import in copied `GifUtils/Utils.ts` - -In `shapes/gif/src/GifUtils/Utils.ts`, replace the import at line 3: - -**Before:** -```typescript -import { type IImage, type ImageParticle, loadImage } from "../Utils.js"; -``` - -**After:** -```typescript -import type { GifParticle } from "../types.js"; -``` - ---- - -### Sub-step 2.3 — Remove `loadGifImage` function from copied `GifUtils/Utils.ts` - -Delete the entire `loadGifImage` function (the last function in the file, lines 755-777 in the original). The function signature is: - -```typescript -export async function loadGifImage(image: IImage, canvasSettings: CanvasRenderingContext2DSettings): Promise { -``` - -This function is replaced by the `GifDrawer.particleInit()` method. - ---- - -### Sub-step 2.4 — Replace `drawGif` function in copied `GifUtils/Utils.ts` - -Replace the entire `drawGif` function (line 641 onward in the original) with the adapted version below. - -The original function accesses GIF data via `particle.image.gifData`. The new version accesses it via `particle.gifData` directly. - -**Full replacement for `drawGif`:** - -```typescript -export function drawGif(data: IShapeDrawData, canvasSettings?: CanvasRenderingContext2DSettings): void { - const { context, radius, particle, delta } = data, - gifData = particle.gifData; - - if (!gifData) { - return; - } - - const offscreenCanvas = new OffscreenCanvas(gifData.width, gifData.height), - offscreenContext = offscreenCanvas.getContext("2d", canvasSettings); - - if (!offscreenContext) { - throw new Error("could not create offscreen canvas context"); - } - - offscreenContext.imageSmoothingQuality = "low"; - offscreenContext.imageSmoothingEnabled = false; - - offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height); - - let frameIndex = particle.gifFrame ?? defaultFrame; - - const pos = { x: -gifData.width * half, y: -gifData.height * half }, - frame = gifData.frames[frameIndex]!; - - particle.gifTime ??= initialTime; - - if (!frame.bitmap) { - return; - } - - context.scale(radius / gifData.width, radius / gifData.height); - - switch (frame.disposalMethod) { - case DisposalMethod.UndefinedA: - case DisposalMethod.UndefinedB: - case DisposalMethod.UndefinedC: - case DisposalMethod.UndefinedD: - case DisposalMethod.Replace: - offscreenContext.drawImage(frame.bitmap, frame.left, frame.top); - context.drawImage(offscreenCanvas, pos.x, pos.y); - offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height); - break; - case DisposalMethod.Combine: - offscreenContext.drawImage(frame.bitmap, frame.left, frame.top); - context.drawImage(offscreenCanvas, pos.x, pos.y); - break; - case DisposalMethod.RestoreBackground: - offscreenContext.drawImage(frame.bitmap, frame.left, frame.top); - context.drawImage(offscreenCanvas, pos.x, pos.y); - offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height); - if (!gifData.globalColorTable.length) { - offscreenContext.putImageData(gifData.frames[firstIndex]!.image, pos.x + frame.left, pos.y + frame.top); - } else { - offscreenContext.putImageData(gifData.backgroundImage, pos.x, pos.y); - } - break; - case DisposalMethod.RestorePrevious: - { - const previousImageData = offscreenContext.getImageData( - originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height, - ); - - offscreenContext.drawImage(frame.bitmap, frame.left, frame.top); - context.drawImage(offscreenCanvas, pos.x, pos.y); - offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height); - offscreenContext.putImageData(previousImageData, originPoint.x, originPoint.y); - } - break; - } - - particle.gifTime += delta.value; - - if (particle.gifTime > frame.delayTime) { - particle.gifTime -= frame.delayTime; - - if (++frameIndex >= gifData.frames.length) { - if (--particle.gifLoopCount <= defaultLoopCount) { - return; - } - - frameIndex = firstIndex; - offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height); - } - - particle.gifFrame = frameIndex; - } - - context.scale(gifData.width / radius, gifData.height / radius); -} -``` - -**Key differences from the original:** -1. `IShapeDrawData` instead of `IShapeDrawData` -2. `gifData = particle.gifData` instead of `image = particle.image` -3. `if (!gifData)` instead of `if (!image?.gifData || !image.gif)` -4. All `image.gifData.*` replaced with `gifData.*` -5. Removed `particle.gifLoopCount ??= image.gifLoopCount ?? defaultLoopCount` (loop count is set by `particleInit()`) -6. All `image.*` references removed - ---- - -### Sub-step 2.5 — Verify no broken imports in copied GifUtils files - -Check that all imported paths resolve correctly: - -| File | Imports | Status | -|---|---|---| -| `ByteStream.ts` | `./Types/GIFDataHeaders.js` | ✅ Internal | -| `Constants.ts` | none | ✅ | -| `Utils.ts` | `@tsparticles/engine`, `../types.js`, `./Constants.js`, `./ByteStream.js`, `./Enums/DisposalMethod.js`, `./Types/GIF.js`, `./Types/GIFDataHeaders.js`, `./Types/GIFProgressCallbackFunction.js` | ✅ Fixed in 2.2 | -| `Enums/DisposalMethod.ts` | none | ✅ | -| `Types/GIF.ts` | `@tsparticles/engine`, `./ApplicationExtension.js`, `./Frame.js` | ✅ | -| `Types/Frame.ts` | `@tsparticles/engine`, `../Enums/DisposalMethod.js`, `./PlainTextData.js` | ✅ | -| `Types/GIFProgressCallbackFunction.ts` | `@tsparticles/engine` | ✅ | -| `Types/PlainTextData.ts` | `@tsparticles/engine` | ✅ | -| Others | none | ✅ | - ---- - -## Step 3 — Remove GIF from `@tsparticles/shape-image` - -### Sub-step 3.1 — Delete `GifUtils/` directory from shape-image - -```bash -rm -rf shapes/image/src/GifUtils/ -``` - ---- - -### Sub-step 3.2 — Clean `shapes/image/src/Utils.ts` - -**Remove import (line 2):** -```typescript -import type { GIF } from "./GifUtils/Types/GIF.js"; -``` - -**Remove 3 fields from `IImage` interface (lines 18-20):** -```typescript -gif: boolean; -gifData?: GIF; -gifLoopCount?: number; -``` - -**Remove 3 fields from `IParticleImage` interface (lines 37-39):** -```typescript -gif: boolean; -gifData?: GIF; -gifLoopCount?: number; -``` - -**Remove 3 fields from `ImageParticle` type (lines 50-52):** -```typescript -gifFrame?: number; -gifLoopCount?: number; -gifTime?: number; -``` - -After removal, `ImageParticle` becomes: -```typescript -export type ImageParticle = Particle & { - image?: IParticleImage; -}; -``` - -**Remove `gif` field from `replaceImageColor` return value (line 166):** -```typescript -// REMOVE this line from the IParticleImage literal: -gif: imageData.gif, -``` - ---- - -### Sub-step 3.3 — Clean `shapes/image/src/IImageShape.ts` - -**Remove `gif: boolean;` (line 4).** - -After: -```typescript -export interface IImageShape extends IShapeValues { - height: number; - name: string; - replaceColor: boolean; - src: string; - width: number; -} -``` - ---- - -### Sub-step 3.4 — Clean `shapes/image/src/Options/Classes/Preload.ts` - -**Remove `gif` property (line 5):** -```typescript -gif = false; // REMOVE -``` - -**Remove `loadProperty(this, "gif", data.gif);` (line 17):** - -After: -```typescript -export class Preload implements IPreload, IOptionLoader { - height?: number; - name?: string; - replaceColor?: boolean; - src = ""; - width?: number; - - load(data?: RecursivePartial): void { - if (isNull(data)) { return; } - - loadProperty(this, "height", data.height); - loadProperty(this, "name", data.name); - loadProperty(this, "replaceColor", data.replaceColor); - loadProperty(this, "src", data.src); - loadProperty(this, "width", data.width); - } -} -``` - ---- - -### Sub-step 3.5 — Clean `shapes/image/src/Options/Interfaces/IPreload.ts` - -**Remove `gif: boolean` and its JSDoc (lines 3-5):** - -After: -```typescript -/** The preload image options */ -export interface IPreload { - /** The image height */ - height?: number; - /** The image name */ - name?: string; - /** Replace the color with the particle color */ - replaceColor?: boolean; - /** The image source */ - src: string; - /** The image width */ - width?: number; -} -``` - ---- - -### Sub-step 3.6 — Clean `shapes/image/src/ImageDrawer.ts` - -**Remove import (line 12):** -```typescript -import { drawGif } from "./GifUtils/Utils.js"; -``` - -**In `draw()` — remove GIF branch (lines 48-49):** - -Before: -```typescript - if (image.gif && image.gifData) { - drawGif(data, this.#container.canvas.render.settings); - } else if (element) { -``` - -After: -```typescript - if (element) { -``` - -**In `particleInit()` — remove gif fields from `imageRes` (lines 158-160):** - -Before: -```typescript - gif: image.gif, - gifData: image.gifData, - gifLoopCount: image.gifLoopCount, -``` - -After: (these 3 lines removed entirely) - -**In `#loadImageShape()` — remove `gif` from preload data (line 196):** - -Before: -```typescript - await this.#engine.loadImage(container, { - gif: imageShape.gif, - name: imageShape.name, -``` - -After: -```typescript - await this.#engine.loadImage(container, { - name: imageShape.name, -``` - ---- - -### Sub-step 3.7 — Clean `shapes/image/src/index.ts` - -**Remove import (line 6):** -```typescript -import { loadGifImage } from "./GifUtils/Utils.js"; -``` - -**Remove `gif` field from `IImage` literal (line 48):** -```typescript -gif: data.gif, // REMOVE -``` - -**Remove `data.gif` check and `loadGifImage` branch (lines 64-65):** - -Before: -```typescript - if (data.gif) { - imageFunc = (img): Promise => loadGifImage(img, { colorSpace: "srgb" }); - } else if (data.replaceColor) { -``` - -After: -```typescript - if (data.replaceColor) { -``` - ---- - -### Sub-step 3.8 — Clean `shapes/image/src/index.lazy.ts` - -**Remove `gif` field from `IImage` literal (line 45):** -```typescript -gif: data.gif, // REMOVE -``` - -**Remove `data.gif` check and dynamic `loadGifImage` import (lines 61-64):** - -Before: -```typescript - if (data.gif) { - const { loadGifImage } = await import("./GifUtils/Utils.js"); - - imageFunc = (img): Promise => loadGifImage(img, { colorSpace: "srgb" }); - } else if (data.replaceColor) { -``` - -After: -```typescript - if (data.replaceColor) { -``` - ---- - -### Sub-step 3.9 — Verify no GIF references remain in shape-image - -```bash -grep -rn "gif\|Gif\|GIF\|GifUtils" shapes/image/src/ --include="*.ts" | grep -v node_modules -``` - -Expected output: no matches. - ---- - -## Step 4 — Add `@tsparticles/shape-gif` to `@tsparticles/all` bundle - -### Sub-step 4.1 — Edit `bundles/all/package.json` - -Add to `dependencies` (in alphabetical order, after `"@tsparticles/shape-cog"`): -```json -"@tsparticles/shape-gif": "workspace:*", -``` - ---- - -### Sub-step 4.2 — Edit `bundles/all/package.dist.json` - -If `bundles/all/package.dist.json` exists, add the same dependency. If not, skip this substep. - ---- - -### Sub-step 4.3 — Edit `bundles/all/src/index.ts` - -**Add import** (in alphabetical order, after existing imports): -```typescript -import { loadGifShape } from "@tsparticles/shape-gif"; -``` - -**Add load call** inside the `Promise.all` shapes block (after `loadSquircleShape(e),`): -```typescript -loadGifShape(e), -``` - -The shapes block becomes: -```typescript - loadArrowShape(e), - loadCardsShape(e), - loadCogShape(e), - loadGifShape(e), - loadHeartShape(e), - loadInfinityShape(e), - loadMatrixShape(e), - loadPathShape(e), - loadRibbonShape(e), - loadRoundedPolygonShape(e), - loadRoundedRectShape(e), - loadSpiralShape(e), - loadSquircleShape(e), -``` - ---- - -### Sub-step 4.4 — Verify `bundles/all/src/bundle.ts` and `bundles/all/src/browser.ts` - -Both files re-export from `./index.js` which will now export `loadGifShape`. No changes needed. - ---- - -## Step 5 — Verify build - -### Sub-step 5.1 — Link workspace packages - -```bash -pnpm install -``` - -### Sub-step 5.2 — Build all packages - -```bash -pnpm run build:ci -``` - -### Sub-step 5.3 — Check for errors - -Look for: -- TypeScript errors in `shapes/gif/src/` -- TypeScript errors in `shapes/image/src/` (no more GIF references) -- TypeScript errors in `bundles/all/src/` (missing import) -- Rollup/webpack bundle errors - -### Sub-step 5.4 — If errors, build individually for debugging - -```bash -pnpm nx run shape-gif:build -pnpm nx run shape-image:build -pnpm nx run all:build -``` - -### Sub-step 5.5 — Verify bundle output - -Check that `shapes/gif/dist/` exists with this structure: -``` -shapes/gif/dist/ - browser/index.js - browser/index.lazy.js - browser/browser.js - cjs/index.js - cjs/index.lazy.js - esm/index.js - esm/index.lazy.js - types/index.d.ts - types/index.lazy.d.ts - types/GifDrawer.d.ts - types/IGifShape.d.ts - types/types.d.ts - types/GifUtils/... -``` - ---- - -## Step 6 — Update demo config - -### Sub-step 6.1 — Edit `utils/configs/src/g/gifs.ts` - -Change from old image+gif config to new gif shape config: - -**Before:** -```typescript -shape: { - options: { - image: { - gif: true, - height: 200, - src: "https://particles.js.org/images/mario.gif", - width: 200, - }, - }, - type: "image", -}, -``` - -**After:** -```typescript -shape: { - options: { - gif: { - height: 200, - src: "https://particles.js.org/images/mario.gif", - width: 200, - }, - }, - type: "gif", -}, -``` - ---- - -## Execution Order - -``` -Step 1 (create shapes/gif/ scaffold) - ├── 1.1 mkdir - ├── 1.2 package.json - ├── 1.3 package.dist.json - ├── 1.4 .browserslistrc - ├── 1.5 eslint.config.js - ├── 1.6 rollup.config.js - ├── 1.7 tsconfig files (5 files) - ├── 1.8 typedoc.json - ├── 1.9 IGifShape.ts - ├── 1.10 types.ts - ├── 1.11 GifDrawer.ts - ├── 1.12 index.ts - ├── 1.13 index.lazy.ts - └── 1.14 browser.ts - -Step 2 (copy GifUtils) - ├── 2.1 cp -r all files - ├── 2.2 fix import in Utils.ts - ├── 2.3 remove loadGifImage - ├── 2.4 replace drawGif - └── 2.5 verify imports - -Step 3 (remove GIF from shape-image) - ├── 3.1 rm -rf GifUtils/ - ├── 3.2 Utils.ts - ├── 3.3 IImageShape.ts - ├── 3.4 Preload.ts - ├── 3.5 IPreload.ts - ├── 3.6 ImageDrawer.ts - ├── 3.7 index.ts - ├── 3.8 index.lazy.ts - └── 3.9 grep verify - -Step 4 (add to @tsparticles/all) - ├── 4.1 package.json - ├── 4.2 package.dist.json - ├── 4.3 src/index.ts - └── 4.4 verify bundle/browser exports - -Step 5 (build & verify) - ├── 5.1 pnpm install - ├── 5.2 pnpm run build:ci - ├── 5.3 check errors - ├── 5.4 debug build per-package - └── 5.5 verify dist/ output - -Step 6 (demo config) - └── 6.1 utils/configs/src/g/gifs.ts -``` - -**Dependencies between steps:** -- Steps 1-3 can run in parallel (different package dirs) -- Step 4 requires Step 1 (package must exist for pnpm workspace resolution to work) -- Step 5 requires Steps 1-4 -- Step 6 can run anytime after Step 3 - ---- - -## Cheat sheet: Exact changes by file - -### New files (17) - -| # | File | Sub-step | -|---|---|---| -| 1 | `shapes/gif/package.json` | 1.2 | -| 2 | `shapes/gif/package.dist.json` | 1.3 | -| 3 | `shapes/gif/.browserslistrc` | 1.4 | -| 4 | `shapes/gif/eslint.config.js` | 1.5 | -| 5 | `shapes/gif/rollup.config.js` | 1.6 | -| 6 | `shapes/gif/tsconfig.base.json` | 1.7 | -| 7 | `shapes/gif/tsconfig.json` | 1.7 | -| 8 | `shapes/gif/tsconfig.browser.json` | 1.7 | -| 9 | `shapes/gif/tsconfig.module.json` | 1.7 | -| 10 | `shapes/gif/tsconfig.types.json` | 1.7 | -| 11 | `shapes/gif/typedoc.json` | 1.8 | -| 12 | `shapes/gif/src/IGifShape.ts` | 1.9 | -| 13 | `shapes/gif/src/types.ts` | 1.10 | -| 14 | `shapes/gif/src/GifDrawer.ts` | 1.11 | -| 15 | `shapes/gif/src/index.ts` | 1.12 | -| 16 | `shapes/gif/src/index.lazy.ts` | 1.13 | -| 17 | `shapes/gif/src/browser.ts` | 1.14 | - -### Copied files (10) - -| File | From | To | Edit needed | -|---|---|---|---| -| `GifUtils/ByteStream.ts` | `shapes/image/src/GifUtils/` | `shapes/gif/src/GifUtils/` | No | -| `GifUtils/Constants.ts` | same | same | No | -| `GifUtils/Utils.ts` | same | same | **Yes** — 2.2, 2.3, 2.4 | -| `GifUtils/Enums/DisposalMethod.ts` | same | same | No | -| `GifUtils/Types/GIF.ts` | same | same | No | -| `GifUtils/Types/Frame.ts` | same | same | No | -| `GifUtils/Types/ApplicationExtension.ts` | same | same | No | -| `GifUtils/Types/GIFDataHeaders.ts` | same | same | No | -| `GifUtils/Types/GIFProgressCallbackFunction.ts` | same | same | No | -| `GifUtils/Types/PlainTextData.ts` | same | same | No | - -### Modified files (10) - -| File | Change | Sub-step | -|---|---|---| -| `shapes/image/src/Utils.ts` | Remove GIF import + 7 gif fields + 1 `gif:` in literal | 3.2 | -| `shapes/image/src/IImageShape.ts` | Remove `gif: boolean` | 3.3 | -| `shapes/image/src/Options/Classes/Preload.ts` | Remove `gif` property + `loadProperty("gif")` | 3.4 | -| `shapes/image/src/Options/Interfaces/IPreload.ts` | Remove `gif: boolean` | 3.5 | -| `shapes/image/src/ImageDrawer.ts` | Remove drawGif import, if-gif branch, gif fields in particleInit, gif in loadImageShape | 3.6 | -| `shapes/image/src/index.ts` | Remove loadGifImage import, gif literal field, if(data.gif) branch | 3.7 | -| `shapes/image/src/index.lazy.ts` | Same as index.ts | 3.8 | -| `bundles/all/package.json` | Add `@tsparticles/shape-gif` dependency | 4.1 | -| `bundles/all/src/index.ts` | Add import + loadGifShape call | 4.3 | -| `utils/configs/src/g/gifs.ts` | Change `type: "image"` + gif opts → `type: "gif"` | 6.1 | - -### Deleted (1) - -| Path | Sub-step | -|---|---| -| `shapes/image/src/GifUtils/` | 3.1 | - -### No changes needed - -| Reason | | -|---|---| -| `pnpm-workspace.yaml` | Already includes `shapes/*` | -| `bundles/all/src/bundle.ts` | Re-exports from `./index.js` | -| `bundles/all/src/browser.ts` | Re-exports from `./index.js` | -| `shapes/image/src/types.ts` | No GIF-specific types | -| `shapes/image/src/ImagePreloader.ts` | No GIF-specific code | -| `shapes/image/src/ImagePreloaderInstance.ts` | No GIF-specific code | -| `shapes/image/src/browser.ts` | No GIF-specific code | - ---- - -## Testing - -Run the demo server after implementation: - -```bash -cd demo/vanilla && pnpm start -``` - -Navigate to the "Gifs" demo preset. Particles should render as animated GIFs using the new `type: "gif"` shape. diff --git a/CHANGELOG.md b/CHANGELOG.md index 57e9a58599a..adef7f0178b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,35 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) +* fixed some issues in deepExtend ([9d9fc9f](https://github.com/tsparticles/tsparticles/commit/9d9fc9f39fadf8d9df96f6e7b7cc8cde98e3ae21)) +* improved deepExtend ([af9d1d9](https://github.com/tsparticles/tsparticles/commit/af9d1d9f146cdc994945abf5dbc32cffbeea7b08)) + + +### Features + +* added new draw layer system ([5442bbb](https://github.com/tsparticles/tsparticles/commit/5442bbb848fde8aa7d622c5c751c7c32570d78a9)) +* added new hdr precision system ([627ec92](https://github.com/tsparticles/tsparticles/commit/627ec92fbd68cd4e776f1d912ff2ca0166603dec)) +* added new particle modifier system ([da3038e](https://github.com/tsparticles/tsparticles/commit/da3038e49b41a1025f945342603abc64a6a9bb45)) +* added support for canvas background and custom draw callbacks ([fb71bd9](https://github.com/tsparticles/tsparticles/commit/fb71bd974412666b0207b3823a81f078090357a9)) +* added support for canvas background mask and custom draw callbacks ([74582bc](https://github.com/tsparticles/tsparticles/commit/74582bc064f174523fa8b22697b83523cccb9a19)) +* improved support for canvas background and custom draw callbacks ([a88798c](https://github.com/tsparticles/tsparticles/commit/a88798c72ff3c981fa8828bb9b51cd6f29245463)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) +### Features + +- added hdr precision enhancement ([#FEATURE-F](https://github.com/tsparticles/tsparticles/issues/F)) + ### Bug Fixes - fixed docs, fixes [#5862](https://github.com/tsparticles/tsparticles/issues/5862) ([bb0cb44](https://github.com/tsparticles/tsparticles/commit/bb0cb44e380f70f9ef58565123edf072664c6a32)) diff --git a/bundles/all/CHANGELOG.md b/bundles/all/CHANGELOG.md index 269ea87854e..b3cb57b18ef 100644 --- a/bundles/all/CHANGELOG.md +++ b/bundles/all/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/all + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/all diff --git a/bundles/all/package.dist.json b/bundles/all/package.dist.json index be72b30df9d..0723d058f44 100644 --- a/bundles/all/package.dist.json +++ b/bundles/all/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/all", - "version": "4.2.1", + "version": "4.3.0", "description": "All-inclusive tsParticles bundle — all engine packages, plugins, interactions, presets, shapes, updaters, effects, paths, emitters, sounds, and palettes in one dependency. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "repository": { @@ -105,84 +105,85 @@ "./package.json": "./package.json" }, "dependencies": { - "@tsparticles/effect-bubble": "4.2.1", - "@tsparticles/effect-filter": "4.2.1", - "@tsparticles/effect-particles": "4.2.1", - "@tsparticles/effect-shadow": "4.2.1", - "@tsparticles/effect-trail": "4.2.1", - "@tsparticles/engine": "4.2.1", - "@tsparticles/interaction-external-cannon": "4.2.1", - "@tsparticles/interaction-external-particle": "4.2.1", - "@tsparticles/interaction-external-pop": "4.2.1", - "@tsparticles/interaction-light": "4.2.1", - "@tsparticles/interaction-particles-repulse": "4.2.1", - "@tsparticles/path-branches": "4.2.1", - "@tsparticles/path-brownian": "4.2.1", - "@tsparticles/path-curl-noise": "4.2.1", - "@tsparticles/path-curves": "4.2.1", - "@tsparticles/path-fractal-noise": "4.2.1", - "@tsparticles/path-grid": "4.2.1", - "@tsparticles/path-levy": "4.2.1", - "@tsparticles/path-perlin-noise": "4.2.1", - "@tsparticles/path-polygon": "4.2.1", - "@tsparticles/path-random": "4.2.1", - "@tsparticles/path-simplex-noise": "4.2.1", - "@tsparticles/path-spiral": "4.2.1", - "@tsparticles/path-svg": "4.2.1", - "@tsparticles/path-zig-zag": "4.2.1", - "@tsparticles/plugin-background-mask": "4.2.1", - "@tsparticles/plugin-canvas-mask": "4.2.1", - "@tsparticles/plugin-easing-back": "4.2.1", - "@tsparticles/plugin-easing-bounce": "4.2.1", - "@tsparticles/plugin-easing-circ": "4.2.1", - "@tsparticles/plugin-easing-cubic": "4.2.1", - "@tsparticles/plugin-easing-elastic": "4.2.1", - "@tsparticles/plugin-easing-expo": "4.2.1", - "@tsparticles/plugin-easing-gaussian": "4.2.1", - "@tsparticles/plugin-easing-linear": "4.2.1", - "@tsparticles/plugin-easing-quart": "4.2.1", - "@tsparticles/plugin-easing-quint": "4.2.1", - "@tsparticles/plugin-easing-sigmoid": "4.2.1", - "@tsparticles/plugin-easing-sine": "4.2.1", - "@tsparticles/plugin-easing-smoothstep": "4.2.1", - "@tsparticles/plugin-emitters-shape-canvas": "4.2.1", - "@tsparticles/plugin-emitters-shape-path": "4.2.1", - "@tsparticles/plugin-emitters-shape-polygon": "4.2.1", - "@tsparticles/plugin-export-image": "4.2.1", - "@tsparticles/plugin-export-json": "4.2.1", - "@tsparticles/plugin-export-video": "4.2.1", - "@tsparticles/plugin-hsv-color": "4.2.1", - "@tsparticles/plugin-hwb-color": "4.2.1", - "@tsparticles/plugin-infection": "4.2.1", - "@tsparticles/plugin-lab-color": "4.2.1", - "@tsparticles/plugin-lch-color": "4.2.1", - "@tsparticles/plugin-manual-particles": "4.2.1", - "@tsparticles/plugin-motion": "4.2.1", - "@tsparticles/plugin-named-color": "4.2.1", - "@tsparticles/plugin-oklab-color": "4.2.1", - "@tsparticles/plugin-oklch-color": "4.2.1", - "@tsparticles/plugin-poisson-disc": "4.2.1", - "@tsparticles/plugin-polygon-mask": "4.2.1", - "@tsparticles/plugin-responsive": "4.2.1", - "@tsparticles/plugin-sounds": "4.2.1", - "@tsparticles/plugin-themes": "4.2.1", - "@tsparticles/plugin-trail": "4.2.1", - "@tsparticles/plugin-zoom": "4.2.1", - "@tsparticles/shape-arrow": "4.2.1", - "@tsparticles/shape-cards": "4.2.1", - "@tsparticles/shape-cog": "4.2.1", - "@tsparticles/shape-heart": "4.2.1", - "@tsparticles/shape-infinity": "4.2.1", - "@tsparticles/shape-matrix": "4.2.1", - "@tsparticles/shape-path": "4.2.1", - "@tsparticles/shape-ribbon": "4.2.1", - "@tsparticles/shape-rounded-polygon": "4.2.1", - "@tsparticles/shape-rounded-rect": "4.2.1", - "@tsparticles/shape-spiral": "4.2.1", - "@tsparticles/shape-squircle": "4.2.1", - "@tsparticles/updater-gradient": "4.2.1", - "@tsparticles/updater-orbit": "4.2.1", - "tsparticles": "4.2.1" + "@tsparticles/effect-bubble": "4.3.0", + "@tsparticles/effect-filter": "4.3.0", + "@tsparticles/effect-particles": "4.3.0", + "@tsparticles/effect-shadow": "4.3.0", + "@tsparticles/effect-trail": "4.3.0", + "@tsparticles/engine": "4.3.0", + "@tsparticles/interaction-external-cannon": "4.3.0", + "@tsparticles/interaction-external-particle": "4.3.0", + "@tsparticles/interaction-external-pop": "4.3.0", + "@tsparticles/interaction-light": "4.3.0", + "@tsparticles/interaction-particles-repulse": "4.3.0", + "@tsparticles/path-branches": "4.3.0", + "@tsparticles/path-brownian": "4.3.0", + "@tsparticles/path-curl-noise": "4.3.0", + "@tsparticles/path-curves": "4.3.0", + "@tsparticles/path-fractal-noise": "4.3.0", + "@tsparticles/path-grid": "4.3.0", + "@tsparticles/path-levy": "4.3.0", + "@tsparticles/path-perlin-noise": "4.3.0", + "@tsparticles/path-polygon": "4.3.0", + "@tsparticles/path-random": "4.3.0", + "@tsparticles/path-simplex-noise": "4.3.0", + "@tsparticles/path-spiral": "4.3.0", + "@tsparticles/path-svg": "4.3.0", + "@tsparticles/path-zig-zag": "4.3.0", + "@tsparticles/plugin-background-mask": "4.3.0", + "@tsparticles/plugin-canvas-mask": "4.3.0", + "@tsparticles/plugin-easing-back": "4.3.0", + "@tsparticles/plugin-easing-bounce": "4.3.0", + "@tsparticles/plugin-easing-circ": "4.3.0", + "@tsparticles/plugin-easing-cubic": "4.3.0", + "@tsparticles/plugin-easing-elastic": "4.3.0", + "@tsparticles/plugin-easing-expo": "4.3.0", + "@tsparticles/plugin-easing-gaussian": "4.3.0", + "@tsparticles/plugin-easing-linear": "4.3.0", + "@tsparticles/plugin-easing-quart": "4.3.0", + "@tsparticles/plugin-easing-quint": "4.3.0", + "@tsparticles/plugin-easing-sigmoid": "4.3.0", + "@tsparticles/plugin-easing-sine": "4.3.0", + "@tsparticles/plugin-easing-smoothstep": "4.3.0", + "@tsparticles/plugin-emitters-shape-canvas": "4.3.0", + "@tsparticles/plugin-emitters-shape-path": "4.3.0", + "@tsparticles/plugin-emitters-shape-polygon": "4.3.0", + "@tsparticles/plugin-export-image": "4.3.0", + "@tsparticles/plugin-export-json": "4.3.0", + "@tsparticles/plugin-export-video": "4.3.0", + "@tsparticles/plugin-hsv-color": "4.3.0", + "@tsparticles/plugin-hwb-color": "4.3.0", + "@tsparticles/plugin-infection": "4.3.0", + "@tsparticles/plugin-lab-color": "4.3.0", + "@tsparticles/plugin-lch-color": "4.3.0", + "@tsparticles/plugin-manual-particles": "4.3.0", + "@tsparticles/plugin-motion": "4.3.0", + "@tsparticles/plugin-named-color": "4.3.0", + "@tsparticles/plugin-oklab-color": "4.3.0", + "@tsparticles/plugin-oklch-color": "4.3.0", + "@tsparticles/plugin-poisson-disc": "4.3.0", + "@tsparticles/plugin-polygon-mask": "4.3.0", + "@tsparticles/plugin-responsive": "4.3.0", + "@tsparticles/plugin-sounds": "4.3.0", + "@tsparticles/plugin-themes": "4.3.0", + "@tsparticles/plugin-trail": "4.3.0", + "@tsparticles/plugin-zoom": "4.3.0", + "@tsparticles/shape-arrow": "4.3.0", + "@tsparticles/shape-cards": "4.3.0", + "@tsparticles/shape-cog": "4.3.0", + "@tsparticles/shape-gif": "4.3.0", + "@tsparticles/shape-heart": "4.3.0", + "@tsparticles/shape-infinity": "4.3.0", + "@tsparticles/shape-matrix": "4.3.0", + "@tsparticles/shape-path": "4.3.0", + "@tsparticles/shape-ribbon": "4.3.0", + "@tsparticles/shape-rounded-polygon": "4.3.0", + "@tsparticles/shape-rounded-rect": "4.3.0", + "@tsparticles/shape-spiral": "4.3.0", + "@tsparticles/shape-squircle": "4.3.0", + "@tsparticles/updater-gradient": "4.3.0", + "@tsparticles/updater-orbit": "4.3.0", + "tsparticles": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/bundles/all/package.json b/bundles/all/package.json index 5323e41a3c9..90176b54429 100644 --- a/bundles/all/package.json +++ b/bundles/all/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/all", - "version": "4.2.1", + "version": "4.3.0", "description": "All-inclusive tsParticles bundle — all engine packages, plugins, interactions, presets, shapes, updaters, effects, paths, emitters, sounds, and palettes in one dependency. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "scripts": { @@ -181,6 +181,7 @@ "@tsparticles/shape-arrow": "workspace:*", "@tsparticles/shape-cards": "workspace:*", "@tsparticles/shape-cog": "workspace:*", + "@tsparticles/shape-gif": "workspace:*", "@tsparticles/shape-heart": "workspace:*", "@tsparticles/shape-infinity": "workspace:*", "@tsparticles/shape-matrix": "workspace:*", diff --git a/bundles/all/src/index.ts b/bundles/all/src/index.ts index f961bd81668..42852662b0f 100644 --- a/bundles/all/src/index.ts +++ b/bundles/all/src/index.ts @@ -34,6 +34,7 @@ import { loadExternalPopInteraction } from "@tsparticles/interaction-external-po import { loadFilterEffect } from "@tsparticles/effect-filter"; import { loadFractalNoisePath } from "@tsparticles/path-fractal-noise"; import { loadFull } from "tsparticles"; +import { loadGifShape } from "@tsparticles/shape-gif"; import { loadGradientUpdater } from "@tsparticles/updater-gradient"; import { loadGridPath } from "@tsparticles/path-grid"; import { loadHeartShape } from "@tsparticles/shape-heart"; @@ -177,6 +178,7 @@ export async function loadAll(engine: Engine): Promise { loadArrowShape(e), loadCardsShape(e), loadCogShape(e), + loadGifShape(e), loadHeartShape(e), loadInfinityShape(e), loadMatrixShape(e), diff --git a/bundles/basic/CHANGELOG.md b/bundles/basic/CHANGELOG.md index 5903d92d59f..b16e8e09f93 100644 --- a/bundles/basic/CHANGELOG.md +++ b/bundles/basic/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/basic + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/basic diff --git a/bundles/basic/package.dist.json b/bundles/basic/package.dist.json index 70602eee65f..9151d7ce094 100644 --- a/bundles/basic/package.dist.json +++ b/bundles/basic/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/basic", - "version": "4.2.1", + "version": "4.3.0", "description": "Basic tsParticles bundle — minimal core engine with only the essential features for fast, lightweight particle animations. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "repository": { @@ -105,17 +105,17 @@ "./package.json": "./package.json" }, "dependencies": { - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-blend": "4.2.1", - "@tsparticles/plugin-hex-color": "4.2.1", - "@tsparticles/plugin-hsl-color": "4.2.1", - "@tsparticles/plugin-move": "4.2.1", - "@tsparticles/plugin-rgb-color": "4.2.1", - "@tsparticles/shape-circle": "4.2.1", - "@tsparticles/updater-opacity": "4.2.1", - "@tsparticles/updater-out-modes": "4.2.1", - "@tsparticles/updater-paint": "4.2.1", - "@tsparticles/updater-size": "4.2.1" + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-blend": "4.3.0", + "@tsparticles/plugin-hex-color": "4.3.0", + "@tsparticles/plugin-hsl-color": "4.3.0", + "@tsparticles/plugin-move": "4.3.0", + "@tsparticles/plugin-rgb-color": "4.3.0", + "@tsparticles/shape-circle": "4.3.0", + "@tsparticles/updater-opacity": "4.3.0", + "@tsparticles/updater-out-modes": "4.3.0", + "@tsparticles/updater-paint": "4.3.0", + "@tsparticles/updater-size": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/bundles/basic/package.json b/bundles/basic/package.json index a2bb81f3d6f..2e63b9bee42 100644 --- a/bundles/basic/package.json +++ b/bundles/basic/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/basic", - "version": "4.2.1", + "version": "4.3.0", "description": "Basic tsParticles bundle — minimal core engine with only the essential features for fast, lightweight particle animations. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "scripts": { diff --git a/bundles/confetti/CHANGELOG.md b/bundles/confetti/CHANGELOG.md index 49de02cadcb..eab3909f278 100644 --- a/bundles/confetti/CHANGELOG.md +++ b/bundles/confetti/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/confetti + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/confetti diff --git a/bundles/confetti/package.dist.json b/bundles/confetti/package.dist.json index 2b539f5b3df..3cfa644d6d5 100644 --- a/bundles/confetti/package.dist.json +++ b/bundles/confetti/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/confetti", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles confetti bundle — easily create confetti, confetti cannon, confetti explosions, confetti falling, and confetti parade animations with presets. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "repository": { @@ -105,22 +105,22 @@ "./package.json": "./package.json" }, "dependencies": { - "@tsparticles/basic": "4.2.1", - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-emitters": "4.2.1", - "@tsparticles/plugin-motion": "4.2.1", - "@tsparticles/shape-cards": "4.2.1", - "@tsparticles/shape-emoji": "4.2.1", - "@tsparticles/shape-heart": "4.2.1", - "@tsparticles/shape-image": "4.2.1", - "@tsparticles/shape-polygon": "4.2.1", - "@tsparticles/shape-square": "4.2.1", - "@tsparticles/shape-star": "4.2.1", - "@tsparticles/updater-life": "4.2.1", - "@tsparticles/updater-roll": "4.2.1", - "@tsparticles/updater-rotate": "4.2.1", - "@tsparticles/updater-tilt": "4.2.1", - "@tsparticles/updater-wobble": "4.2.1" + "@tsparticles/basic": "4.3.0", + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-emitters": "4.3.0", + "@tsparticles/plugin-motion": "4.3.0", + "@tsparticles/shape-cards": "4.3.0", + "@tsparticles/shape-emoji": "4.3.0", + "@tsparticles/shape-heart": "4.3.0", + "@tsparticles/shape-image": "4.3.0", + "@tsparticles/shape-polygon": "4.3.0", + "@tsparticles/shape-square": "4.3.0", + "@tsparticles/shape-star": "4.3.0", + "@tsparticles/updater-life": "4.3.0", + "@tsparticles/updater-roll": "4.3.0", + "@tsparticles/updater-rotate": "4.3.0", + "@tsparticles/updater-tilt": "4.3.0", + "@tsparticles/updater-wobble": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/bundles/confetti/package.json b/bundles/confetti/package.json index 1b5e9976a5d..f3cf8852c19 100644 --- a/bundles/confetti/package.json +++ b/bundles/confetti/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/confetti", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles confetti bundle — easily create confetti, confetti cannon, confetti explosions, confetti falling, and confetti parade animations with presets. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "scripts": { diff --git a/bundles/fireworks/CHANGELOG.md b/bundles/fireworks/CHANGELOG.md index e40a2b28520..c96e6d992d1 100644 --- a/bundles/fireworks/CHANGELOG.md +++ b/bundles/fireworks/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/fireworks + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/fireworks diff --git a/bundles/fireworks/package.dist.json b/bundles/fireworks/package.dist.json index bb7a110093a..81d48b7da91 100644 --- a/bundles/fireworks/package.dist.json +++ b/bundles/fireworks/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/fireworks", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles fireworks bundle — easily create spectacular fireworks and fountain particle effects with built-in presets. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "repository": { @@ -105,17 +105,17 @@ "./package.json": "./package.json" }, "dependencies": { - "@tsparticles/basic": "4.2.1", - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-blend": "4.2.1", - "@tsparticles/plugin-emitters": "4.2.1", - "@tsparticles/plugin-emitters-shape-square": "4.2.1", - "@tsparticles/plugin-sounds": "4.2.1", - "@tsparticles/shape-line": "4.2.1", - "@tsparticles/updater-destroy": "4.2.1", - "@tsparticles/updater-life": "4.2.1", - "@tsparticles/updater-paint": "4.2.1", - "@tsparticles/updater-rotate": "4.2.1" + "@tsparticles/basic": "4.3.0", + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-blend": "4.3.0", + "@tsparticles/plugin-emitters": "4.3.0", + "@tsparticles/plugin-emitters-shape-square": "4.3.0", + "@tsparticles/plugin-sounds": "4.3.0", + "@tsparticles/shape-line": "4.3.0", + "@tsparticles/updater-destroy": "4.3.0", + "@tsparticles/updater-life": "4.3.0", + "@tsparticles/updater-paint": "4.3.0", + "@tsparticles/updater-rotate": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/bundles/fireworks/package.json b/bundles/fireworks/package.json index c37c86d4361..13c07db7376 100644 --- a/bundles/fireworks/package.json +++ b/bundles/fireworks/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/fireworks", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles fireworks bundle — easily create spectacular fireworks and fountain particle effects with built-in presets. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "scripts": { diff --git a/bundles/full/CHANGELOG.md b/bundles/full/CHANGELOG.md index cd7d96899cb..290a25c5370 100644 --- a/bundles/full/CHANGELOG.md +++ b/bundles/full/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package tsparticles + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package tsparticles diff --git a/bundles/full/package.dist.json b/bundles/full/package.dist.json index d7eeefec233..52de6982c4a 100644 --- a/bundles/full/package.dist.json +++ b/bundles/full/package.dist.json @@ -1,6 +1,6 @@ { "name": "tsparticles", - "version": "4.2.1", + "version": "4.3.0", "description": "Full-featured tsParticles bundle — create stunning particle, confetti and fireworks animations with all official plugins and presets included. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "repository": { @@ -105,20 +105,20 @@ "./package.json": "./package.json" }, "dependencies": { - "@tsparticles/engine": "4.2.1", - "@tsparticles/interaction-external-drag": "4.2.1", - "@tsparticles/interaction-external-trail": "4.2.1", - "@tsparticles/plugin-absorbers": "4.2.1", - "@tsparticles/plugin-emitters": "4.2.1", - "@tsparticles/plugin-emitters-shape-circle": "4.2.1", - "@tsparticles/plugin-emitters-shape-square": "4.2.1", - "@tsparticles/shape-text": "4.2.1", - "@tsparticles/slim": "4.2.1", - "@tsparticles/updater-destroy": "4.2.1", - "@tsparticles/updater-roll": "4.2.1", - "@tsparticles/updater-tilt": "4.2.1", - "@tsparticles/updater-twinkle": "4.2.1", - "@tsparticles/updater-wobble": "4.2.1" + "@tsparticles/engine": "4.3.0", + "@tsparticles/interaction-external-drag": "4.3.0", + "@tsparticles/interaction-external-trail": "4.3.0", + "@tsparticles/plugin-absorbers": "4.3.0", + "@tsparticles/plugin-emitters": "4.3.0", + "@tsparticles/plugin-emitters-shape-circle": "4.3.0", + "@tsparticles/plugin-emitters-shape-square": "4.3.0", + "@tsparticles/shape-text": "4.3.0", + "@tsparticles/slim": "4.3.0", + "@tsparticles/updater-destroy": "4.3.0", + "@tsparticles/updater-roll": "4.3.0", + "@tsparticles/updater-tilt": "4.3.0", + "@tsparticles/updater-twinkle": "4.3.0", + "@tsparticles/updater-wobble": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/bundles/full/package.json b/bundles/full/package.json index 0a0e53db5d8..ab35508f5ca 100644 --- a/bundles/full/package.json +++ b/bundles/full/package.json @@ -1,6 +1,6 @@ { "name": "tsparticles", - "version": "4.2.1", + "version": "4.3.0", "description": "Full-featured tsParticles bundle — create stunning particle, confetti and fireworks animations with all official plugins and presets included. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "scripts": { diff --git a/bundles/particles/CHANGELOG.md b/bundles/particles/CHANGELOG.md index 830b1456b26..ab3ea11f748 100644 --- a/bundles/particles/CHANGELOG.md +++ b/bundles/particles/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/particles + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/particles diff --git a/bundles/particles/package.dist.json b/bundles/particles/package.dist.json index 53118e27166..aa469503a80 100644 --- a/bundles/particles/package.dist.json +++ b/bundles/particles/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/particles", - "version": "4.2.1", + "version": "4.3.0", "description": "Minimal tsParticles particles bundle — lightweight particle engine without confetti or fireworks extras. Perfect for pure particle backgrounds. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "repository": { @@ -81,11 +81,11 @@ "./package.json": "./package.json" }, "dependencies": { - "@tsparticles/basic": "4.2.1", - "@tsparticles/engine": "4.2.1", - "@tsparticles/interaction-particles-collisions": "4.2.1", - "@tsparticles/interaction-particles-links": "4.2.1", - "@tsparticles/plugin-interactivity": "4.2.1" + "@tsparticles/basic": "4.3.0", + "@tsparticles/engine": "4.3.0", + "@tsparticles/interaction-particles-collisions": "4.3.0", + "@tsparticles/interaction-particles-links": "4.3.0", + "@tsparticles/plugin-interactivity": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/bundles/particles/package.json b/bundles/particles/package.json index e7891930d1b..f0abf3f7582 100644 --- a/bundles/particles/package.json +++ b/bundles/particles/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/particles", - "version": "4.2.1", + "version": "4.3.0", "description": "Minimal tsParticles particles bundle — lightweight particle engine without confetti or fireworks extras. Perfect for pure particle backgrounds. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "scripts": { diff --git a/bundles/pjs/CHANGELOG.md b/bundles/pjs/CHANGELOG.md index 9835253a58f..b78c0deaf85 100644 --- a/bundles/pjs/CHANGELOG.md +++ b/bundles/pjs/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/pjs + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/pjs diff --git a/bundles/pjs/package.dist.json b/bundles/pjs/package.dist.json index 5f8dd431783..d43b3f5c90a 100644 --- a/bundles/pjs/package.dist.json +++ b/bundles/pjs/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/pjs", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles particles.js compatibility layer — drop-in replacement for particles.js with full API compatibility and enhanced features. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "repository": { @@ -98,9 +98,9 @@ "./package.json": "./package.json" }, "dependencies": { - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-responsive": "4.2.1", - "tsparticles": "4.2.1" + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-responsive": "4.3.0", + "tsparticles": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/bundles/pjs/package.json b/bundles/pjs/package.json index b619918a4fd..37ad84163f7 100644 --- a/bundles/pjs/package.json +++ b/bundles/pjs/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/pjs", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles particles.js compatibility layer — drop-in replacement for particles.js with full API compatibility and enhanced features. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "scripts": { diff --git a/bundles/ribbons/CHANGELOG.md b/bundles/ribbons/CHANGELOG.md index c91041c0c23..448edde6a31 100644 --- a/bundles/ribbons/CHANGELOG.md +++ b/bundles/ribbons/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/ribbons + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) ### Bug Fixes diff --git a/bundles/ribbons/package.dist.json b/bundles/ribbons/package.dist.json index 7dec5aaf98f..5798c6f8ea6 100644 --- a/bundles/ribbons/package.dist.json +++ b/bundles/ribbons/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/ribbons", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles ribbons bundle — easily create animated ribbons, ribbon bursts and ribbon falling effects. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "repository": { @@ -102,13 +102,13 @@ "./package.json": "./package.json" }, "dependencies": { - "@tsparticles/basic": "4.2.1", - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-emitters": "4.2.1", - "@tsparticles/plugin-emitters-shape-square": "4.2.1", - "@tsparticles/plugin-motion": "4.2.1", - "@tsparticles/shape-ribbon": "4.2.1", - "@tsparticles/updater-life": "4.2.1" + "@tsparticles/basic": "4.3.0", + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-emitters": "4.3.0", + "@tsparticles/plugin-emitters-shape-square": "4.3.0", + "@tsparticles/plugin-motion": "4.3.0", + "@tsparticles/shape-ribbon": "4.3.0", + "@tsparticles/updater-life": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/bundles/ribbons/package.json b/bundles/ribbons/package.json index f72b85f51e7..4b6226decc6 100644 --- a/bundles/ribbons/package.json +++ b/bundles/ribbons/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/ribbons", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles ribbons bundle — easily create animated ribbons, ribbon bursts and ribbon falling effects. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "scripts": { diff --git a/bundles/slim/CHANGELOG.md b/bundles/slim/CHANGELOG.md index 73bf63388dc..2e556c287f6 100644 --- a/bundles/slim/CHANGELOG.md +++ b/bundles/slim/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/slim + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/slim diff --git a/bundles/slim/package.dist.json b/bundles/slim/package.dist.json index 55d6fe0a124..3a04c6a96e4 100644 --- a/bundles/slim/package.dist.json +++ b/bundles/slim/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/slim", - "version": "4.2.1", + "version": "4.3.0", "description": "Slim tsParticles bundle — core engine with essential plugins, presets, and interactions for lightweight particle animations. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "repository": { @@ -105,34 +105,34 @@ "./package.json": "./package.json" }, "dependencies": { - "@tsparticles/basic": "4.2.1", - "@tsparticles/engine": "4.2.1", - "@tsparticles/interaction-external-attract": "4.2.1", - "@tsparticles/interaction-external-bounce": "4.2.1", - "@tsparticles/interaction-external-bubble": "4.2.1", - "@tsparticles/interaction-external-connect": "4.2.1", - "@tsparticles/interaction-external-destroy": "4.2.1", - "@tsparticles/interaction-external-grab": "4.2.1", - "@tsparticles/interaction-external-parallax": "4.2.1", - "@tsparticles/interaction-external-pause": "4.2.1", - "@tsparticles/interaction-external-push": "4.2.1", - "@tsparticles/interaction-external-remove": "4.2.1", - "@tsparticles/interaction-external-repulse": "4.2.1", - "@tsparticles/interaction-external-slow": "4.2.1", - "@tsparticles/interaction-particles-attract": "4.2.1", - "@tsparticles/interaction-particles-collisions": "4.2.1", - "@tsparticles/interaction-particles-links": "4.2.1", - "@tsparticles/plugin-easing-quad": "4.2.1", - "@tsparticles/plugin-interactivity": "4.2.1", - "@tsparticles/shape-emoji": "4.2.1", - "@tsparticles/shape-image": "4.2.1", - "@tsparticles/shape-line": "4.2.1", - "@tsparticles/shape-polygon": "4.2.1", - "@tsparticles/shape-square": "4.2.1", - "@tsparticles/shape-star": "4.2.1", - "@tsparticles/updater-life": "4.2.1", - "@tsparticles/updater-paint": "4.2.1", - "@tsparticles/updater-rotate": "4.2.1" + "@tsparticles/basic": "4.3.0", + "@tsparticles/engine": "4.3.0", + "@tsparticles/interaction-external-attract": "4.3.0", + "@tsparticles/interaction-external-bounce": "4.3.0", + "@tsparticles/interaction-external-bubble": "4.3.0", + "@tsparticles/interaction-external-connect": "4.3.0", + "@tsparticles/interaction-external-destroy": "4.3.0", + "@tsparticles/interaction-external-grab": "4.3.0", + "@tsparticles/interaction-external-parallax": "4.3.0", + "@tsparticles/interaction-external-pause": "4.3.0", + "@tsparticles/interaction-external-push": "4.3.0", + "@tsparticles/interaction-external-remove": "4.3.0", + "@tsparticles/interaction-external-repulse": "4.3.0", + "@tsparticles/interaction-external-slow": "4.3.0", + "@tsparticles/interaction-particles-attract": "4.3.0", + "@tsparticles/interaction-particles-collisions": "4.3.0", + "@tsparticles/interaction-particles-links": "4.3.0", + "@tsparticles/plugin-easing-quad": "4.3.0", + "@tsparticles/plugin-interactivity": "4.3.0", + "@tsparticles/shape-emoji": "4.3.0", + "@tsparticles/shape-image": "4.3.0", + "@tsparticles/shape-line": "4.3.0", + "@tsparticles/shape-polygon": "4.3.0", + "@tsparticles/shape-square": "4.3.0", + "@tsparticles/shape-star": "4.3.0", + "@tsparticles/updater-life": "4.3.0", + "@tsparticles/updater-paint": "4.3.0", + "@tsparticles/updater-rotate": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/bundles/slim/package.json b/bundles/slim/package.json index 7c35ac0b88e..3a573c6e09c 100644 --- a/bundles/slim/package.json +++ b/bundles/slim/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/slim", - "version": "4.2.1", + "version": "4.3.0", "description": "Slim tsParticles bundle — core engine with essential plugins, presets, and interactions for lightweight particle animations. Ready to use components available for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "scripts": { diff --git a/cli/commands/build-bundle-rollup/CHANGELOG.md b/cli/commands/build-bundle-rollup/CHANGELOG.md index 9bca3d82a93..ed6965dd2b6 100644 --- a/cli/commands/build-bundle-rollup/CHANGELOG.md +++ b/cli/commands/build-bundle-rollup/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-command-build-bundle-rollup diff --git a/cli/commands/build-bundle-rollup/package.json b/cli/commands/build-bundle-rollup/package.json index 7c65816a8c5..e91003cae85 100644 --- a/cli/commands/build-bundle-rollup/package.json +++ b/cli/commands/build-bundle-rollup/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-build-bundle-rollup", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -34,7 +34,7 @@ "commander": "^15" }, "dependencies": { - "@swc/core": "^1.15.41", + "@swc/core": "^1.15.43", "@tsparticles/depcruise-config": "workspace:*", "@tsparticles/eslint-config": "workspace:*", "@tsparticles/prettier-config": "workspace:*", @@ -43,7 +43,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "klaw": "^4.1.0", @@ -53,17 +53,17 @@ "prettier-plugin-multiline-arrays": "^4.1.9", "prompts": "^2.4.2", "rimraf": "^6.1.3", - "rollup": "^4.62.0", + "rollup": "^4.62.2", "swc-loader": "^0.2.7", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" }, "devDependencies": { "@types/estree": "^1.0.9", "@types/klaw": "^3.0.7", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/prompts": "^2.4.9", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/build-bundle-webpack/CHANGELOG.md b/cli/commands/build-bundle-webpack/CHANGELOG.md index 210672a55c1..7e2efa36779 100644 --- a/cli/commands/build-bundle-webpack/CHANGELOG.md +++ b/cli/commands/build-bundle-webpack/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-command-build-bundle-webpack diff --git a/cli/commands/build-bundle-webpack/package.json b/cli/commands/build-bundle-webpack/package.json index 9e3746fd5d2..3f2da77786a 100644 --- a/cli/commands/build-bundle-webpack/package.json +++ b/cli/commands/build-bundle-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-build-bundle-webpack", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -34,7 +34,7 @@ "commander": "^15" }, "dependencies": { - "@swc/core": "^1.15.41", + "@swc/core": "^1.15.43", "@tsparticles/depcruise-config": "workspace:*", "@tsparticles/eslint-config": "workspace:*", "@tsparticles/prettier-config": "workspace:*", @@ -43,7 +43,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "klaw": "^4.1.0", @@ -55,16 +55,16 @@ "rimraf": "^6.1.3", "swc-loader": "^0.2.7", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1", + "typescript-eslint": "^8.62.0", "webpack": "^5.107.2" }, "devDependencies": { "@types/estree": "^1.0.9", "@types/klaw": "^3.0.7", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/prompts": "^2.4.9", "@types/webpack-env": "^1.18.8", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/build-circular-deps/CHANGELOG.md b/cli/commands/build-circular-deps/CHANGELOG.md index 14d55a77c58..1af01df1aba 100644 --- a/cli/commands/build-circular-deps/CHANGELOG.md +++ b/cli/commands/build-circular-deps/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-command-build-circular-deps diff --git a/cli/commands/build-circular-deps/package.json b/cli/commands/build-circular-deps/package.json index a7725ea1c6f..6a0ad3a95d3 100644 --- a/cli/commands/build-circular-deps/package.json +++ b/cli/commands/build-circular-deps/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-build-circular-deps", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -34,7 +34,7 @@ "commander": "^15" }, "dependencies": { - "@swc/core": "^1.15.41", + "@swc/core": "^1.15.43", "@tsparticles/depcruise-config": "workspace:*", "@tsparticles/eslint-config": "workspace:*", "@tsparticles/prettier-config": "workspace:*", @@ -42,7 +42,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "klaw": "^4.1.0", @@ -54,14 +54,14 @@ "rimraf": "^6.1.3", "swc-loader": "^0.2.7", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" }, "devDependencies": { "@types/estree": "^1.0.9", "@types/klaw": "^3.0.7", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/prompts": "^2.4.9", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/build-clear/CHANGELOG.md b/cli/commands/build-clear/CHANGELOG.md index 302a1d271e6..bc656e12c5e 100644 --- a/cli/commands/build-clear/CHANGELOG.md +++ b/cli/commands/build-clear/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-command-build-clear diff --git a/cli/commands/build-clear/package.json b/cli/commands/build-clear/package.json index 114b9fada10..c5e6b04cb0c 100644 --- a/cli/commands/build-clear/package.json +++ b/cli/commands/build-clear/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-build-clear", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -34,7 +34,7 @@ "commander": "^15" }, "dependencies": { - "@swc/core": "^1.15.41", + "@swc/core": "^1.15.43", "@tsparticles/depcruise-config": "workspace:*", "@tsparticles/eslint-config": "workspace:*", "@tsparticles/prettier-config": "workspace:*", @@ -42,7 +42,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "klaw": "^4.1.0", @@ -54,14 +54,14 @@ "rimraf": "^6.1.3", "swc-loader": "^0.2.7", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" }, "devDependencies": { "@types/estree": "^1.0.9", "@types/klaw": "^3.0.7", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/prompts": "^2.4.9", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/build-distfiles/CHANGELOG.md b/cli/commands/build-distfiles/CHANGELOG.md index 663159e878f..0bb1f493c40 100644 --- a/cli/commands/build-distfiles/CHANGELOG.md +++ b/cli/commands/build-distfiles/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-command-build-distfiles diff --git a/cli/commands/build-distfiles/package.json b/cli/commands/build-distfiles/package.json index 5e5a225623c..43a11275972 100644 --- a/cli/commands/build-distfiles/package.json +++ b/cli/commands/build-distfiles/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-build-distfiles", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -34,7 +34,7 @@ "commander": "^15" }, "dependencies": { - "@swc/core": "^1.15.41", + "@swc/core": "^1.15.43", "@tsparticles/depcruise-config": "workspace:*", "@tsparticles/eslint-config": "workspace:*", "@tsparticles/prettier-config": "workspace:*", @@ -42,7 +42,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "klaw": "^4.1.0", @@ -54,14 +54,14 @@ "rimraf": "^6.1.3", "swc-loader": "^0.2.7", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" }, "devDependencies": { "@types/estree": "^1.0.9", "@types/klaw": "^3.0.7", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/prompts": "^2.4.9", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/build-diststats/CHANGELOG.md b/cli/commands/build-diststats/CHANGELOG.md index 9c1ddf8bb86..cf7fffbfd2c 100644 --- a/cli/commands/build-diststats/CHANGELOG.md +++ b/cli/commands/build-diststats/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-command-build-diststats diff --git a/cli/commands/build-diststats/package.json b/cli/commands/build-diststats/package.json index 212004369dc..467d3e3793d 100644 --- a/cli/commands/build-diststats/package.json +++ b/cli/commands/build-diststats/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-build-diststats", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -31,7 +31,7 @@ "prepack": "pnpm run build" }, "dependencies": { - "@swc/core": "^1.15.41", + "@swc/core": "^1.15.43", "@tsparticles/depcruise-config": "workspace:*", "@tsparticles/eslint-config": "workspace:*", "@tsparticles/prettier-config": "workspace:*", @@ -39,7 +39,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "klaw": "^4.1.0", @@ -50,13 +50,13 @@ "rimraf": "^6.1.3", "swc-loader": "^0.2.7", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" }, "devDependencies": { "@types/estree": "^1.0.9", "@types/klaw": "^3.0.7", - "@types/node": "^25.9.3", - "browserslist": "^4.28.2", + "@types/node": "^26.0.1", + "browserslist": "^4.28.4", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", "ts-node": "^10.9.2" diff --git a/cli/commands/build-eslint/CHANGELOG.md b/cli/commands/build-eslint/CHANGELOG.md index 276be37372b..3e4cf297196 100644 --- a/cli/commands/build-eslint/CHANGELOG.md +++ b/cli/commands/build-eslint/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-command-build-eslint diff --git a/cli/commands/build-eslint/package.json b/cli/commands/build-eslint/package.json index ec2c7c10092..5d9cc53aacd 100644 --- a/cli/commands/build-eslint/package.json +++ b/cli/commands/build-eslint/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-build-eslint", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -35,14 +35,14 @@ "eslint": "^10" }, "dependencies": { - "@swc/core": "^1.15.41", + "@swc/core": "^1.15.43", "@tsparticles/depcruise-config": "workspace:*", "@tsparticles/eslint-config": "workspace:*", "@tsparticles/prettier-config": "workspace:*", "@tsparticles/tsconfig": "workspace:*", "dependency-cruiser": "^17.4.3", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "klaw": "^4.1.0", @@ -54,14 +54,14 @@ "rimraf": "^6.1.3", "swc-loader": "^0.2.7", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" }, "devDependencies": { "@types/estree": "^1.0.9", "@types/klaw": "^3.0.7", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/prompts": "^2.4.9", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/build-prettier/CHANGELOG.md b/cli/commands/build-prettier/CHANGELOG.md index 91f552b2175..c95ba7ad059 100644 --- a/cli/commands/build-prettier/CHANGELOG.md +++ b/cli/commands/build-prettier/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-command-build-prettier diff --git a/cli/commands/build-prettier/package.json b/cli/commands/build-prettier/package.json index b876fc86343..18854485b77 100644 --- a/cli/commands/build-prettier/package.json +++ b/cli/commands/build-prettier/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-build-prettier", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -35,7 +35,7 @@ "prettier": "^3" }, "dependencies": { - "@swc/core": "^1.15.41", + "@swc/core": "^1.15.43", "@tsparticles/depcruise-config": "workspace:*", "@tsparticles/eslint-config": "workspace:*", "@tsparticles/prettier-config": "workspace:*", @@ -43,7 +43,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "klaw": "^4.1.0", @@ -55,14 +55,14 @@ "rimraf": "^6.1.3", "swc-loader": "^0.2.7", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" }, "devDependencies": { "@types/estree": "^1.0.9", "@types/klaw": "^3.0.7", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/prompts": "^2.4.9", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/build-tsc/CHANGELOG.md b/cli/commands/build-tsc/CHANGELOG.md index 39ad56d9776..ba77289b6c8 100644 --- a/cli/commands/build-tsc/CHANGELOG.md +++ b/cli/commands/build-tsc/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-command-build-tsc diff --git a/cli/commands/build-tsc/package.json b/cli/commands/build-tsc/package.json index 999e1ccadc3..3671facfd50 100644 --- a/cli/commands/build-tsc/package.json +++ b/cli/commands/build-tsc/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-build-tsc", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -35,7 +35,7 @@ "typescript": "^6" }, "dependencies": { - "@swc/core": "^1.15.41", + "@swc/core": "^1.15.43", "@tsparticles/depcruise-config": "workspace:*", "@tsparticles/eslint-config": "workspace:*", "@tsparticles/prettier-config": "workspace:*", @@ -43,7 +43,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "klaw": "^4.1.0", @@ -54,14 +54,14 @@ "prompts": "^2.4.2", "rimraf": "^6.1.3", "swc-loader": "^0.2.7", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" }, "devDependencies": { "@types/estree": "^1.0.9", "@types/klaw": "^3.0.7", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/prompts": "^2.4.9", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/build/CHANGELOG.md b/cli/commands/build/CHANGELOG.md index 7586be08b62..950e754e2d1 100644 --- a/cli/commands/build/CHANGELOG.md +++ b/cli/commands/build/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-command-build diff --git a/cli/commands/build/package.json b/cli/commands/build/package.json index 053a09e731a..4677b1ee0c3 100644 --- a/cli/commands/build/package.json +++ b/cli/commands/build/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-build", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -36,7 +36,7 @@ "commander": "^15" }, "dependencies": { - "@swc/core": "^1.15.41", + "@swc/core": "^1.15.43", "@tsparticles/cli-command-build-bundle-rollup": "workspace:*", "@tsparticles/cli-command-build-bundle-webpack": "workspace:*", "@tsparticles/cli-command-build-circular-deps": "workspace:*", @@ -54,7 +54,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "klaw": "^4.1.0", @@ -66,16 +66,16 @@ "rimraf": "^6.1.3", "swc-loader": "^0.2.7", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1", + "typescript-eslint": "^8.62.0", "webpack": "^5.107.2" }, "devDependencies": { "@types/estree": "^1.0.9", "@types/klaw": "^3.0.7", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/prompts": "^2.4.9", "@types/webpack-env": "^1.18.8", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/create-app/CHANGELOG.md b/cli/commands/create-app/CHANGELOG.md index 3b8cf64925d..6dcbc4e3baa 100644 --- a/cli/commands/create-app/CHANGELOG.md +++ b/cli/commands/create-app/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) ### Bug Fixes diff --git a/cli/commands/create-app/package.json b/cli/commands/create-app/package.json index 739670b2ea1..17c87e3a73c 100644 --- a/cli/commands/create-app/package.json +++ b/cli/commands/create-app/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-create-app", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -48,7 +48,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", @@ -57,9 +57,9 @@ }, "devDependencies": { "@types/estree": "^1.0.9", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/prompts": "^2.4.9", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/create-bundle/CHANGELOG.md b/cli/commands/create-bundle/CHANGELOG.md index d7bb398da4f..e4d951885a6 100644 --- a/cli/commands/create-bundle/CHANGELOG.md +++ b/cli/commands/create-bundle/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/cli-command-create-bundle diff --git a/cli/commands/create-bundle/package.json b/cli/commands/create-bundle/package.json index 281f950f22c..68059eddaef 100644 --- a/cli/commands/create-bundle/package.json +++ b/cli/commands/create-bundle/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-create-bundle", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -39,7 +39,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", @@ -47,8 +47,8 @@ }, "devDependencies": { "@types/estree": "^1.0.9", - "@types/node": "^25.9.3", - "browserslist": "^4.28.2", + "@types/node": "^26.0.1", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/create-effect/CHANGELOG.md b/cli/commands/create-effect/CHANGELOG.md index 7b8d17689c1..71ed475945e 100644 --- a/cli/commands/create-effect/CHANGELOG.md +++ b/cli/commands/create-effect/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/cli-command-create-effect diff --git a/cli/commands/create-effect/package.json b/cli/commands/create-effect/package.json index 8f8af3e7aa7..9df9d406e54 100644 --- a/cli/commands/create-effect/package.json +++ b/cli/commands/create-effect/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-create-effect", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -39,7 +39,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", @@ -47,8 +47,8 @@ }, "devDependencies": { "@types/estree": "^1.0.9", - "@types/node": "^25.9.3", - "browserslist": "^4.28.2", + "@types/node": "^26.0.1", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/create-interaction/CHANGELOG.md b/cli/commands/create-interaction/CHANGELOG.md index 86d9baef9fd..f456cdb7bee 100644 --- a/cli/commands/create-interaction/CHANGELOG.md +++ b/cli/commands/create-interaction/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/cli-command-create-interaction diff --git a/cli/commands/create-interaction/package.json b/cli/commands/create-interaction/package.json index 1c40ae20deb..02891a8a085 100644 --- a/cli/commands/create-interaction/package.json +++ b/cli/commands/create-interaction/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-create-interaction", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -39,7 +39,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", @@ -47,8 +47,8 @@ }, "devDependencies": { "@types/estree": "^1.0.9", - "@types/node": "^25.9.3", - "browserslist": "^4.28.2", + "@types/node": "^26.0.1", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/create-palette/CHANGELOG.md b/cli/commands/create-palette/CHANGELOG.md index 5cce8270ecd..2087d6dab56 100644 --- a/cli/commands/create-palette/CHANGELOG.md +++ b/cli/commands/create-palette/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/cli-command-create-palette diff --git a/cli/commands/create-palette/package.json b/cli/commands/create-palette/package.json index f93a3b8b0c4..9a5e2301d66 100644 --- a/cli/commands/create-palette/package.json +++ b/cli/commands/create-palette/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-create-palette", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -39,7 +39,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", @@ -47,8 +47,8 @@ }, "devDependencies": { "@types/estree": "^1.0.9", - "@types/node": "^25.9.3", - "browserslist": "^4.28.2", + "@types/node": "^26.0.1", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/create-path/CHANGELOG.md b/cli/commands/create-path/CHANGELOG.md index 9b13bb3d66c..8cc0ba47fac 100644 --- a/cli/commands/create-path/CHANGELOG.md +++ b/cli/commands/create-path/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/cli-command-create-path diff --git a/cli/commands/create-path/package.json b/cli/commands/create-path/package.json index a85d6e0b865..2a86fc10b1f 100644 --- a/cli/commands/create-path/package.json +++ b/cli/commands/create-path/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-create-path", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -39,7 +39,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", @@ -47,8 +47,8 @@ }, "devDependencies": { "@types/estree": "^1.0.9", - "@types/node": "^25.9.3", - "browserslist": "^4.28.2", + "@types/node": "^26.0.1", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/create-plugin/CHANGELOG.md b/cli/commands/create-plugin/CHANGELOG.md index 94c5c59d0b3..8f83bf88f9c 100644 --- a/cli/commands/create-plugin/CHANGELOG.md +++ b/cli/commands/create-plugin/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/cli-command-create-plugin diff --git a/cli/commands/create-plugin/package.json b/cli/commands/create-plugin/package.json index c806c4533f7..5e8e4664e82 100644 --- a/cli/commands/create-plugin/package.json +++ b/cli/commands/create-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-create-plugin", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -39,7 +39,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", @@ -47,8 +47,8 @@ }, "devDependencies": { "@types/estree": "^1.0.9", - "@types/node": "^25.9.3", - "browserslist": "^4.28.2", + "@types/node": "^26.0.1", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/create-preset/CHANGELOG.md b/cli/commands/create-preset/CHANGELOG.md index db4b2323fd4..bf105d02f5e 100644 --- a/cli/commands/create-preset/CHANGELOG.md +++ b/cli/commands/create-preset/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/cli-command-create-preset diff --git a/cli/commands/create-preset/package.json b/cli/commands/create-preset/package.json index 1b44643083c..39eb11fdc82 100644 --- a/cli/commands/create-preset/package.json +++ b/cli/commands/create-preset/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-create-preset", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -39,7 +39,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", @@ -47,8 +47,8 @@ }, "devDependencies": { "@types/estree": "^1.0.9", - "@types/node": "^25.9.3", - "browserslist": "^4.28.2", + "@types/node": "^26.0.1", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/create-shape/CHANGELOG.md b/cli/commands/create-shape/CHANGELOG.md index 98749a6753a..89a396c3869 100644 --- a/cli/commands/create-shape/CHANGELOG.md +++ b/cli/commands/create-shape/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/cli-command-create-shape diff --git a/cli/commands/create-shape/package.json b/cli/commands/create-shape/package.json index 468da6d0bc7..cf2962caa3e 100644 --- a/cli/commands/create-shape/package.json +++ b/cli/commands/create-shape/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-create-shape", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -39,7 +39,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", @@ -47,8 +47,8 @@ }, "devDependencies": { "@types/estree": "^1.0.9", - "@types/node": "^25.9.3", - "browserslist": "^4.28.2", + "@types/node": "^26.0.1", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/create-updater/CHANGELOG.md b/cli/commands/create-updater/CHANGELOG.md index 4b70e0f0dc4..8e7cbc6b8da 100644 --- a/cli/commands/create-updater/CHANGELOG.md +++ b/cli/commands/create-updater/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/cli-command-create-updater diff --git a/cli/commands/create-updater/package.json b/cli/commands/create-updater/package.json index e6aeb268fe2..4b48c42f6e1 100644 --- a/cli/commands/create-updater/package.json +++ b/cli/commands/create-updater/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-create-updater", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -39,7 +39,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", @@ -47,8 +47,8 @@ }, "devDependencies": { "@types/estree": "^1.0.9", - "@types/node": "^25.9.3", - "browserslist": "^4.28.2", + "@types/node": "^26.0.1", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/commands/create-utils/CHANGELOG.md b/cli/commands/create-utils/CHANGELOG.md index 01f8d13e8bd..e3a3cc80ab5 100644 --- a/cli/commands/create-utils/CHANGELOG.md +++ b/cli/commands/create-utils/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-create-utils diff --git a/cli/commands/create-utils/files/empty-project/package.dist.json b/cli/commands/create-utils/files/empty-project/package.dist.json index 1f53a9a615a..52c6b7063e2 100644 --- a/cli/commands/create-utils/files/empty-project/package.dist.json +++ b/cli/commands/create-utils/files/empty-project/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/empty-template", - "version": "4.2.1", + "version": "4.3.0", "private": true, "type": "module", "author": "Matteo Bruni ", @@ -73,6 +73,6 @@ "module": "index.js", "types": "index.d.ts", "peerDependencies": { - "@tsparticles/engine": "^4.2.1" + "@tsparticles/engine": "^4.3.0" } } diff --git a/cli/commands/create-utils/files/empty-project/package.json b/cli/commands/create-utils/files/empty-project/package.json index b0464be177d..41eef35ffec 100644 --- a/cli/commands/create-utils/files/empty-project/package.json +++ b/cli/commands/create-utils/files/empty-project/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/empty-template", - "version": "4.2.1", + "version": "4.3.0", "private": true, "type": "module", "description": "tsParticles empty template", @@ -91,7 +91,7 @@ "@tsparticles/prettier-config": "^4.1.3", "@tsparticles/rollup-plugin": "^4.1.3", "@tsparticles/tsconfig": "^4.1.3", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "copyfiles": "^2.4.1", "eslint": "^10.4.1", "eslint-config-prettier": "^10.1.8", @@ -102,6 +102,6 @@ "typescript-eslint": "^8.60.1" }, "peerDependencies": { - "@tsparticles/engine": "^4.2.1" + "@tsparticles/engine": "^4.3.0" } } diff --git a/cli/commands/create-utils/package.json b/cli/commands/create-utils/package.json index c1138c18546..541b0b45d08 100644 --- a/cli/commands/create-utils/package.json +++ b/cli/commands/create-utils/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-create-utils", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -42,7 +42,7 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "klaw": "^4.1.0", @@ -53,14 +53,14 @@ "prompts": "^2.4.2", "rimraf": "^6.1.3", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" }, "devDependencies": { "@types/estree": "^1.0.9", "@types/klaw": "^3.0.7", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/prompts": "^2.4.9", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", "ts-node": "^10.9.2", diff --git a/cli/commands/create-utils/src/create-project.ts b/cli/commands/create-utils/src/create-project.ts index 730a432b322..4e0db9cd9bc 100644 --- a/cli/commands/create-utils/src/create-project.ts +++ b/cli/commands/create-utils/src/create-project.ts @@ -585,7 +585,6 @@ export async function ${loadFunction}(engine: Engine): Promise { /** * - * @param nameData - The nameData * @param loadFunction - The loadFunction * @param pluginClass - The pluginClass * @returns The string value diff --git a/cli/commands/create-utils/src/template-utils.ts b/cli/commands/create-utils/src/template-utils.ts index 7984d0e9f91..159f0af2505 100644 --- a/cli/commands/create-utils/src/template-utils.ts +++ b/cli/commands/create-utils/src/template-utils.ts @@ -130,7 +130,7 @@ export async function runInstall(destPath: string): Promise { }, error => { if (error) { - reject(error); + reject(new Error(error.message)); return; } @@ -158,7 +158,7 @@ export async function runBuild(destPath: string): Promise { }, error => { if (error) { - reject(error); + reject(new Error(error.message)); return; } diff --git a/cli/commands/create/CHANGELOG.md b/cli/commands/create/CHANGELOG.md index 7ee54bf0338..5af516054ce 100644 --- a/cli/commands/create/CHANGELOG.md +++ b/cli/commands/create/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/cli-command-create diff --git a/cli/commands/create/package.json b/cli/commands/create/package.json index e916e3046e3..b01c24ee23e 100644 --- a/cli/commands/create/package.json +++ b/cli/commands/create/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-command-create", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "publishConfig": { @@ -53,20 +53,20 @@ "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", "rimraf": "^6.1.3", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" }, "devDependencies": { "@types/estree": "^1.0.9", "@types/klaw": "^3.0.7", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/prompts": "^2.4.9", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "commander": "^15.0.0", "copyfiles": "^2.4.1", "cross-env": "^10.1.0", diff --git a/cli/packages/cli-build/CHANGELOG.md b/cli/packages/cli-build/CHANGELOG.md index 6b02175f501..25c943fae5f 100644 --- a/cli/packages/cli-build/CHANGELOG.md +++ b/cli/packages/cli-build/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/cli-build + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-build diff --git a/cli/packages/cli-build/package.json b/cli/packages/cli-build/package.json index 8e4373a9001..1f3d58a3959 100644 --- a/cli/packages/cli-build/package.json +++ b/cli/packages/cli-build/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-build", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "bin": { diff --git a/cli/packages/cli-create/CHANGELOG.md b/cli/packages/cli-create/CHANGELOG.md index ed012061e76..b507cc00c70 100644 --- a/cli/packages/cli-create/CHANGELOG.md +++ b/cli/packages/cli-create/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/cli-create + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/cli-create diff --git a/cli/packages/cli-create/package.json b/cli/packages/cli-create/package.json index e8d67cb4d19..6e803ac7174 100644 --- a/cli/packages/cli-create/package.json +++ b/cli/packages/cli-create/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-create", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "bin": { diff --git a/cli/packages/create-404/CHANGELOG.md b/cli/packages/create-404/CHANGELOG.md index 1771f0fec4e..4e8a85afa69 100644 --- a/cli/packages/create-404/CHANGELOG.md +++ b/cli/packages/create-404/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package create-404 + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package create-404 diff --git a/cli/packages/create-404/package.json b/cli/packages/create-404/package.json index d71dc807670..24547473839 100644 --- a/cli/packages/create-404/package.json +++ b/cli/packages/create-404/package.json @@ -1,6 +1,6 @@ { "name": "create-404", - "version": "4.2.1", + "version": "4.3.0", "description": "Scaffold a @tsparticles/template-404 project — npm create 404", "homepage": "https://particles.js.org", "license": "MIT", diff --git a/cli/packages/create-confetti/CHANGELOG.md b/cli/packages/create-confetti/CHANGELOG.md index db3fd793817..924c0cc315a 100644 --- a/cli/packages/create-confetti/CHANGELOG.md +++ b/cli/packages/create-confetti/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package create-confetti + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package create-confetti diff --git a/cli/packages/create-confetti/package.json b/cli/packages/create-confetti/package.json index 30d128e286a..8158afc864f 100644 --- a/cli/packages/create-confetti/package.json +++ b/cli/packages/create-confetti/package.json @@ -1,6 +1,6 @@ { "name": "create-confetti", - "version": "4.2.1", + "version": "4.3.0", "description": "Scaffold a @tsparticles/confetti project — npm create confetti", "homepage": "https://particles.js.org", "license": "MIT", diff --git a/cli/packages/create-particles/CHANGELOG.md b/cli/packages/create-particles/CHANGELOG.md index bb38603f691..f7ae1eba6e3 100644 --- a/cli/packages/create-particles/CHANGELOG.md +++ b/cli/packages/create-particles/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package create-particles + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package create-particles diff --git a/cli/packages/create-particles/package.json b/cli/packages/create-particles/package.json index 6daab098c4a..aaf87234f96 100644 --- a/cli/packages/create-particles/package.json +++ b/cli/packages/create-particles/package.json @@ -1,6 +1,6 @@ { "name": "create-particles", - "version": "4.2.1", + "version": "4.3.0", "description": "Scaffold a @tsparticles/particles project — npm create particles", "homepage": "https://particles.js.org", "license": "MIT", diff --git a/cli/packages/create-ribbons/CHANGELOG.md b/cli/packages/create-ribbons/CHANGELOG.md index b58ce8eb110..e5ca7dc3b6a 100644 --- a/cli/packages/create-ribbons/CHANGELOG.md +++ b/cli/packages/create-ribbons/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package create-ribbons + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package create-ribbons diff --git a/cli/packages/create-ribbons/package.json b/cli/packages/create-ribbons/package.json index 5206207afe7..f4add1b36e0 100644 --- a/cli/packages/create-ribbons/package.json +++ b/cli/packages/create-ribbons/package.json @@ -1,6 +1,6 @@ { "name": "create-ribbons", - "version": "4.2.1", + "version": "4.3.0", "description": "Scaffold a @tsparticles/ribbons project — npm create ribbons", "homepage": "https://particles.js.org", "license": "MIT", diff --git a/cli/packages/create-tsparticles/CHANGELOG.md b/cli/packages/create-tsparticles/CHANGELOG.md index e7a153c384d..a0ff7dc9641 100644 --- a/cli/packages/create-tsparticles/CHANGELOG.md +++ b/cli/packages/create-tsparticles/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package create-tsparticles + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package create-tsparticles diff --git a/cli/packages/create-tsparticles/package.json b/cli/packages/create-tsparticles/package.json index a3bfe8c6b8a..794f5070f16 100644 --- a/cli/packages/create-tsparticles/package.json +++ b/cli/packages/create-tsparticles/package.json @@ -1,6 +1,6 @@ { "name": "create-tsparticles", - "version": "4.2.1", + "version": "4.3.0", "description": "Scaffold a tsParticles project — npm create tsparticles", "homepage": "https://particles.js.org", "license": "MIT", diff --git a/cli/packages/nx-plugin/CHANGELOG.md b/cli/packages/nx-plugin/CHANGELOG.md index 4b3f6f80fe1..c3775c7b0ab 100644 --- a/cli/packages/nx-plugin/CHANGELOG.md +++ b/cli/packages/nx-plugin/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/cli-nx-plugin diff --git a/cli/packages/nx-plugin/package.json b/cli/packages/nx-plugin/package.json index ca1b502ff68..a8fbe130895 100644 --- a/cli/packages/nx-plugin/package.json +++ b/cli/packages/nx-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/cli-nx-plugin", - "version": "4.2.1", + "version": "4.3.0", "license": "MIT", "type": "module", "repository": { @@ -31,24 +31,24 @@ "nx": "^22" }, "dependencies": { - "@nx/devkit": "^22.7.5", + "@nx/devkit": "^23.0.0", "@tsparticles/eslint-config": "workspace:*", "@tsparticles/prettier-config": "workspace:*", "@tsparticles/tsconfig": "workspace:*", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", "prettier-plugin-multiline-arrays": "^4.1.9", "rimraf": "^6.1.3", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1", + "typescript-eslint": "^8.62.0", "vitest": "^4.1.9" }, "devDependencies": { - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "nx": "^22.7.5" }, "description": "tsParticles Nx plugin", diff --git a/cli/utils/browserslist-config/CHANGELOG.md b/cli/utils/browserslist-config/CHANGELOG.md index 288eb505885..3dd6cc615a9 100644 --- a/cli/utils/browserslist-config/CHANGELOG.md +++ b/cli/utils/browserslist-config/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/browserslist-config diff --git a/cli/utils/browserslist-config/package.json b/cli/utils/browserslist-config/package.json index 632e804371d..7e35244ea9d 100644 --- a/cli/utils/browserslist-config/package.json +++ b/cli/utils/browserslist-config/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/browserslist-config", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles default Browserslist configuration", "main": "dist/index.js", "license": "MIT", @@ -20,7 +20,7 @@ "build:ci": "cpx \"./src/**.*\" ./dist/" }, "devDependencies": { - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "cpx2": "^9.0.0" }, "peerDependencies": { diff --git a/cli/utils/depcruise-config/CHANGELOG.md b/cli/utils/depcruise-config/CHANGELOG.md index 2014ac83f71..c689cb2f77a 100644 --- a/cli/utils/depcruise-config/CHANGELOG.md +++ b/cli/utils/depcruise-config/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/depcruise-config diff --git a/cli/utils/depcruise-config/package.json b/cli/utils/depcruise-config/package.json index 2fbd2fca4d1..92f1ca76763 100644 --- a/cli/utils/depcruise-config/package.json +++ b/cli/utils/depcruise-config/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/depcruise-config", - "version": "4.2.1", + "version": "4.3.0", "private": false, "type": "module", "publishConfig": { @@ -45,16 +45,16 @@ "@stylistic/eslint-plugin": "^5.10.0", "@tsparticles/eslint-config": "workspace:*", "@tsparticles/prettier-config": "workspace:*", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "dependency-cruiser": "^17.4.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", "prettier-plugin-multiline-arrays": "^4.1.9", "tsdown": "^0.22.3", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" } } diff --git a/cli/utils/eslint-config/CHANGELOG.md b/cli/utils/eslint-config/CHANGELOG.md index 5b6b0267308..f8a34066ac8 100644 --- a/cli/utils/eslint-config/CHANGELOG.md +++ b/cli/utils/eslint-config/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/eslint-config diff --git a/cli/utils/eslint-config/package.json b/cli/utils/eslint-config/package.json index 754d2e42c7b..1e5844c87af 100644 --- a/cli/utils/eslint-config/package.json +++ b/cli/utils/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/eslint-config", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles default ESLint Configuration (ESLint 10 + Flat Config)", "type": "module", "main": "dist/eslint.config.js", @@ -40,17 +40,17 @@ "@stylistic/eslint-plugin": "^5.10.0", "@tsparticles/prettier-config": "workspace:*", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tsdoc": "^0.5.2", "jiti": "^2.7.0", "prettier": "^3.8.4", "prettier-plugin-multiline-arrays": "^4.1.9", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" }, "devDependencies": { - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "eslint": "^10.5.0" } } diff --git a/cli/utils/prettier-config/CHANGELOG.md b/cli/utils/prettier-config/CHANGELOG.md index ff755250991..6e94ee8a58f 100644 --- a/cli/utils/prettier-config/CHANGELOG.md +++ b/cli/utils/prettier-config/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/prettier-config + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/prettier-config diff --git a/cli/utils/prettier-config/package.json b/cli/utils/prettier-config/package.json index d861eddd819..a654d042158 100644 --- a/cli/utils/prettier-config/package.json +++ b/cli/utils/prettier-config/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/prettier-config", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles default Prettier Configuration", "main": "dist/index.cjs", "exports": { diff --git a/cli/utils/rollup-plugin/CHANGELOG.md b/cli/utils/rollup-plugin/CHANGELOG.md index 29e90c178d8..b03e9ec9b8c 100644 --- a/cli/utils/rollup-plugin/CHANGELOG.md +++ b/cli/utils/rollup-plugin/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/rollup-plugin diff --git a/cli/utils/rollup-plugin/package.json b/cli/utils/rollup-plugin/package.json index 4c54a1dd9b2..c570ab3e76f 100644 --- a/cli/utils/rollup-plugin/package.json +++ b/cli/utils/rollup-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/rollup-plugin", - "version": "4.2.1", + "version": "4.3.0", "description": "Rollup build utilities for tsParticles", "private": false, "type": "module", @@ -56,7 +56,7 @@ "@tsparticles/prettier-config": "workspace:*", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", "prettier-plugin-multiline-arrays": "^4.1.9", @@ -64,9 +64,9 @@ }, "devDependencies": { "@rollup/plugin-typescript": "^12.3.0", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "rimraf": "^6.1.3", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1" + "typescript-eslint": "^8.62.0" } } diff --git a/cli/utils/tsconfig/CHANGELOG.md b/cli/utils/tsconfig/CHANGELOG.md index 7b6e9d0ccd5..9c4b058a3d7 100644 --- a/cli/utils/tsconfig/CHANGELOG.md +++ b/cli/utils/tsconfig/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/tsconfig + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/tsconfig diff --git a/cli/utils/tsconfig/package.json b/cli/utils/tsconfig/package.json index f88f5058648..af96e29ce91 100644 --- a/cli/utils/tsconfig/package.json +++ b/cli/utils/tsconfig/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/tsconfig", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles default TypeScript Compiler Configuration", "license": "MIT", "repository": { diff --git a/cli/utils/webpack-config/CHANGELOG.md b/cli/utils/webpack-config/CHANGELOG.md index 141933603ad..bf8e60e0779 100644 --- a/cli/utils/webpack-config/CHANGELOG.md +++ b/cli/utils/webpack-config/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/webpack-plugin diff --git a/cli/utils/webpack-config/package.json b/cli/utils/webpack-config/package.json index 6a8172e7a69..6352bea9608 100644 --- a/cli/utils/webpack-config/package.json +++ b/cli/utils/webpack-config/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/webpack-plugin", - "version": "4.2.1", + "version": "4.3.0", "type": "module", "main": "dist/webpack-tsparticles.js", "types": "dist/webpack-tsparticles.d.ts", @@ -42,25 +42,25 @@ }, "dependencies": { "@stylistic/eslint-plugin": "^5.10.0", - "@swc/core": "^1.15.41", + "@swc/core": "^1.15.43", "@tsparticles/eslint-config": "workspace:*", "@tsparticles/prettier-config": "workspace:*", - "browserslist": "^4.28.2", + "browserslist": "^4.28.4", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-tsdoc": "^0.5.2", "prettier": "^3.8.4", "prettier-plugin-multiline-arrays": "^4.1.9", "swc-loader": "^0.2.7", "terser-webpack-plugin": "^5.6.1", "typescript": "^6.0.3", - "typescript-eslint": "^8.61.1", + "typescript-eslint": "^8.62.0", "webpack-bundle-analyzer": "^5.3.0", "webpack-cli": "^7.0.3" }, "devDependencies": { - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/webpack-bundle-analyzer": "^4.7.0", "@types/webpack-env": "^1.18.8", "rimraf": "^6.1.3", diff --git a/demo/angular/CHANGELOG.md b/demo/angular/CHANGELOG.md index 342965285d3..4d6c743445c 100644 --- a/demo/angular/CHANGELOG.md +++ b/demo/angular/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/angular-demo diff --git a/demo/angular/package.json b/demo/angular/package.json index 7cbbeabc534..f286ebacc74 100644 --- a/demo/angular/package.json +++ b/demo/angular/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/angular-demo", - "version": "4.2.1", + "version": "4.3.0", "repository": { "type": "git", "url": "git+https://github.com/tsparticles/tsparticles.git", @@ -16,13 +16,12 @@ }, "private": true, "dependencies": { - "@angular/common": "~22.0.1", - "@angular/compiler": "~22.0.1", - "@angular/core": "~22.0.1", - "@angular/forms": "~22.0.1", - "@angular/platform-browser": "~22.0.1", - "@angular/platform-browser-dynamic": "~22.0.1", - "@angular/router": "~22.0.1", + "@angular/common": "~22.0.2", + "@angular/compiler": "~22.0.2", + "@angular/core": "~22.0.2", + "@angular/forms": "~22.0.2", + "@angular/platform-browser": "~22.0.2", + "@angular/router": "~22.0.2", "@tsparticles/angular": "workspace:*", "@tsparticles/animation-utils": "workspace:*", "@tsparticles/basic": "workspace:*", @@ -96,11 +95,11 @@ "zone.js": "~0.16.2" }, "devDependencies": { - "@angular/build": "22.0.1", - "@angular/cli": "~22.0.1", - "@angular/compiler-cli": "~22.0.1", + "@angular/build": "~22.0.4", + "@angular/cli": "~22.0.4", + "@angular/compiler-cli": "~22.0.2", "@types/jasmine": "~6.0.0", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "jasmine-core": "~6.3.0", "karma": "~6.4.4", "karma-chrome-launcher": "~3.2.0", diff --git a/demo/angular/src/app/app.component.ts b/demo/angular/src/app/app.component.ts index d49c6ae9bf5..09b57586bd2 100644 --- a/demo/angular/src/app/app.component.ts +++ b/demo/angular/src/app/app.component.ts @@ -1,12 +1,23 @@ +import { CommonModule } from "@angular/common"; import { Component } from "@angular/core"; +import { RouterModule } from "@angular/router"; import type { Container, Engine, ISourceOptions } from "@tsparticles/engine"; import { loadFull } from "tsparticles"; import configs from "@tsparticles/configs"; -import { NgParticlesService } from "@tsparticles/angular"; +import { NgParticlesService, NgxParticlesModule } from "@tsparticles/angular"; +import { NgxConfettiModule } from "angular-confetti"; +import { NgxFireworksModule } from "angular-fireworks"; @Component({ selector: "app-root", - standalone: false, + standalone: true, + imports: [ + CommonModule, + RouterModule, + NgxParticlesModule, + NgxConfettiModule, + NgxFireworksModule, + ], templateUrl: "./app.component.html", styleUrls: ["./app.component.css"], }) diff --git a/demo/angular/src/app/app.module.ts b/demo/angular/src/app/app.module.ts deleted file mode 100644 index 8f4bb38f451..00000000000 --- a/demo/angular/src/app/app.module.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { NgxParticlesModule } from '@tsparticles/angular'; -import { NgxConfettiModule } from 'angular-confetti'; -import { NgxFireworksModule } from 'angular-fireworks'; - -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; - -@NgModule({ - declarations: [AppComponent], - imports: [ - BrowserModule, - AppRoutingModule, - NgxParticlesModule, - NgxConfettiModule, - NgxFireworksModule, - ], - providers: [], - bootstrap: [AppComponent], -}) -export class AppModule {} diff --git a/demo/angular/src/main.ts b/demo/angular/src/main.ts index c7b673cf44b..45f0953d911 100644 --- a/demo/angular/src/main.ts +++ b/demo/angular/src/main.ts @@ -1,12 +1,26 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { enableProdMode, importProvidersFrom } from '@angular/core'; +import { bootstrapApplication } from '@angular/platform-browser'; +import { BrowserModule } from '@angular/platform-browser'; -import { AppModule } from './app/app.module'; +import { AppComponent } from './app/app.component'; +import { AppRoutingModule } from './app/app-routing.module'; import { environment } from './environments/environment'; +import { NgxConfettiModule } from 'angular-confetti'; +import { NgxFireworksModule } from 'angular-fireworks'; +import { NgxParticlesModule } from '@tsparticles/angular'; if (environment.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.error(err)); +bootstrapApplication(AppComponent, { + providers: [ + importProvidersFrom( + BrowserModule, + AppRoutingModule, + NgxParticlesModule, + NgxConfettiModule, + NgxFireworksModule, + ), + ], +}).catch(err => console.error(err)); diff --git a/demo/astro/CHANGELOG.md b/demo/astro/CHANGELOG.md index 9473130c8cc..c5932167e71 100644 --- a/demo/astro/CHANGELOG.md +++ b/demo/astro/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/astro-demo + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/astro-demo diff --git a/demo/astro/package.json b/demo/astro/package.json index 16601894087..cabc7db8d80 100644 --- a/demo/astro/package.json +++ b/demo/astro/package.json @@ -1,7 +1,7 @@ { "name": "@tsparticles/astro-demo", "type": "module", - "version": "4.2.1", + "version": "4.3.0", "private": true, "repository": { "type": "git", diff --git a/demo/electron/CHANGELOG.md b/demo/electron/CHANGELOG.md index 8eaa7d65430..4ed30e8983c 100644 --- a/demo/electron/CHANGELOG.md +++ b/demo/electron/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/electron-demo diff --git a/demo/electron/package.json b/demo/electron/package.json index cb7b7d5aa6a..cbc06e975b1 100644 --- a/demo/electron/package.json +++ b/demo/electron/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/electron-demo", - "version": "4.2.1", + "version": "4.3.0", "description": "", "main": "app/index.cjs", "private": true, @@ -86,7 +86,7 @@ "@electron/windows-sign": "^2.0.3", "@malept/cross-spawn-promise": "^2.0.0", "@sec-ant/readable-stream": "^0.7.0", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@xmldom/xmldom": "^0.9.10", "author-regex": "^1.0.0", "balanced-match": "^4.0.4", diff --git a/demo/ember/CHANGELOG.md b/demo/ember/CHANGELOG.md index 2bc71cbc9da..5464e50fe5d 100644 --- a/demo/ember/CHANGELOG.md +++ b/demo/ember/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/ember-demo diff --git a/demo/ember/app/utils/options.ts b/demo/ember/app/utils/options.ts index a9d5b9eb8f3..1769e9c60ff 100644 --- a/demo/ember/app/utils/options.ts +++ b/demo/ember/app/utils/options.ts @@ -1,7 +1,9 @@ export const LINK_OPTIONS = { particles: { - color: { - value: "#ffffff", + paint: { + color: { + value: "#ffffff", + }, }, links: { color: "#ffffff", @@ -44,8 +46,10 @@ export const SNOW_OPTIONS = { zIndex: -1, }, particles: { - color: { - value: "#fff", + paint: { + color: { + value: "#fff", + }, }, move: { direction: "bottom", @@ -98,8 +102,10 @@ export const CONFETTI_OPTIONS = { }, }, particles: { - color: { - value: ["#1E00FF", "#FF0061", "#E1FF00", "#00FF9E"], + paint: { + color: { + value: ["#1E00FF", "#FF0061", "#E1FF00", "#00FF9E"], + }, }, move: { decay: 0.05, diff --git a/demo/ember/package.json b/demo/ember/package.json index 1a23b4e8a15..f938070d6a8 100644 --- a/demo/ember/package.json +++ b/demo/ember/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/ember-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "description": "Ember demo for @tsparticles/ember", "repository": { @@ -30,7 +30,7 @@ "ember-modifier": "^4.3.0", "ember-page-title": "^9.0.3", "ember-resolver": "^13.2.0", - "ember-source": "~7.0.0", + "ember-source": "~7.1.0", "tsparticles": "workspace:*" }, "devDependencies": { @@ -41,7 +41,7 @@ "@types/ember__application": "^4.0.11", "@types/ember__controller": "^4.0.12", "@types/ember__routing": "^4.0.23", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/qunit": "^2.19.14", "broccoli-asset-rev": "^3.0.0", "ember-cli": "~7.0.1", @@ -53,8 +53,8 @@ "ember-template-lint": "^7.9.3", "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-ember": "^13.3.2", - "eslint-plugin-node": "^11.1.0", + "eslint-plugin-ember": "^13.4.0", + "eslint-plugin-n": "^18.2.1", "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-qunit": "^8.2.6", "loader.js": "^4.7.0", @@ -62,6 +62,6 @@ "qunit": "^2.26.0", "qunit-dom": "^3.5.1", "typescript": "^6.0.3", - "webpack": "^5.107.2" + "webpack": "^5.108.0" } } diff --git a/demo/inferno/CHANGELOG.md b/demo/inferno/CHANGELOG.md index b4d94c0e274..e5583b0fb99 100644 --- a/demo/inferno/CHANGELOG.md +++ b/demo/inferno/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/inferno-demo + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/inferno-demo diff --git a/demo/inferno/package.json b/demo/inferno/package.json index 21bad86bc27..e7c06de61e6 100644 --- a/demo/inferno/package.json +++ b/demo/inferno/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/inferno-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "description": "> TODO: description", "main": "index.js", diff --git a/demo/ionic/CHANGELOG.md b/demo/ionic/CHANGELOG.md index 96a38a1187e..cb18c1f0e8e 100644 --- a/demo/ionic/CHANGELOG.md +++ b/demo/ionic/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/ionic-demo diff --git a/demo/ionic/package.json b/demo/ionic/package.json index cc5bb3e590a..c16c4b482fc 100644 --- a/demo/ionic/package.json +++ b/demo/ionic/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/ionic-demo", - "version": "4.2.1", + "version": "4.3.0", "author": "Matteo Bruni ", "homepage": "https://particles.js.org", "repository": { @@ -19,19 +19,18 @@ }, "private": true, "dependencies": { - "@angular/common": "~22.0.1", - "@angular/core": "~22.0.1", - "@angular/forms": "~22.0.1", - "@angular/platform-browser": "~22.0.1", - "@angular/platform-browser-dynamic": "~22.0.1", - "@angular/router": "~22.0.1", + "@angular/common": "~22.0.2", + "@angular/core": "~22.0.2", + "@angular/forms": "~22.0.2", + "@angular/platform-browser": "~22.0.2", + "@angular/router": "~22.0.2", "@capacitor/app": "^8.1.0", - "@capacitor/core": "^8.4.0", + "@capacitor/core": "^8.4.1", "@capacitor/haptics": "^8.0.2", "@capacitor/keyboard": "^8.0.5", "@capacitor/status-bar": "^8.0.2", - "@ionic/angular": "^8.8.10", - "@ionic/core": "^8.8.10", + "@ionic/angular": "^8.8.12", + "@ionic/core": "^8.8.12", "@stencil/core": "^4.43.5", "@tsparticles/angular": "workspace:*", "@tsparticles/animation-utils": "workspace:*", @@ -105,21 +104,21 @@ "@angular-eslint/eslint-plugin": "~22.0.0", "@angular-eslint/eslint-plugin-template": "~22.0.0", "@angular-eslint/template-parser": "~22.0.0", - "@angular/build": "~22.0.1", - "@angular/cli": "~22.0.1", - "@angular/compiler": "~22.0.1", - "@angular/compiler-cli": "~22.0.1", - "@angular/language-service": "~22.0.1", - "@capacitor/cli": "^8.4.0", + "@angular/build": "~22.0.4", + "@angular/cli": "~22.0.4", + "@angular/compiler": "~22.0.2", + "@angular/compiler-cli": "~22.0.2", + "@angular/language-service": "~22.0.2", + "@capacitor/cli": "^8.4.1", "@ionic/angular-toolkit": "^12.3.0", "@types/jasmine": "~6.0.0", "@types/jasminewd2": "~2.0.13", - "@types/node": "^25.9.3", - "@typescript-eslint/eslint-plugin": "^8.61.1", - "@typescript-eslint/parser": "^8.61.1", + "@types/node": "^26.0.1", + "@typescript-eslint/eslint-plugin": "^8.62.0", + "@typescript-eslint/parser": "^8.62.0", "eslint": "^10.5.0", "eslint-plugin-import": "^2.32.0", - "eslint-plugin-jsdoc": "^63.0.5", + "eslint-plugin-jsdoc": "^63.0.8", "eslint-plugin-prefer-arrow": "^1.2.3", "jasmine-core": "~6.3.0", "jasmine-spec-reporter": "~7.0.0", diff --git a/demo/ionic/src/app/app.component.ts b/demo/ionic/src/app/app.component.ts index e14f1e2bff0..b7b112df412 100644 --- a/demo/ionic/src/app/app.component.ts +++ b/demo/ionic/src/app/app.component.ts @@ -1,10 +1,13 @@ import { Component } from "@angular/core"; -import { NgParticlesService } from "@tsparticles/angular"; +import { IonicModule } from "@ionic/angular"; +import { RouterModule } from "@angular/router"; +import { NgParticlesService, NgxParticlesModule } from "@tsparticles/angular"; import { loadFull } from "tsparticles"; @Component({ selector: "app-root", - standalone: false, + standalone: true, + imports: [IonicModule, RouterModule, NgxParticlesModule], templateUrl: "app.component.html", styleUrls: ["app.component.scss"], }) diff --git a/demo/ionic/src/app/app.module.ts b/demo/ionic/src/app/app.module.ts deleted file mode 100644 index de886d9e476..00000000000 --- a/demo/ionic/src/app/app.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { RouteReuseStrategy } from '@angular/router'; - -import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; - -import { AppRoutingModule } from './app-routing.module'; -import { AppComponent } from './app.component'; - -@NgModule({ - declarations: [AppComponent], - //entryComponents: [], - imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule], - providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }], - bootstrap: [AppComponent], -}) -export class AppModule {} diff --git a/demo/ionic/src/main.ts b/demo/ionic/src/main.ts index 91ec6da5f07..953a4c2165c 100644 --- a/demo/ionic/src/main.ts +++ b/demo/ionic/src/main.ts @@ -1,12 +1,20 @@ -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { enableProdMode, importProvidersFrom } from '@angular/core'; +import { bootstrapApplication } from '@angular/platform-browser'; +import { BrowserModule } from '@angular/platform-browser'; +import { RouteReuseStrategy } from '@angular/router'; +import { IonicModule, IonicRouteStrategy } from '@ionic/angular'; -import { AppModule } from './app/app.module'; +import { AppComponent } from './app/app.component'; +import { AppRoutingModule } from './app/app-routing.module'; import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.log(err)); +bootstrapApplication(AppComponent, { + providers: [ + { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }, + importProvidersFrom(BrowserModule, IonicModule.forRoot(), AppRoutingModule), + ], +}).catch(err => console.error(err)); diff --git a/demo/jquery/CHANGELOG.md b/demo/jquery/CHANGELOG.md index ae4369e24f1..7bea7ec5f39 100644 --- a/demo/jquery/CHANGELOG.md +++ b/demo/jquery/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/jquery-demo + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/jquery-demo diff --git a/demo/jquery/package.json b/demo/jquery/package.json index 7e007e4bcb0..18aa09b36e5 100644 --- a/demo/jquery/package.json +++ b/demo/jquery/package.json @@ -1,7 +1,7 @@ { "name": "@tsparticles/jquery-demo", "private": true, - "version": "4.2.1", + "version": "4.3.0", "description": "> TODO: description", "author": "Matteo Bruni ", "homepage": "https://particles.js.org", diff --git a/demo/lit/CHANGELOG.md b/demo/lit/CHANGELOG.md index 39e8b8a9090..4f9cf272c58 100644 --- a/demo/lit/CHANGELOG.md +++ b/demo/lit/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/lit-demo diff --git a/demo/lit/package.json b/demo/lit/package.json index a583525d241..e5c60dbf6c1 100644 --- a/demo/lit/package.json +++ b/demo/lit/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/lit-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "description": "A simple web component", "type": "module", @@ -55,7 +55,7 @@ "node-resolve": "^1.3.4", "prettier": "^3.8.4", "rimraf": "^5.0.10", - "rollup": "^4.62.0", + "rollup": "^4.62.2", "rollup-plugin-filesize": "^10.0.0", "sinon": "^22.0.0", "typescript": "^6.0.3", diff --git a/demo/nextjs-legacy/CHANGELOG.md b/demo/nextjs-legacy/CHANGELOG.md index 531b687fca3..aaa4325b7dd 100644 --- a/demo/nextjs-legacy/CHANGELOG.md +++ b/demo/nextjs-legacy/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/nextjs-legacy-demo + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/nextjs-legacy-demo diff --git a/demo/nextjs-legacy/package.json b/demo/nextjs-legacy/package.json index c9d1a0e0bc8..3f5f931db95 100644 --- a/demo/nextjs-legacy/package.json +++ b/demo/nextjs-legacy/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/nextjs-legacy-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "repository": { "type": "git", diff --git a/demo/nextjs/CHANGELOG.md b/demo/nextjs/CHANGELOG.md index 487f185c711..6c59e0d4b98 100644 --- a/demo/nextjs/CHANGELOG.md +++ b/demo/nextjs/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/nextjs-demo diff --git a/demo/nextjs/package.json b/demo/nextjs/package.json index e4179f1936c..56909bd0082 100644 --- a/demo/nextjs/package.json +++ b/demo/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/nextjs-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "repository": { "type": "git", @@ -19,7 +19,7 @@ "@tsparticles/nextjs": "workspace:*", "@tsparticles/plugin-themes": "workspace:*", "@tsparticles/slim": "workspace:*", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", "next": "^16.2.8", diff --git a/demo/nuxt2/CHANGELOG.md b/demo/nuxt2/CHANGELOG.md index 5946bfab4f9..136167d27de 100644 --- a/demo/nuxt2/CHANGELOG.md +++ b/demo/nuxt2/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/nuxt2-demo diff --git a/demo/nuxt2/package.json b/demo/nuxt2/package.json index 0397f35a113..99a82d75ca5 100644 --- a/demo/nuxt2/package.json +++ b/demo/nuxt2/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/nuxt2-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "repository": { "type": "git", @@ -49,7 +49,7 @@ "eslint-config-prettier": "^10.1.8", "eslint-plugin-nuxt": "^4.0.0", "eslint-plugin-vue": "^10.9.2", - "globals": "^17.6.0", + "globals": "^17.7.0", "postcss-loader": "^4.3.0", "prettier": "^3.8.4", "ts-loader": "^8.4.0", diff --git a/demo/nuxt3/CHANGELOG.md b/demo/nuxt3/CHANGELOG.md index 9d5d82798f1..ed3e3c0a501 100644 --- a/demo/nuxt3/CHANGELOG.md +++ b/demo/nuxt3/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/nuxt3-demo diff --git a/demo/nuxt3/package.json b/demo/nuxt3/package.json index 83d39f52a04..1afa9adb526 100644 --- a/demo/nuxt3/package.json +++ b/demo/nuxt3/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/nuxt3-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "type": "module", "repository": { @@ -37,7 +37,7 @@ "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-vue": "^10.9.2", - "globals": "^17.6.0", + "globals": "^17.7.0", "lint-staged": "^17.0.7", "nuxt": "^3.21.8", "prettier": "^3.8.4", diff --git a/demo/nuxt4/CHANGELOG.md b/demo/nuxt4/CHANGELOG.md index a4973b845a6..1e90c9be1f1 100644 --- a/demo/nuxt4/CHANGELOG.md +++ b/demo/nuxt4/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/nuxt4-demo diff --git a/demo/nuxt4/package.json b/demo/nuxt4/package.json index 60aa599ef4f..e2ed8a74fed 100644 --- a/demo/nuxt4/package.json +++ b/demo/nuxt4/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/nuxt4-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "type": "module", "repository": { @@ -37,7 +37,7 @@ "eslint": "^10.5.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-vue": "^10.9.2", - "globals": "^17.6.0", + "globals": "^17.7.0", "lint-staged": "^17.0.7", "nuxt": "^4.4.8", "prettier": "^3.8.4", diff --git a/demo/preact/CHANGELOG.md b/demo/preact/CHANGELOG.md index 075b14ef632..dfbca336c10 100644 --- a/demo/preact/CHANGELOG.md +++ b/demo/preact/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/preact-demo + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/preact-demo diff --git a/demo/preact/package.json b/demo/preact/package.json index eda762665bf..116dffdbf6f 100644 --- a/demo/preact/package.json +++ b/demo/preact/package.json @@ -1,7 +1,7 @@ { "name": "@tsparticles/preact-demo", "private": true, - "version": "4.2.1", + "version": "4.3.0", "type": "module", "description": "> TODO: description", "author": "Matteo Bruni ", diff --git a/demo/qwik/CHANGELOG.md b/demo/qwik/CHANGELOG.md index 95e665d7457..4a9e84f4df7 100644 --- a/demo/qwik/CHANGELOG.md +++ b/demo/qwik/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/qwik-demo diff --git a/demo/qwik/package.json b/demo/qwik/package.json index 09ce6527517..a96ad9c5e96 100644 --- a/demo/qwik/package.json +++ b/demo/qwik/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/qwik-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "type": "module", "repository": { @@ -20,9 +20,9 @@ "tsparticles": "workspace:*" }, "devDependencies": { - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "typescript": "^6.0.3", - "vite": "^8.0.16", + "vite": "^8.1.0", "vite-tsconfig-paths": "^6.1.1" } } diff --git a/demo/react/CHANGELOG.md b/demo/react/CHANGELOG.md index 9d0ef483e98..7c7d865bb40 100644 --- a/demo/react/CHANGELOG.md +++ b/demo/react/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/react-demo diff --git a/demo/react/package.json b/demo/react/package.json index af5e0354595..c4950f104c6 100644 --- a/demo/react/package.json +++ b/demo/react/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/react-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "type": "module", "repository": { @@ -27,6 +27,6 @@ "@eslint/js": "^10.0.1", "@vitejs/plugin-react": "^6.0.2", "eslint": "^10.5.0", - "vite": "^8.0.16" + "vite": "^8.1.0" } } diff --git a/demo/riot/CHANGELOG.md b/demo/riot/CHANGELOG.md index e6a088aad02..63b66fb393a 100644 --- a/demo/riot/CHANGELOG.md +++ b/demo/riot/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/riot-demo + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/riot-demo diff --git a/demo/riot/package.json b/demo/riot/package.json index 9589bb2b45b..84f7469be8e 100644 --- a/demo/riot/package.json +++ b/demo/riot/package.json @@ -1,7 +1,7 @@ { "name": "@tsparticles/riot-demo", "private": true, - "version": "4.2.1", + "version": "4.3.0", "description": "", "main": "index.js", "repository": { diff --git a/demo/solid/CHANGELOG.md b/demo/solid/CHANGELOG.md index 128e3fb5ae6..8d78b4f5062 100644 --- a/demo/solid/CHANGELOG.md +++ b/demo/solid/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/solid-demo diff --git a/demo/solid/package.json b/demo/solid/package.json index c2ada96be57..32d7c16d906 100644 --- a/demo/solid/package.json +++ b/demo/solid/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/solid-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "description": "", "repository": { @@ -18,7 +18,7 @@ "devDependencies": { "solid-devtools": "^0.34.5", "typescript": "^6.0.3", - "vite": "^8.0.16", + "vite": "^8.1.0", "vite-plugin-solid": "^2.11.12" }, "dependencies": { diff --git a/demo/stencil/CHANGELOG.md b/demo/stencil/CHANGELOG.md index fbf1358e849..a3f55964421 100644 --- a/demo/stencil/CHANGELOG.md +++ b/demo/stencil/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/stencil-demo + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/stencil-demo diff --git a/demo/stencil/package.json b/demo/stencil/package.json index 3be89629b77..c127eac290e 100644 --- a/demo/stencil/package.json +++ b/demo/stencil/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/stencil-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "description": "Stencil demo for @tsparticles/stencil", "repository": { diff --git a/demo/svelte-kit/CHANGELOG.md b/demo/svelte-kit/CHANGELOG.md index 07fb5ddabac..1401ef7667d 100644 --- a/demo/svelte-kit/CHANGELOG.md +++ b/demo/svelte-kit/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/svelte-kit-demo + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/svelte-kit-demo diff --git a/demo/svelte-kit/package.json b/demo/svelte-kit/package.json index fac0d703bc1..48101d4f840 100644 --- a/demo/svelte-kit/package.json +++ b/demo/svelte-kit/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/svelte-kit-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "repository": { "type": "git", diff --git a/demo/svelte/CHANGELOG.md b/demo/svelte/CHANGELOG.md index 1dadc190538..6840b713279 100644 --- a/demo/svelte/CHANGELOG.md +++ b/demo/svelte/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/svelte-demo diff --git a/demo/svelte/package.json b/demo/svelte/package.json index 8f5aabf6c28..ff30994ae04 100644 --- a/demo/svelte/package.json +++ b/demo/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/svelte-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "repository": { "type": "git", @@ -21,7 +21,7 @@ "@rollup/plugin-terser": "^1.0.0", "@rollup/plugin-typescript": "^12.3.0", "@tsconfig/svelte": "^5.0.8", - "rollup": "^4.62.0", + "rollup": "^4.62.2", "rollup-plugin-css-only": "^4.5.5", "rollup-plugin-livereload": "^2.0.5", "rollup-plugin-svelte": "^7.2.3", diff --git a/demo/vanilla/CHANGELOG.md b/demo/vanilla/CHANGELOG.md index 5f7e2e23aa5..519ce0dc91e 100644 --- a/demo/vanilla/CHANGELOG.md +++ b/demo/vanilla/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + +### Features + +* added support for canvas background mask and custom draw callbacks ([74582bc](https://github.com/tsparticles/tsparticles/commit/74582bc064f174523fa8b22697b83523cccb9a19)) +* improved support for canvas background and custom draw callbacks ([a88798c](https://github.com/tsparticles/tsparticles/commit/a88798c72ff3c981fa8828bb9b51cd6f29245463)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/vanilla-demo diff --git a/demo/vanilla/app.ts b/demo/vanilla/app.ts index e17d34f55dd..fc653781103 100644 --- a/demo/vanilla/app.ts +++ b/demo/vanilla/app.ts @@ -485,6 +485,7 @@ app.use( app.use("/interaction-particles-links", express.static("./node_modules/@tsparticles/interaction-particles-links")); app.use("/shape-circle", express.static("./node_modules/@tsparticles/shape-circle")); app.use("/shape-emoji", express.static("./node_modules/@tsparticles/shape-emoji")); +app.use("/shape-gif", express.static("./node_modules/@tsparticles/shape-gif")); app.use("/shape-image", express.static("./node_modules/@tsparticles/shape-image")); app.use("/shape-line", express.static("./node_modules/@tsparticles/shape-line")); app.use("/shape-polygon", express.static("./node_modules/@tsparticles/shape-polygon")); diff --git a/demo/vanilla/package.json b/demo/vanilla/package.json index 8cf8c60cd36..031ff3844f9 100644 --- a/demo/vanilla/package.json +++ b/demo/vanilla/package.json @@ -1,7 +1,7 @@ { "name": "@tsparticles/vanilla-demo", "private": true, - "version": "4.2.1", + "version": "4.3.0", "description": "> TODO: description", "author": "Matteo Bruni ", "homepage": "https://particles.js.org", @@ -30,7 +30,7 @@ "@types/connect-livereload": "^0.6.3", "@types/express": "^5.0.6", "@types/livereload": "^0.9.5", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@types/stylus": "^0.48.43", "ace-builds": "^1.44.0", "bootstrap": "^5.3.8", @@ -376,6 +376,7 @@ "@tsparticles/shape-circle": "workspace:*", "@tsparticles/shape-cog": "workspace:*", "@tsparticles/shape-emoji": "workspace:*", + "@tsparticles/shape-gif": "workspace:*", "@tsparticles/shape-heart": "workspace:*", "@tsparticles/shape-image": "workspace:*", "@tsparticles/shape-infinity": "workspace:*", diff --git a/demo/vanilla/views/index.pug b/demo/vanilla/views/index.pug index 75cb450ac5b..b2d1c62980b 100644 --- a/demo/vanilla/views/index.pug +++ b/demo/vanilla/views/index.pug @@ -143,6 +143,7 @@ html(lang="en") script(src="/plugin-move/tsparticles.plugin.move.min.js") script(src="/shape-circle/tsparticles.shape.circle.min.js") script(src="/shape-image/tsparticles.shape.image.min.js") + script(src="/shape-gif/tsparticles.shape.gif.min.js") script(src="/shape-line/tsparticles.shape.line.min.js") script(src="/shape-polygon/tsparticles.shape.polygon.min.js") script(src="/shape-square/tsparticles.shape.square.min.js") diff --git a/demo/vanilla/views/playground.pug b/demo/vanilla/views/playground.pug index a44370a46de..5155c0968eb 100644 --- a/demo/vanilla/views/playground.pug +++ b/demo/vanilla/views/playground.pug @@ -130,6 +130,7 @@ html(lang="en") script(src="/interaction-external-parallax/tsparticles.interaction.external.parallax.js") script(src="/shape-circle/tsparticles.shape.circle.js") script(src="/shape-image/tsparticles.shape.image.js") + script(src="/shape-gif/tsparticles.shape.gif.js") script(src="/shape-line/tsparticles.shape.line.js") script(src="/shape-polygon/tsparticles.shape.polygon.js") script(src="/shape-square/tsparticles.shape.square.js") diff --git a/demo/vanilla/views/slim.pug b/demo/vanilla/views/slim.pug index 7e26c67f0b4..fc7fbd1d5b8 100644 --- a/demo/vanilla/views/slim.pug +++ b/demo/vanilla/views/slim.pug @@ -190,6 +190,7 @@ html(lang="en") script(src="/plugin-move/tsparticles.plugin.move.min.js") script(src="/shape-circle/tsparticles.shape.circle.min.js") script(src="/shape-image/tsparticles.shape.image.min.js") + script(src="/shape-gif/tsparticles.shape.gif.min.js") script(src="/shape-line/tsparticles.shape.line.min.js") script(src="/shape-polygon/tsparticles.shape.polygon.min.js") script(src="/shape-square/tsparticles.shape.square.min.js") diff --git a/demo/vanilla_new/CHANGELOG.md b/demo/vanilla_new/CHANGELOG.md index 2c7962b1237..985d50dae46 100644 --- a/demo/vanilla_new/CHANGELOG.md +++ b/demo/vanilla_new/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/vanilla-new-demo diff --git a/demo/vanilla_new/package.json b/demo/vanilla_new/package.json index 562d14c6164..d0d18dc409c 100644 --- a/demo/vanilla_new/package.json +++ b/demo/vanilla_new/package.json @@ -1,7 +1,7 @@ { "name": "@tsparticles/vanilla-new-demo", "private": true, - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles Demo Website", "main": "index.html", "scripts": { @@ -25,7 +25,7 @@ }, "homepage": "https://particles.js.org", "devDependencies": { - "@swc/core": "^1.15.41", + "@swc/core": "^1.15.43", "minify": "^15.3.1", "sass": "^1.101.0" }, diff --git a/demo/vite/CHANGELOG.md b/demo/vite/CHANGELOG.md index 5e8b6f666ec..2f9840b8632 100644 --- a/demo/vite/CHANGELOG.md +++ b/demo/vite/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/vite-demo diff --git a/demo/vite/package.json b/demo/vite/package.json index d3226ff6f2e..6605dcf3d28 100644 --- a/demo/vite/package.json +++ b/demo/vite/package.json @@ -1,7 +1,7 @@ { "name": "@tsparticles/vite-demo", "private": true, - "version": "4.2.1", + "version": "4.3.0", "type": "module", "repository": { "type": "git", @@ -22,6 +22,6 @@ }, "devDependencies": { "typescript": "^6.0.3", - "vite": "^8.0.16" + "vite": "^8.1.0" } } diff --git a/demo/vue2/CHANGELOG.md b/demo/vue2/CHANGELOG.md index fb0ccdd827d..09f3fb492c5 100644 --- a/demo/vue2/CHANGELOG.md +++ b/demo/vue2/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/vue2-demo diff --git a/demo/vue2/package.json b/demo/vue2/package.json index 190520a0adb..fd724c56964 100644 --- a/demo/vue2/package.json +++ b/demo/vue2/package.json @@ -1,7 +1,7 @@ { "name": "@tsparticles/vue2-demo", "private": true, - "version": "4.2.1", + "version": "4.3.0", "description": "VueJS Demo", "author": "Matteo Bruni ", "homepage": "https://particles.js.org", @@ -51,10 +51,10 @@ "eslint-config-prettier": "^10.1.8", "eslint-plugin-vue": "^10.9.2", "fork-ts-checker-webpack-plugin": "^9.1.0", - "globals": "^17.6.0", + "globals": "^17.7.0", "postcss": "^8.5.15", "prettier": "^3.8.4", - "rollup": "^4.62.0", + "rollup": "^4.62.2", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-typescript": "^1.0.1", "rollup-plugin-typescript2": "^0.37.0", diff --git a/demo/vue3/CHANGELOG.md b/demo/vue3/CHANGELOG.md index ecf73362d44..877d45aeb79 100644 --- a/demo/vue3/CHANGELOG.md +++ b/demo/vue3/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed angular confetti ([6f25a4a](https://github.com/tsparticles/tsparticles/commit/6f25a4a1eaa69c47f2668316e7b396fe55195f84)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/vue3-demo diff --git a/demo/vue3/package.json b/demo/vue3/package.json index f9d1c01e16d..4a3f6e42d1e 100644 --- a/demo/vue3/package.json +++ b/demo/vue3/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/vue3-demo", - "version": "4.2.1", + "version": "4.3.0", "private": true, "type": "module", "repository": { @@ -29,7 +29,7 @@ "@eslint/js": "^10.0.1", "@rushstack/eslint-patch": "^1.16.1", "@tsconfig/node18": "^18.2.6", - "@types/node": "^25.9.3", + "@types/node": "^26.0.1", "@typescript-eslint/parser": "^8.61.1", "@vitejs/plugin-vue": "^6.0.7", "@vitejs/plugin-vue-jsx": "^5.1.5", @@ -38,12 +38,12 @@ "@vue/tsconfig": "^0.9.1", "eslint": "^10.5.0", "eslint-plugin-vue": "^10.9.2", - "globals": "^17.6.0", + "globals": "^17.7.0", "minimatch": "^10.2.5", "npm-run-all": "^4.1.5", "prettier": "^3.8.4", "typescript": "^6.0.3", - "vite": "^8.0.16", + "vite": "^8.1.0", "vue-eslint-parser": "^10.4.1", "vue-tsc": "^3.3.5" } diff --git a/demo/webcomponents/CHANGELOG.md b/demo/webcomponents/CHANGELOG.md index d566a59b250..af7a2269d37 100644 --- a/demo/webcomponents/CHANGELOG.md +++ b/demo/webcomponents/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/webcomponents-demo + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/webcomponents-demo diff --git a/demo/webcomponents/package.json b/demo/webcomponents/package.json index 7eb0308d011..d4901a54dde 100644 --- a/demo/webcomponents/package.json +++ b/demo/webcomponents/package.json @@ -1,7 +1,7 @@ { "name": "@tsparticles/webcomponents-demo", "private": true, - "version": "4.2.1", + "version": "4.3.0", "description": "> TODO: description", "author": "Matteo Bruni ", "homepage": "https://particles.js.org", diff --git a/effects/bubble/CHANGELOG.md b/effects/bubble/CHANGELOG.md index 288d442082d..3c17c99bd1a 100644 --- a/effects/bubble/CHANGELOG.md +++ b/effects/bubble/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/effect-bubble + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/effect-bubble diff --git a/effects/bubble/package.dist.json b/effects/bubble/package.dist.json index d90ab906ef0..f3602714cac 100644 --- a/effects/bubble/package.dist.json +++ b/effects/bubble/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/effect-bubble", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles bubble effect", "homepage": "https://particles.js.org", "repository": { @@ -106,7 +106,7 @@ "./package.json": "./package.json" }, "peerDependencies": { - "@tsparticles/engine": "4.2.1" + "@tsparticles/engine": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/effects/bubble/package.json b/effects/bubble/package.json index 2871a841aef..de2a6458afb 100644 --- a/effects/bubble/package.json +++ b/effects/bubble/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/effect-bubble", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles effect for applying a bubbly, rounded visual effect to particle rendering", "homepage": "https://particles.js.org", "scripts": { diff --git a/effects/filter/CHANGELOG.md b/effects/filter/CHANGELOG.md index 68f304be32a..296f46d60c7 100644 --- a/effects/filter/CHANGELOG.md +++ b/effects/filter/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/effect-filter + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/effect-filter diff --git a/effects/filter/package.dist.json b/effects/filter/package.dist.json index 980cec62761..61a3cff7186 100644 --- a/effects/filter/package.dist.json +++ b/effects/filter/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/effect-filter", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles filter effect", "homepage": "https://particles.js.org", "repository": { @@ -106,7 +106,7 @@ "./package.json": "./package.json" }, "peerDependencies": { - "@tsparticles/engine": "4.2.1" + "@tsparticles/engine": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/effects/filter/package.json b/effects/filter/package.json index 029129542e6..ea0deabb79d 100644 --- a/effects/filter/package.json +++ b/effects/filter/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/effect-filter", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles effect for applying CSS filter effects (blur, grayscale, sepia, etc.) to particles", "homepage": "https://particles.js.org", "scripts": { diff --git a/effects/particles/CHANGELOG.md b/effects/particles/CHANGELOG.md index cf9a482f3db..1dfca4d8f71 100644 --- a/effects/particles/CHANGELOG.md +++ b/effects/particles/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/effect-particles + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/effect-particles diff --git a/effects/particles/package.dist.json b/effects/particles/package.dist.json index 89669642775..292b7abbb43 100644 --- a/effects/particles/package.dist.json +++ b/effects/particles/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/effect-particles", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles particles effect", "homepage": "https://particles.js.org", "repository": { @@ -106,7 +106,7 @@ "./package.json": "./package.json" }, "peerDependencies": { - "@tsparticles/engine": "4.2.1" + "@tsparticles/engine": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/effects/particles/package.json b/effects/particles/package.json index 6a346c6cfe9..9190e40604e 100644 --- a/effects/particles/package.json +++ b/effects/particles/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/effect-particles", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles effect for rendering particles as miniature particle clusters, creating fractal-like patterns", "homepage": "https://particles.js.org", "scripts": { diff --git a/effects/shadow/CHANGELOG.md b/effects/shadow/CHANGELOG.md index 6ab2b6f9278..acb450cf043 100644 --- a/effects/shadow/CHANGELOG.md +++ b/effects/shadow/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/effect-shadow + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/effect-shadow diff --git a/effects/shadow/package.dist.json b/effects/shadow/package.dist.json index 270c96bac48..841bef0276e 100644 --- a/effects/shadow/package.dist.json +++ b/effects/shadow/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/effect-shadow", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles shadow effect", "homepage": "https://particles.js.org", "repository": { @@ -106,7 +106,7 @@ "./package.json": "./package.json" }, "peerDependencies": { - "@tsparticles/engine": "4.2.1" + "@tsparticles/engine": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/effects/shadow/package.json b/effects/shadow/package.json index 5505b740845..3dd577f2a5a 100644 --- a/effects/shadow/package.json +++ b/effects/shadow/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/effect-shadow", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles effect for adding drop shadows and depth effects to particle rendering", "homepage": "https://particles.js.org", "scripts": { diff --git a/effects/trail/CHANGELOG.md b/effects/trail/CHANGELOG.md index 4fe96ca9c92..f604121e8b6 100644 --- a/effects/trail/CHANGELOG.md +++ b/effects/trail/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/effect-trail + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) **Note:** Version bump only for package @tsparticles/effect-trail diff --git a/effects/trail/package.dist.json b/effects/trail/package.dist.json index ee00402e995..29902b45779 100644 --- a/effects/trail/package.dist.json +++ b/effects/trail/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/effect-trail", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles trail effect", "homepage": "https://particles.js.org", "repository": { @@ -106,7 +106,7 @@ "./package.json": "./package.json" }, "peerDependencies": { - "@tsparticles/engine": "4.2.1" + "@tsparticles/engine": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/effects/trail/package.json b/effects/trail/package.json index 489fb288147..f8a02a5610c 100644 --- a/effects/trail/package.json +++ b/effects/trail/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/effect-trail", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles effect for creating visual motion trails that follow behind moving particles", "homepage": "https://particles.js.org", "scripts": { diff --git a/engine/CHANGELOG.md b/engine/CHANGELOG.md index 940b057c8e5..5f266f78c71 100644 --- a/engine/CHANGELOG.md +++ b/engine/CHANGELOG.md @@ -3,8 +3,33 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Bug Fixes + +* fixed some issues in deepExtend ([9d9fc9f](https://github.com/tsparticles/tsparticles/commit/9d9fc9f39fadf8d9df96f6e7b7cc8cde98e3ae21)) +* improved deepExtend ([af9d1d9](https://github.com/tsparticles/tsparticles/commit/af9d1d9f146cdc994945abf5dbc32cffbeea7b08)) + + +### Features + +* added new draw layer system ([5442bbb](https://github.com/tsparticles/tsparticles/commit/5442bbb848fde8aa7d622c5c751c7c32570d78a9)) +* added new hdr precision system ([627ec92](https://github.com/tsparticles/tsparticles/commit/627ec92fbd68cd4e776f1d912ff2ca0166603dec)) +* added new particle modifier system ([da3038e](https://github.com/tsparticles/tsparticles/commit/da3038e49b41a1025f945342603abc64a6a9bb45)) +* added support for canvas background and custom draw callbacks ([fb71bd9](https://github.com/tsparticles/tsparticles/commit/fb71bd974412666b0207b3823a81f078090357a9)) +* improved support for canvas background and custom draw callbacks ([a88798c](https://github.com/tsparticles/tsparticles/commit/a88798c72ff3c981fa8828bb9b51cd6f29245463)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) +### Features + +- added hdr precision enhancement — floating-point RGB pipeline for display-p3 colors, reduced banding and compensated animation speed in HDR mode ([#FEATURE-F](https://github.com/tsparticles/tsparticles/issues/F)) + **Note:** Version bump only for package @tsparticles/engine # [4.2.0](https://github.com/tsparticles/tsparticles/compare/v4.1.3...v4.2.0) (2026-06-17) diff --git a/engine/package.dist.json b/engine/package.dist.json index 098ab1b694e..8e2b593c0b8 100644 --- a/engine/package.dist.json +++ b/engine/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/engine", - "version": "4.2.1", + "version": "4.3.0", "description": "Easily create highly customizable particle, confetti and fireworks animations and use them as animated backgrounds for your website. Ready to use components available also for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "scripts": { diff --git a/engine/package.json b/engine/package.json index 514981ce6e2..570a1f7f10e 100644 --- a/engine/package.json +++ b/engine/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/engine", - "version": "4.2.1", + "version": "4.3.0", "description": "Easily create highly customizable particle, confetti and fireworks animations and use them as animated backgrounds for your website. Ready to use components available also for React, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Riot.js, Inferno.", "homepage": "https://particles.js.org", "scripts": { diff --git a/engine/src/Core/CanvasManager.ts b/engine/src/Core/CanvasManager.ts index 927c18c84b9..5f5b349a04c 100644 --- a/engine/src/Core/CanvasManager.ts +++ b/engine/src/Core/CanvasManager.ts @@ -444,6 +444,7 @@ export class CanvasManager { container.actualOptions.hdr && safeMatchMedia("(color-gamut: p3)")?.matches && safeMatchMedia("(dynamic-range: high)")?.matches; + this.render.setContextSettings({ alpha: true, desynchronized: true, @@ -452,6 +453,7 @@ export class CanvasManager { ? { colorSpace: "display-p3" as const, colorType: "float16" as const } : { colorSpace: "srgb" as const }), }); + const renderCanvas = this.renderCanvas; if (!renderCanvas) { diff --git a/engine/src/Core/Interfaces/IBubbleParticleData.ts b/engine/src/Core/Interfaces/IBubbleParticleData.ts deleted file mode 100644 index f8551738f25..00000000000 --- a/engine/src/Core/Interfaces/IBubbleParticleData.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { IHsl } from "./Colors.js"; - -/** Bubble effect data for a particle */ -export interface IBubbleParticleData { - /** Bubble color */ - color?: IHsl; - /** Optional div element for hover bubbles */ - div?: HTMLElement; - /** Final calculated bubble color */ - finalColor?: IHsl; - /** Whether the particle is within bubble range */ - inRange: boolean; - /** Bubble opacity */ - opacity?: number; - /** Bubble radius */ - radius?: number; -} diff --git a/engine/src/Core/Interfaces/IContainerPlugin.ts b/engine/src/Core/Interfaces/IContainerPlugin.ts index 068a74325cb..f35c5b815c0 100644 --- a/engine/src/Core/Interfaces/IContainerPlugin.ts +++ b/engine/src/Core/Interfaces/IContainerPlugin.ts @@ -1,3 +1,4 @@ +import type { DrawLayer } from "../../Enums/DrawLayer.js"; import type { ExportResult } from "../../Types/ExportResult.js"; import type { ICoordinates } from "./ICoordinates.js"; import type { IDelta } from "./IDelta.js"; @@ -38,6 +39,17 @@ export interface IContainerPlugin { export?: (type: string, data: Record) => Promise; /** Initializes the plugin */ init?: () => Promise; + /** + * Primary draw layer for this plugin. When set, identifies the plugin's main rendering layer. + * The actual layer assignment in {@link RenderManager.initPlugins} is based on ALL hook methods + * the plugin implements (e.g., `drawSettingsSetup`→CanvasSetup, `canvasPaint`→BackgroundMask, + * `drawSettingsCleanup`/`clearDraw`→CanvasCleanup), so a plugin can be active on multiple layers. + * + * This property serves as documentation of the plugin's primary rendering role and is used + * as a fallback for layers that have no dedicated hook method. + * @see DrawLayer + */ + layer?: DrawLayer; /** Handles particle bounce with the given direction */ particleBounce?: (particle: Particle, delta: IDelta, direction: OutModeDirection) => boolean; /** Called when a particle is created */ diff --git a/engine/src/Core/Interfaces/IParticleModifier.ts b/engine/src/Core/Interfaces/IParticleModifier.ts new file mode 100644 index 00000000000..bf9e1732840 --- /dev/null +++ b/engine/src/Core/Interfaces/IParticleModifier.ts @@ -0,0 +1,21 @@ +import type { IHsl } from "./Colors.js"; + +/** Particle modifier interface for dynamic property overrides */ +export interface IParticleModifier { + /** Whether this modifier is active */ + readonly enabled: boolean; + /** Modified fill color override */ + readonly fillColor?: IHsl; + /** Unique identifier for this modifier (used to remove it later) */ + readonly id: string; + /** Modified opacity override */ + readonly opacity?: number; + /** Priority: higher number = applied later (overrides lower priorities) */ + readonly priority: number; + /** Modified radius override */ + readonly radius?: number; + /** Modified movement speed factor override */ + readonly speedFactor?: number; + /** Modified stroke color override */ + readonly strokeColor?: IHsl; +} diff --git a/engine/src/Core/Interfaces/ISlowParticleData.ts b/engine/src/Core/Interfaces/ISlowParticleData.ts deleted file mode 100644 index 9d275e5ff13..00000000000 --- a/engine/src/Core/Interfaces/ISlowParticleData.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** Slow effect data for a particle */ -export interface ISlowParticleData { - /** Slow factor applied to the particle */ - factor: number; - /** Whether the particle is within slow range */ - inRange: boolean; -} diff --git a/engine/src/Core/Particle.ts b/engine/src/Core/Particle.ts index f36fe5473e5..aa96ad7e2b4 100644 --- a/engine/src/Core/Particle.ts +++ b/engine/src/Core/Particle.ts @@ -32,12 +32,12 @@ import { } from "./Utils/Constants.js"; import type { Container } from "./Container.js"; import { EventType } from "../Enums/Types/EventType.js"; -import type { IBubbleParticleData } from "./Interfaces/IBubbleParticleData.js"; import type { IDelta } from "./Interfaces/IDelta.js"; import type { IEffect } from "../Options/Interfaces/Particles/Effect/IEffect.js"; import type { IEffectDrawer } from "./Interfaces/IEffectDrawer.js"; import type { IHsl } from "./Interfaces/Colors.js"; import type { IParticleHslAnimation } from "./Interfaces/IParticleHslAnimation.js"; +import type { IParticleModifier } from "./Interfaces/IParticleModifier.js"; import type { IParticleNumericValueAnimation } from "./Interfaces/IParticleValueAnimation.js"; import type { IParticleOpacityData } from "./Interfaces/IParticleOpacityData.js"; import type { IParticleRetinaProps } from "./Interfaces/IParticleRetinaProps.js"; @@ -49,7 +49,6 @@ import type { IParticlesOptions } from "../Options/Interfaces/Particles/IParticl import type { IShape } from "../Options/Interfaces/Particles/Shape/IShape.js"; import type { IShapeDrawer } from "./Interfaces/IShapeDrawer.js"; import type { IShapeValues } from "./Interfaces/IShapeValues.js"; -import type { ISlowParticleData } from "./Interfaces/ISlowParticleData.js"; import { MoveDirection } from "../Enums/Directions/MoveDirection.js"; import { OutMode } from "../Enums/Modes/OutMode.js"; import { OutModeDirection } from "../Enums/Directions/OutModeDirection.js"; @@ -377,11 +376,6 @@ export class Particle { */ backColor?: IHsl; - /** - * Gets particles bubble data - */ - bubble!: IBubbleParticleData; - /** * Checks if the particle is destroyed */ @@ -535,11 +529,6 @@ export class Particle { */ size!: IParticleNumericValueAnimation; - /** - * Gets particle slow options - */ - slow!: ISlowParticleData; - /** * Check if the particle is spawning, and can't be touched */ @@ -592,6 +581,8 @@ export class Particle { readonly #container; + readonly #modifiers: IParticleModifier[] = []; + /** * Gets the particle containing engine instance * @internal @@ -603,6 +594,22 @@ export class Particle { this.#container = container; } + /** + * Adds a modifier to this particle, sorted by priority + * @param modifier - The modifier to add + */ + addModifier(modifier: IParticleModifier): void { + this.#modifiers.push(modifier); + this.#modifiers.sort((a, b) => a.priority - b.priority); + } + + /** + * Removes all modifiers from this particle + */ + clearModifiers(): void { + this.#modifiers.length = 0; + } + /** * Destroys the particle * @param override - The override @@ -613,8 +620,7 @@ export class Particle { } this.destroyed = true; - this.bubble.inRange = false; - this.slow.inRange = false; + this.clearModifiers(); const container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined; @@ -659,7 +665,7 @@ export class Particle { * @returns the fill color object */ getFillColor(): IHsl | undefined { - return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.fillColor)); + return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.fillColor), m => m.fillColor)); } /** @@ -670,6 +676,15 @@ export class Particle { return this.getRadius() ** squareExp * Math.PI * half; } + /** + * Gets a modifier by its id + * @param id - The modifier id to find + * @returns the modifier or undefined + */ + getModifier(id: string): IParticleModifier | undefined { + return this.#modifiers.find(m => m.id === id); + } + /** * Gets the particle opacity * @returns the opacity object @@ -678,7 +693,9 @@ export class Particle { const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, - opacity = this.bubble.opacity ?? getRangeValue(this.opacity?.value ?? defaultOpacity), + baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity), + modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), + opacity = modifierOpacity ?? baseOpacity, fillOpacity = this.fillOpacity ?? defaultOpacity, strokeOpacity = this.strokeOpacity ?? defaultOpacity; @@ -706,7 +723,7 @@ export class Particle { * @returns the particle radius */ getRadius(): number { - return this.bubble.radius ?? this.size.value; + return this.#applyModifiers(this.size.value, m => m.radius); } /** @@ -727,7 +744,7 @@ export class Particle { * @returns the stroke color */ getStrokeColor(): IHsl | undefined { - return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.strokeColor)); + return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.strokeColor), m => m.strokeColor)); } /** @@ -775,14 +792,6 @@ export class Particle { runUpdaterPreInit(container.particleUpdaters, this); /* position */ - this.bubble = { - inRange: false, - }; - this.slow = { - inRange: false, - factor: 1, - }; - this.#initPosition(position); /* animation - velocity for speed */ @@ -863,6 +872,18 @@ export class Particle { return !this.destroyed && !this.spawning && this.isInsideCanvas(); } + /** + * Removes a modifier by its id + * @param id - The modifier id to remove + */ + removeModifier(id: string): void { + const idx = this.#modifiers.findIndex(m => m.id === id); + + if (idx >= defaultAngle) { + this.#modifiers.splice(idx, identity); + } + } + /** * This method is used when the particle has lost a life and needs some value resets */ @@ -872,6 +893,22 @@ export class Particle { } } + #applyModifiers(base: T, getter: (mod: IParticleModifier) => T | undefined): T { + let value = base; + + for (const mod of this.#modifiers) { + if (mod.enabled) { + const override = getter(mod); + + if (override !== undefined) { + value = override; + } + } + } + + return value; + } + #calcPosition(position: ICoordinates | undefined, zIndex: number): Vector3d | undefined { let tryCount = defaultRetryCount, posVec = position ? Vector3d.create(position.x, position.y, zIndex) : undefined; diff --git a/engine/src/Core/RenderManager.ts b/engine/src/Core/RenderManager.ts index 5ebe016031e..c7ca931bd4c 100644 --- a/engine/src/Core/RenderManager.ts +++ b/engine/src/Core/RenderManager.ts @@ -10,6 +10,7 @@ import { import { getStyleFromHsl, rangeColorToHsl } from "../Utils/ColorUtils.js"; import type { CanvasManager } from "./CanvasManager.js"; import type { Container } from "./Container.js"; +import { DrawLayer } from "../Enums/DrawLayer.js"; import type { IContainerPlugin } from "./Interfaces/IContainerPlugin.js"; import type { IDelta } from "./Interfaces/IDelta.js"; import type { IDrawParticleParams } from "./Interfaces/IDrawParticleParams.js"; @@ -22,6 +23,7 @@ import type { IShapeDrawData } from "./Interfaces/IShapeDrawData.js"; import type { IShapeDrawer } from "./Interfaces/IShapeDrawer.js"; import type { Particle } from "./Particle.js"; import type { PluginManager } from "./Utils/PluginManager.js"; +import { getLogger } from "../Utils/LogUtils.js"; const fColorIndex = 0, sColorIndex = 1; @@ -47,10 +49,10 @@ function setTransformValue( * Canvas manager */ export class RenderManager { + #backgroundElement: CanvasImageSource | null; + readonly #backgroundWarnings: Set; #canvasClearPlugins: IContainerPlugin[]; readonly #canvasManager: CanvasManager; - #canvasPaintPlugins: IContainerPlugin[]; - #clearDrawPlugins: IContainerPlugin[]; #colorPlugins: IContainerPlugin[]; readonly #container; /** @@ -61,9 +63,16 @@ export class RenderManager { #drawParticlePlugins: IContainerPlugin[]; #drawParticlesCleanupPlugins: IContainerPlugin[]; #drawParticlesSetupPlugins: IContainerPlugin[]; - #drawPlugins: IContainerPlugin[]; - #drawSettingsCleanupPlugins: IContainerPlugin[]; - #drawSettingsSetupPlugins: IContainerPlugin[]; + /** + * Layer-based plugin storage: each plugin is pushed to ALL layers where it has relevant hooks. + * For example, a plugin implementing both `canvasPaint` and `drawSettingsSetup` appears in + * both `BackgroundMask` and `CanvasSetup` layers. + * + * Populated by {@link initPlugins} and consumed by {@link drawParticles} which iterates + * layers 0-7 in ordinal order. + * @see DrawLayer + */ + #layers: Record; readonly #pluginManager; #postDrawUpdaters: IParticleUpdater[]; #preDrawUpdaters: IParticleUpdater[]; @@ -82,18 +91,25 @@ export class RenderManager { this.#container = container; this.#canvasManager = canvasManager; this.#context = null; + this.#backgroundElement = null; + this.#backgroundWarnings = new Set(); this.#preDrawUpdaters = []; this.#postDrawUpdaters = []; - this.#colorPlugins = []; this.#canvasClearPlugins = []; - this.#canvasPaintPlugins = []; - this.#clearDrawPlugins = []; + this.#colorPlugins = []; this.#drawParticlePlugins = []; this.#drawParticlesCleanupPlugins = []; this.#drawParticlesSetupPlugins = []; - this.#drawPlugins = []; - this.#drawSettingsSetupPlugins = []; - this.#drawSettingsCleanupPlugins = []; + this.#layers = { + 0: [], + 1: [], + 2: [], + 3: [], + 4: [], + 5: [], + 6: [], + 7: [], + }; } /** @@ -116,21 +132,33 @@ export class RenderManager { } /** - * Clears the canvas content + * Clears the canvas content through the layer system. + * + * First checks plugins registered in the dedicated `#canvasClearPlugins` array (plugins that + * implement `canvasClear` as their only rendering hook, e.g. trail), then iterates all layers + * in ordinal order (0–7) for any additional `canvasClear` implementations. + * + * The first plugin that returns `true` short-circuits the clear. If no plugin handles it, + * falls back to {@link canvasClear} which respects `actualOptions.clear`. + * @see IContainerPlugin.canvasClear */ clear(): void { - let pluginHandled = false; - + /* check dedicated canvasClear plugins first (e.g. trail, which has no layer hooks) */ for (const plugin of this.#canvasClearPlugins) { - pluginHandled = plugin.canvasClear?.() ?? false; - - if (pluginHandled) { - break; + if (plugin.canvasClear?.() ?? false) { + return; } } - if (pluginHandled) { - return; + /* then check all layer plugins */ + for (const layer of Object.values(DrawLayer)) { + if (typeof layer === "number") { + for (const plugin of this.#getLayerPlugins(layer)) { + if (plugin.canvasClear?.() ?? false) { + return; + } + } + } } this.canvasClear(); @@ -142,18 +170,20 @@ export class RenderManager { destroy(): void { this.stop(); + this.#backgroundElement = null; + this.#backgroundWarnings.clear(); this.#preDrawUpdaters = []; this.#postDrawUpdaters = []; - this.#colorPlugins = []; this.#canvasClearPlugins = []; - this.#canvasPaintPlugins = []; - this.#clearDrawPlugins = []; + this.#colorPlugins = []; this.#drawParticlePlugins = []; this.#drawParticlesCleanupPlugins = []; this.#drawParticlesSetupPlugins = []; - this.#drawPlugins = []; - this.#drawSettingsSetupPlugins = []; - this.#drawSettingsCleanupPlugins = []; + for (const layer of Object.values(DrawLayer)) { + if (typeof layer === "number") { + this.#layers[layer] = []; + } + } } /** @@ -253,11 +283,22 @@ export class RenderManager { } /** - * Draws all particles for the current frame + * Draws all particles for the current frame via the layer-based rendering pipeline. + * + * Layer order (back to front): + * 0. BackgroundElement — auto-draw `background.element` via `ctx.drawImage` + * 1. BackgroundDraw — execute `background.draw(ctx, delta)` callback + * 2. BackgroundMask — `plugin.canvasPaint()` for each plugin + * 3. CanvasSetup — `plugin.drawSettingsSetup(ctx, delta)` for each plugin + * 4. PluginContent — `plugin.draw(ctx, delta)` for each plugin + * 5. Particles — `particles.drawParticles(delta)` (core particle rendering) + * 6. CanvasCleanup — `plugin.clearDraw()` + `plugin.drawSettingsCleanup()` for each plugin + * 7. Foreground — reserved for future overlay/fx * @param delta - The delta time + * @see DrawLayer */ drawParticles(delta: IDelta): void { - const { particles } = this.#container; + const { particles, actualOptions } = this.#container; this.clear(); @@ -265,23 +306,54 @@ export class RenderManager { particles.update(delta); this.draw(ctx => { - for (const plugin of this.#drawSettingsSetupPlugins) { + const width = this.#canvasManager.size.width, + height = this.#canvasManager.size.height; + + /* Layer 0 — BackgroundElement: background.element auto-draw */ + if (this.#backgroundElement) { + try { + ctx.drawImage(this.#backgroundElement, originPoint.x, originPoint.y, width, height); + } catch { + this.#warnOnce("background-element-draw-error", "Error drawing background element onto canvas"); + } + } + + /* Layer 1 — BackgroundDraw: background.draw callback */ + const background = actualOptions.background; + + if (background.draw) { + try { + background.draw(ctx, delta); + } catch { + this.#warnOnce("background-draw-error", "Error in background.draw callback"); + } + } + + /* Layer 2 — BackgroundMask: plugin canvasPaint */ + for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) { + plugin.canvasPaint?.(); + } + + /* Layer 3 — CanvasSetup: plugin drawSettingsSetup */ + for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) { plugin.drawSettingsSetup?.(ctx, delta); } - for (const plugin of this.#drawPlugins) { + /* Layer 4 — PluginContent: plugin draw behind particles */ + for (const plugin of this.#getLayerPlugins(DrawLayer.PluginContent)) { plugin.draw?.(ctx, delta); } + /* Layer 5 — Particles */ particles.drawParticles(delta); - for (const plugin of this.#clearDrawPlugins) { + /* Layer 6 — CanvasCleanup: plugin clearDraw + drawSettingsCleanup */ + for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasCleanup)) { plugin.clearDraw?.(ctx, delta); - } - - for (const plugin of this.#drawSettingsCleanupPlugins) { plugin.drawSettingsCleanup?.(ctx, delta); } + + /* Layer 7 — Foreground: reserved */ }); } @@ -291,37 +363,42 @@ export class RenderManager { init(): void { this.initUpdaters(); this.initPlugins(); + this.#resolveBackgroundElement(); this.paint(); } /** - * Initializes the plugins needed by canvas + * Initializes the plugins needed by canvas. + * + * Assigns each plugin to ALL layers where it has relevant hooks, not just one primary layer. + * This enables plugins like {@link BackgroundMaskPluginInstance} that implement multiple hooks + * (`canvasPaint`→BackgroundMask, `drawSettingsSetup`→CanvasSetup, `drawSettingsCleanup`→CanvasCleanup) + * to participate in all the layers they need. + * + * Hook-independent features (`particleFillColor`, `particleStrokeColor`, `drawParticle`, + * `drawParticleSetup`, `drawParticleCleanup`) are collected into separate arrays for + * per-particle use during rendering. + * @see DrawLayer + * @see IContainerPlugin */ initPlugins(): void { - this.#colorPlugins = []; this.#canvasClearPlugins = []; - this.#canvasPaintPlugins = []; - this.#clearDrawPlugins = []; + this.#colorPlugins = []; this.#drawParticlePlugins = []; this.#drawParticlesSetupPlugins = []; this.#drawParticlesCleanupPlugins = []; - this.#drawPlugins = []; - this.#drawSettingsSetupPlugins = []; - this.#drawSettingsCleanupPlugins = []; + + for (const layer of Object.values(DrawLayer)) { + if (typeof layer === "number") { + this.#layers[layer] = []; + } + } for (const plugin of this.#container.plugins) { if (plugin.particleFillColor ?? plugin.particleStrokeColor) { this.#colorPlugins.push(plugin); } - if (plugin.canvasClear) { - this.#canvasClearPlugins.push(plugin); - } - - if (plugin.canvasPaint) { - this.#canvasPaintPlugins.push(plugin); - } - if (plugin.drawParticle) { this.#drawParticlePlugins.push(plugin); } @@ -334,20 +411,25 @@ export class RenderManager { this.#drawParticlesCleanupPlugins.push(plugin); } - if (plugin.draw) { - this.#drawPlugins.push(plugin); + if (plugin.canvasClear) { + this.#canvasClearPlugins.push(plugin); + } + + /* assign plugin to all layers where it has relevant hooks */ + if (plugin.canvasPaint) { + this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin); } if (plugin.drawSettingsSetup) { - this.#drawSettingsSetupPlugins.push(plugin); + this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin); } - if (plugin.drawSettingsCleanup) { - this.#drawSettingsCleanupPlugins.push(plugin); + if (plugin.draw) { + this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin); } - if (plugin.clearDraw) { - this.#clearDrawPlugins.push(plugin); + if (plugin.clearDraw ?? plugin.drawSettingsCleanup) { + this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin); } } } @@ -376,7 +458,7 @@ export class RenderManager { paint(): void { let handled = false; - for (const plugin of this.#canvasPaintPlugins) { + for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) { handled = plugin.canvasPaint?.() ?? false; if (handled) { @@ -650,6 +732,10 @@ export class RenderManager { drawer.beforeDraw(data); } + #getLayerPlugins(layer: DrawLayer): IContainerPlugin[] { + return this.#layers[layer]; + } + #getPluginParticleColors(particle: Particle): (IHsl | undefined)[] { let fColor: IHsl | undefined, sColor: IHsl | undefined; @@ -672,4 +758,49 @@ export class RenderManager { return this.#reusablePluginColors; } + + #resolveBackgroundElement(): void { + const background = this.#container.actualOptions.background; + + this.#backgroundElement = null; + + if (!background.element) { + return; + } + + if (typeof background.element === "string") { + if (typeof document !== "undefined") { + const node = document.querySelector(background.element); + + if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) { + this.#backgroundElement = node; + } else if (node) { + this.#warnOnce( + "background-element-not-supported", + `Background element "${background.element}" is not a supported drawable element (canvas, video, or img)`, + ); + } else { + this.#warnOnce( + "background-element-not-found", + `Background element selector "${background.element}" not found`, + ); + } + } + } else if ( + background.element instanceof HTMLCanvasElement || + background.element instanceof OffscreenCanvas || + background.element instanceof HTMLVideoElement || + background.element instanceof HTMLImageElement + ) { + this.#backgroundElement = background.element; + } + } + + #warnOnce(key: string, message: string): void { + if (!this.#backgroundWarnings.has(key)) { + this.#backgroundWarnings.add(key); + + getLogger().warning(message); + } + } } diff --git a/engine/src/Enums/DrawLayer.ts b/engine/src/Enums/DrawLayer.ts new file mode 100644 index 00000000000..048c7c97f3e --- /dev/null +++ b/engine/src/Enums/DrawLayer.ts @@ -0,0 +1,58 @@ +/** + * Fixed ordinal layer positions for the RenderManager layer-based rendering pipeline. + * + * Each layer has a fixed position that determines drawing order (0 = back, 7 = front). + * Plugins declare their layer via {@link IContainerPlugin.layer} or get assigned to all + * applicable layers based on which hook methods they implement. + * + * The pipeline in {@link RenderManager.drawParticles} iterates these layers in order: + * 0 BackgroundElement → 1 BackgroundDraw → 2 BackgroundMask → 3 CanvasSetup → + * 4 PluginContent → 5 Particles → 6 CanvasCleanup → 7 Foreground + */ +export enum DrawLayer { + /** + * Auto-draw the CSS background element (`background.element`) via `ctx.drawImage`. + * Handled inline by RenderManager, not by plugins. + */ + BackgroundElement = 0, + /** + * Execute the `background.draw(ctx, delta)` callback on the main canvas context. + * Handled inline by RenderManager, not by plugins. + */ + BackgroundDraw = 1, + /** + * Background mask overlay: calls `plugin.canvasPaint()` on all plugins in this layer. + * Used by {@link BackgroundMaskPluginInstance} to draw the mask before particle compositing. + * @see BackgroundMaskPluginInstance.canvasPaint + */ + BackgroundMask = 2, + /** + * Plugin draw setup: calls `plugin.drawSettingsSetup(ctx, delta)` on all plugins in this layer. + * Used by zoom, blend, and backgroundMask plugins to configure canvas state (composite mode, transforms) + * before particles are drawn. + * @see IContainerPlugin.drawSettingsSetup + */ + CanvasSetup = 3, + /** + * Plugin content drawn behind particles: calls `plugin.draw(ctx, delta)` on all plugins in this layer. + * @see IContainerPlugin.draw + */ + PluginContent = 4, + /** + * Particle rendering (z-bucketed). Calls `particles.drawParticles(delta)` — this is the core + * particle rendering step, not a plugin hook. + */ + Particles = 5, + /** + * Plugin draw cleanup: calls `plugin.clearDraw(ctx, delta)` then `plugin.drawSettingsCleanup(ctx, delta)` + * on all plugins in this layer. Restores canvas state after particle rendering. + * @see IContainerPlugin.clearDraw + * @see IContainerPlugin.drawSettingsCleanup + */ + CanvasCleanup = 6, + /** + * Reserved for overlay/fx on top of everything. No default behavior — available for future + * plugins that need to render above particles. + */ + Foreground = 7, +} diff --git a/engine/src/Options/Classes/Background/Background.ts b/engine/src/Options/Classes/Background/Background.ts index 8d5e075916e..d0524cf7817 100644 --- a/engine/src/Options/Classes/Background/Background.ts +++ b/engine/src/Options/Classes/Background/Background.ts @@ -1,5 +1,6 @@ +import type { BackgroundDrawContext, IBackground } from "../../Interfaces/Background/IBackground.js"; import { OptionLoader, loadProperty } from "../../../Utils/OptionsUtils.js"; -import type { IBackground } from "../../Interfaces/Background/IBackground.js"; +import type { IDelta } from "../../../Core/Interfaces/IDelta.js"; import { OptionsColor } from "../OptionsColor.js"; import type { RecursivePartial } from "../../../Types/RecursivePartial.js"; @@ -8,6 +9,8 @@ import type { RecursivePartial } from "../../../Types/RecursivePartial.js"; */ export class Background extends OptionLoader implements IBackground { color: OptionsColor; + draw?: (context: BackgroundDrawContext, delta: IDelta) => void; + element?: string | HTMLCanvasElement | OffscreenCanvas | HTMLVideoElement | HTMLImageElement; image = ""; opacity = 1; position = ""; @@ -25,6 +28,8 @@ export class Background extends OptionLoader implements IBackground this.color = OptionsColor.create(this.color, data.color); } + loadProperty(this, "element", data.element); + loadProperty(this, "draw", data.draw as typeof this.draw); loadProperty(this, "image", data.image); loadProperty(this, "position", data.position); loadProperty(this, "repeat", data.repeat); diff --git a/engine/src/Options/Interfaces/Background/IBackground.ts b/engine/src/Options/Interfaces/Background/IBackground.ts index b003a90d54b..26a525e46c9 100644 --- a/engine/src/Options/Interfaces/Background/IBackground.ts +++ b/engine/src/Options/Interfaces/Background/IBackground.ts @@ -1,5 +1,8 @@ +import type { IDelta } from "../../../Core/Interfaces/IDelta.js"; import type { IOptionsColor } from "../IOptionsColor.js"; +export type BackgroundDrawContext = OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D; + /** * The background options used by the canvas element, it's not drawn, it's applied in the style * [[include:Options/Background.md]] @@ -12,6 +15,20 @@ export interface IBackground { */ color: string | IOptionsColor; + /** + * An optional per-frame callback for custom background rendering. + * When specified, it is called each frame after the canvas is cleared and before particles are drawn. + * The callback receives the drawing context and delta time. + */ + draw?: (context: BackgroundDrawContext, delta: IDelta) => void; + + /** + * An optional external element (CSS selector, canvas, video, image, or OffscreenCanvas) that is + * auto-drawn onto the main canvas each frame via ctx.drawImage(). + * The element is not managed by the engine — external code handles its rendering. + */ + element?: string | HTMLCanvasElement | OffscreenCanvas | HTMLVideoElement | HTMLImageElement; + /** * The `image` property sets the canvas style `background-image` property. * diff --git a/engine/src/Utils/ColorUtils.ts b/engine/src/Utils/ColorUtils.ts index 7be9b500434..2b5a42df4b8 100644 --- a/engine/src/Utils/ColorUtils.ts +++ b/engine/src/Utils/ColorUtils.ts @@ -54,7 +54,10 @@ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, - sdrReferenceWhiteNits = 203; + hdrRgbFixedPrecision = 4, + hdrHslFixedPrecision = 4, + sdrReferenceWhiteNits = 203, + hdrAnimationScale = sdrReferenceWhiteNits / maxNits; /** * Generic cache function for color styles @@ -348,6 +351,38 @@ export function hslToRgb(hsl: IHsl): IRgb { return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) }; } +/** + * + * @param hsl - The HSL color + * @returns The result with floating-point RGB values (0.0-255.0) + */ +export function hslToRgbFloat(hsl: IHsl): IRgb { + const h = ((hsl.h % hMax) + hMax) % hMax, + s = Math.max(sMin, Math.min(sMax, hsl.s)), + l = Math.max(lMin, Math.min(lMax, hsl.l)), + hNormalized = h / hMax, + sNormalized = s / sMax, + lNormalized = l / lMax; + + if (s === sMin) { + const grayscaleValue = lNormalized * rgbMax; + + return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue }; + } + + const temp1 = + lNormalized < half + ? lNormalized * (sNormalizedOffset + sNormalized) + : lNormalized + sNormalized - lNormalized * sNormalized, + temp2 = double * lNormalized - temp1, + phaseThird = phaseNumerator / triple, + red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), + green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), + blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird)); + + return { r: red, g: green, b: blue }; +} + /** * Converts HSLA color to RGBA color * @param hsla - the HSLA color to convert @@ -367,11 +402,21 @@ export function hslaToRgba(hsla: IHsla): IRgba { /** * Returns a random ({@link IRgb}) color * @param min - the minimum value for the color + * @param hdr * @returns the random ({@link IRgb}) color */ -export function getRandomRgbColor(min?: number): IRgb { - const fixedMin = min ?? defaultRgbMin, - fixedMax = rgbMax + identity, +export function getRandomRgbColor(min?: number, hdr?: boolean): IRgb { + const fixedMin = min ?? defaultRgbMin; + + if (hdr) { + return { + r: getRandomInRange(fixedMin, rgbMax), + g: getRandomInRange(fixedMin, rgbMax), + b: getRandomInRange(fixedMin, rgbMax), + }; + } + + const fixedMax = rgbMax + identity, getRgbInRangeValue = (): number => Math.floor(getRandomInRange(fixedMin, fixedMax)); return { @@ -389,8 +434,9 @@ export function getRandomRgbColor(min?: number): IRgb { * @returns the CSS style string */ export function getStyleFromRgb(color: IRgb, hdr: boolean, opacity?: number): string { - const op = opacity ?? defaultOpacity, - key = `rgb-${color.r.toFixed(rgbFixedPrecision)}-${color.g.toFixed(rgbFixedPrecision)}-${color.b.toFixed(rgbFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`; + const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, + op = opacity ?? defaultOpacity, + key = `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`; return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity))); } @@ -426,12 +472,13 @@ function getSdrStyleFromRgb(color: IRgb, opacity?: number): string { * @returns the CSS style string */ export function getStyleFromHsl(color: IHsl, hdr: boolean, opacity?: number): string { - const op = opacity ?? defaultOpacity, - key = `hsl-${color.h.toFixed(hslFixedPrecision)}-${color.s.toFixed(hslFixedPrecision)}-${color.l.toFixed(hslFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`; + const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, + op = opacity ?? defaultOpacity, + key = `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`; return getCachedStyle(key, () => hdr - ? getStyleFromRgb(hslToRgb(color), true, opacity) + ? getStyleFromRgb(hslToRgbFloat(color), true, opacity) : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`, ); } @@ -628,8 +675,9 @@ function setColorAnimation( * @param data - the color animation data * @param decrease - whether the color should decrease over time * @param delta - the frame delta time + * @param hdr */ -export function updateColorValue(data: IParticleColorAnimation, decrease: boolean, delta: IDelta): void { +export function updateColorValue(data: IParticleColorAnimation, decrease: boolean, delta: IDelta, hdr?: boolean): void { const minLoops = 0, minDelay = 0, identity = 1, @@ -655,7 +703,8 @@ export function updateColorValue(data: IParticleColorAnimation, decrease: boolea } const offset = data.offset ? randomInRangeValue(data.offset) : minOffset, - velocity = (data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor, + velocity = + ((data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor) * (hdr ? hdrAnimationScale : identity), decay = data.decay ?? identity, max = data.max, min = data.min; @@ -695,17 +744,18 @@ export function updateColorValue(data: IParticleColorAnimation, decrease: boolea * Updates all HSL color channels for the current frame * @param color - the HSL animation to update * @param delta - the frame delta time + * @param hdr */ -export function updateColor(color: IParticleHslAnimation | undefined, delta: IDelta): void { +export function updateColor(color: IParticleHslAnimation | undefined, delta: IDelta, hdr?: boolean): void { if (!color) { return; } const { h, s, l } = color; - updateColorValue(h, false, delta); - updateColorValue(s, true, delta); - updateColorValue(l, true, delta); + updateColorValue(h, false, delta, hdr); + updateColorValue(s, true, delta, hdr); + updateColorValue(l, true, delta, hdr); } /** diff --git a/engine/src/Utils/Utils.ts b/engine/src/Utils/Utils.ts index 489f26f3f82..63723dd59dc 100644 --- a/engine/src/Utils/Utils.ts +++ b/engine/src/Utils/Utils.ts @@ -168,15 +168,13 @@ export function deepExtend(destination: unknown, ...sources: unknown[]): unknown destination = []; } } else if (!isObject(destination) || Array.isArray(destination)) { - destination = {}; + destination = Object.create(null) as Record; } // Micro-optimization + safety: if the source is a shallow object (no nested objects/arrays), // perform a fast shallow copy for common-case merges. Also explicitly ignore dangerous - // prototype/constructor keys to avoid prototype pollution. See .planning/research/PITFALLS.md - // for rationale. + // prototype/constructor keys to avoid prototype pollution. const sourceKeys = Object.keys(source), - dangerousKeys = new Set(["__proto__", "constructor", "prototype"]), // Detect if the source contains nested structures that need full deep merging hasNested = sourceKeys.some(k => { const v = (source as Record)[k]; @@ -190,17 +188,14 @@ export function deepExtend(destination: unknown, ...sources: unknown[]): unknown destDict = destination as Record; for (const key of sourceKeys) { - if (dangerousKeys.has(key)) { + if (key === "__proto__" || key === "constructor" || key === "prototype") { continue; } - // Avoid assigning undefined keys and preserve type-safety - if (key in sourceDict) { - const v = sourceDict[key]; + const v = sourceDict[key]; - if (v !== undefined) { - destDict[key] = v; - } + if (v !== undefined) { + destDict[key] = v; } } @@ -208,7 +203,7 @@ export function deepExtend(destination: unknown, ...sources: unknown[]): unknown } for (const key of sourceKeys) { - if (dangerousKeys.has(key)) { + if (key === "__proto__" || key === "constructor" || key === "prototype") { continue; } diff --git a/engine/src/export-types.ts b/engine/src/export-types.ts index 4cb882f1001..2ffcf21d7c5 100644 --- a/engine/src/export-types.ts +++ b/engine/src/export-types.ts @@ -1,6 +1,6 @@ export type * from "./Core/Interfaces/Colors.js"; export type * from "./Core/Interfaces/IBounds.js"; -export type * from "./Core/Interfaces/IBubbleParticleData.js"; + export type * from "./Core/Interfaces/ICircleBouncer.js"; export type * from "./Core/Interfaces/IColorManager.js"; export type * from "./Core/Interfaces/IContainerPlugin.js"; @@ -16,6 +16,7 @@ export type * from "./Core/Interfaces/IParticleCanvasBounds.js"; export type * from "./Core/Interfaces/IParticleColorStyle.js"; export type * from "./Core/Interfaces/IParticleHslAnimation.js"; export type * from "./Core/Interfaces/IParticleLife.js"; +export type * from "./Core/Interfaces/IParticleModifier.js"; export type * from "./Core/Interfaces/IParticleRetinaProps.js"; export type * from "./Core/Interfaces/IParticleRoll.js"; export type * from "./Core/Interfaces/IParticleTransformValues.js"; @@ -27,7 +28,6 @@ export type * from "./Core/Interfaces/IRangeValue.js"; export type * from "./Core/Interfaces/IShapeDrawData.js"; export type * from "./Core/Interfaces/IShapeDrawer.js"; export type * from "./Core/Interfaces/IShapeValues.js"; -export type * from "./Core/Interfaces/ISlowParticleData.js"; export type * from "./Options/Interfaces/Background/IBackground.js"; diff --git a/engine/src/exports.ts b/engine/src/exports.ts index d2753b06c28..b93449bd126 100644 --- a/engine/src/exports.ts +++ b/engine/src/exports.ts @@ -21,6 +21,8 @@ export * from "./Enums/Types/EventType.js"; export * from "./Enums/AnimationStatus.js"; +export * from "./Enums/DrawLayer.js"; + export * from "./Options/Classes/AnimatableColor.js"; export * from "./Options/Classes/AnimationOptions.js"; diff --git a/integrations/mcp-server/CHANGELOG.md b/integrations/mcp-server/CHANGELOG.md index aacde218206..3bb2d428b19 100644 --- a/integrations/mcp-server/CHANGELOG.md +++ b/integrations/mcp-server/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/mcp-server + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-18) ### Bug Fixes diff --git a/integrations/mcp-server/package.json b/integrations/mcp-server/package.json index 80bc00ff226..25505255258 100644 --- a/integrations/mcp-server/package.json +++ b/integrations/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/mcp-server", - "version": "4.2.1", + "version": "4.3.0", "description": "MCP server for tsParticles - generate options from natural language and suggest required plugins", "homepage": "https://particles.js.org", "type": "module", diff --git a/interactions/external/attract/CHANGELOG.md b/interactions/external/attract/CHANGELOG.md index 4b6b60e7837..6a49cb3be53 100644 --- a/interactions/external/attract/CHANGELOG.md +++ b/interactions/external/attract/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/interaction-external-attract + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/interaction-external-attract diff --git a/interactions/external/attract/package.dist.json b/interactions/external/attract/package.dist.json index 7fafc1ff2fd..2e058c15659 100644 --- a/interactions/external/attract/package.dist.json +++ b/interactions/external/attract/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-external-attract", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles attract external interaction", "homepage": "https://particles.js.org", "repository": { @@ -97,7 +97,7 @@ }, "type": "module", "peerDependencies": { - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-interactivity": "4.2.1" + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-interactivity": "4.3.0" } } diff --git a/interactions/external/attract/package.json b/interactions/external/attract/package.json index 9941f5e56e5..81990ad521a 100644 --- a/interactions/external/attract/package.json +++ b/interactions/external/attract/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-external-attract", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles external interaction for attracting particles toward the mouse cursor or touch position", "homepage": "https://particles.js.org", "scripts": { diff --git a/interactions/external/bounce/CHANGELOG.md b/interactions/external/bounce/CHANGELOG.md index a40d70af429..bf4e16ee274 100644 --- a/interactions/external/bounce/CHANGELOG.md +++ b/interactions/external/bounce/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/interaction-external-bounce + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/interaction-external-bounce diff --git a/interactions/external/bounce/package.dist.json b/interactions/external/bounce/package.dist.json index bc9366df190..d001a94e9ef 100644 --- a/interactions/external/bounce/package.dist.json +++ b/interactions/external/bounce/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-external-bounce", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles bounce external interaction", "homepage": "https://particles.js.org", "repository": { @@ -97,7 +97,7 @@ }, "type": "module", "peerDependencies": { - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-interactivity": "4.2.1" + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-interactivity": "4.3.0" } } diff --git a/interactions/external/bounce/package.json b/interactions/external/bounce/package.json index 99213ccc96c..424f44e3b7b 100644 --- a/interactions/external/bounce/package.json +++ b/interactions/external/bounce/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-external-bounce", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles external interaction for bouncing particles away from the mouse cursor or touch area", "homepage": "https://particles.js.org", "scripts": { diff --git a/interactions/external/bubble/CHANGELOG.md b/interactions/external/bubble/CHANGELOG.md index 2c5af57ac98..d8baddfb058 100644 --- a/interactions/external/bubble/CHANGELOG.md +++ b/interactions/external/bubble/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + + +### Features + +* added new particle modifier system ([da3038e](https://github.com/tsparticles/tsparticles/commit/da3038e49b41a1025f945342603abc64a6a9bb45)) + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/interaction-external-bubble diff --git a/interactions/external/bubble/package.dist.json b/interactions/external/bubble/package.dist.json index cf876cf12ef..27e755cfcc4 100644 --- a/interactions/external/bubble/package.dist.json +++ b/interactions/external/bubble/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-external-bubble", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles bubble external interaction", "homepage": "https://particles.js.org", "repository": { @@ -97,7 +97,7 @@ }, "type": "module", "peerDependencies": { - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-interactivity": "4.2.1" + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-interactivity": "4.3.0" } } diff --git a/interactions/external/bubble/package.json b/interactions/external/bubble/package.json index 2d42cb1b062..e0dc6d09385 100644 --- a/interactions/external/bubble/package.json +++ b/interactions/external/bubble/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-external-bubble", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles external interaction that enlarges particles near the mouse cursor, creating a bubble effect", "homepage": "https://particles.js.org", "scripts": { diff --git a/interactions/external/bubble/src/BubbleModifier.ts b/interactions/external/bubble/src/BubbleModifier.ts new file mode 100644 index 00000000000..9df484b38af --- /dev/null +++ b/interactions/external/bubble/src/BubbleModifier.ts @@ -0,0 +1,15 @@ +import type { IHsl, IParticleModifier } from "@tsparticles/engine"; + +/** Bubble modifier implementing IParticleModifier for the bubble interactor */ +export class BubbleModifier implements IParticleModifier { + div?: HTMLElement; + enabled = false; + fillColor?: IHsl; + finalColor?: IHsl; + readonly id = "bubble"; + inRange = false; + opacity?: number; + readonly priority = 100; + radius?: number; + strokeColor?: IHsl; +} diff --git a/interactions/external/bubble/src/Bubbler.ts b/interactions/external/bubble/src/Bubbler.ts index c291b1c8c82..5bc22cff328 100644 --- a/interactions/external/bubble/src/Bubbler.ts +++ b/interactions/external/bubble/src/Bubbler.ts @@ -34,6 +34,7 @@ import { } from "@tsparticles/plugin-interactivity"; import { Bubble } from "./Options/Classes/Bubble.js"; import type { BubbleDiv } from "./Options/Classes/BubbleDiv.js"; +import { BubbleModifier } from "./BubbleModifier.js"; import type { Interfaces } from "./Interfaces.js"; import { ProcessBubbleType } from "./Enums.js"; import { calculateBubbleValue } from "./Utils.js"; @@ -54,6 +55,7 @@ export class Bubbler extends ExternalInteractorBase { handleClickMode: (mode: string, interactivityData: IInteractivityData) => void; #maxDistance; + readonly #modifiers = new WeakMap(); readonly #pluginManager; constructor(pluginManager: PluginManager, container: BubbleContainer) { @@ -80,14 +82,29 @@ export class Bubbler extends ExternalInteractorBase { } clear(particle: Particle, _delta: IDelta, force?: boolean): void { - if (particle.bubble.inRange && !force) { + const mod = this.#modifiers.get(particle); + + if (mod?.inRange && !force) { return; } - delete particle.bubble.div; - delete particle.bubble.opacity; - delete particle.bubble.radius; - delete particle.bubble.color; + particle.removeModifier(bubbleMode); + + this.#modifiers.delete(particle); + } + + getOrCreateModifier(particle: Particle): BubbleModifier { + let mod = this.#modifiers.get(particle); + + if (!mod) { + mod = new BubbleModifier(); + + this.#modifiers.set(particle, mod); + + particle.addModifier(mod); + } + + return mod; } init(): void { @@ -163,7 +180,12 @@ export class Bubbler extends ExternalInteractorBase { } reset(_interactivityData: IInteractivityData, particle: Particle): void { - particle.bubble.inRange = false; + const mod = this.#modifiers.get(particle); + + if (mod) { + mod.enabled = false; + mod.inRange = false; + } } #clickBubble(interactivityData: IInteractivityData): void { @@ -194,7 +216,10 @@ export class Bubbler extends ExternalInteractorBase { continue; } - particle.bubble.inRange = !bubble.durationEnd; + const mod = this.getOrCreateModifier(particle); + + mod.enabled = !bubble.durationEnd; + mod.inRange = !bubble.durationEnd; const pos = particle.getPosition(), distMouse = getDistance(pos, mouseClickPos), @@ -213,7 +238,7 @@ export class Bubbler extends ExternalInteractorBase { const sizeData: Interfaces = { bubbleObj: { optValue: container.retina.bubbleModeSize, - value: particle.bubble.radius, + value: mod.radius, }, particlesObj: { optValue: particle.size.max, @@ -227,7 +252,7 @@ export class Bubbler extends ExternalInteractorBase { const opacityData: Interfaces = { bubbleObj: { optValue: bubbleOptions.opacity, - value: particle.bubble.opacity, + value: mod.opacity, }, particlesObj: { optValue: particle.opacity?.max ?? defaultOpacity, @@ -241,7 +266,8 @@ export class Bubbler extends ExternalInteractorBase { if (!bubble.durationEnd && distMouse <= distance) { this.#hoverBubbleColor(particle, distMouse); } else { - delete particle.bubble.color; + mod.fillColor = undefined; + mod.strokeColor = undefined; } } } @@ -257,9 +283,11 @@ export class Bubbler extends ExternalInteractorBase { const query = container.particles.grid.queryCircle(mousePos, distance, p => this.isEnabled(interactivityData, p)); - // for (const { distance, particle } of query) { for (const particle of query) { - particle.bubble.inRange = true; + const mod = this.getOrCreateModifier(particle); + + mod.enabled = true; + mod.inRange = true; const pos = particle.getPosition(), pointDistance = getDistance(pos, mousePos), @@ -290,13 +318,14 @@ export class Bubbler extends ExternalInteractorBase { #hoverBubbleColor(particle: Particle, ratio: number, divBubble?: BubbleDiv): void { const options = this.container.actualOptions, - bubbleOptions = divBubble ?? options.interactivity?.modes.bubble; + bubbleOptions = divBubble ?? options.interactivity?.modes.bubble, + mod = this.getOrCreateModifier(particle); if (!bubbleOptions) { return; } - if (!particle.bubble.finalColor) { + if (!mod.finalColor) { const modeColor = bubbleOptions.color; if (!modeColor) { @@ -305,23 +334,31 @@ export class Bubbler extends ExternalInteractorBase { const bubbleColor = itemFromSingleOrMultiple(modeColor); - particle.bubble.finalColor = rangeColorToHsl(this.#pluginManager, bubbleColor); + mod.finalColor = rangeColorToHsl(this.#pluginManager, bubbleColor); } - if (!particle.bubble.finalColor) { + if (!mod.finalColor) { return; } if (bubbleOptions.mix) { - particle.bubble.color = undefined; + mod.fillColor = undefined; + mod.strokeColor = undefined; const pColor = particle.getFillColor(); - particle.bubble.color = pColor - ? rgbToHsl(colorMix(pColor, particle.bubble.finalColor, ratioOffset - ratio, ratio)) - : particle.bubble.finalColor; + if (pColor) { + const mixedColor = rgbToHsl(colorMix(pColor, mod.finalColor, ratioOffset - ratio, ratio)); + + mod.fillColor = mixedColor; + mod.strokeColor = mixedColor; + } else { + mod.fillColor = mod.finalColor; + mod.strokeColor = mod.finalColor; + } } else { - particle.bubble.color = particle.bubble.finalColor; + mod.fillColor = mod.finalColor; + mod.strokeColor = mod.finalColor; } } @@ -338,7 +375,9 @@ export class Bubbler extends ExternalInteractorBase { opacity = calculateBubbleValue(pOpacity, modeOpacity, particle.opacity?.max ?? defaultOpacity, ratio); if (opacity !== undefined) { - particle.bubble.opacity = opacity; + const mod = this.getOrCreateModifier(particle); + + mod.opacity = opacity; } } @@ -354,7 +393,9 @@ export class Bubbler extends ExternalInteractorBase { size = calculateBubbleValue(pSize, modeSize, particle.size.max, ratio); if (size !== undefined) { - particle.bubble.radius = size; + const mod = this.getOrCreateModifier(particle); + + mod.radius = size; } } @@ -381,14 +422,16 @@ export class Bubbler extends ExternalInteractorBase { container.bubble ??= {}; + const mod = this.getOrCreateModifier(particle); + if (container.bubble.durationEnd) { if (pObjBubble) { if (type === ProcessBubbleType.size) { - delete particle.bubble.radius; + mod.radius = undefined; } if (type === ProcessBubbleType.opacity) { - delete particle.bubble.opacity; + mod.opacity = undefined; } } } else { @@ -399,20 +442,20 @@ export class Bubbler extends ExternalInteractorBase { const value = pObj - (timeSpent * (pObj - bubbleParam)) / bubbleDuration; if (type === ProcessBubbleType.size) { - particle.bubble.radius = value; + mod.radius = value; } if (type === ProcessBubbleType.opacity) { - particle.bubble.opacity = value; + mod.opacity = value; } } } else { if (type === ProcessBubbleType.size) { - delete particle.bubble.radius; + mod.radius = undefined; } if (type === ProcessBubbleType.opacity) { - delete particle.bubble.opacity; + mod.opacity = undefined; } } } @@ -451,15 +494,18 @@ export class Bubbler extends ExternalInteractorBase { continue; } - particle.bubble.inRange = true; + const mod = this.getOrCreateModifier(particle); + + mod.enabled = true; + mod.inRange = true; const divs = bubble.divs, divBubble = divMode(divs, elem); - if (!particle.bubble.div || particle.bubble.div !== elem) { + if (!mod.div || mod.div !== elem) { this.clear(particle, delta, true); - particle.bubble.div = elem; + mod.div = elem; } /* size */ diff --git a/interactions/external/bubble/src/index.ts b/interactions/external/bubble/src/index.ts index fe5dee085bc..07fe958f315 100644 --- a/interactions/external/bubble/src/index.ts +++ b/interactions/external/bubble/src/index.ts @@ -20,6 +20,7 @@ export async function loadExternalBubbleInteraction(engine: Engine): Promise { #maxDistance; + readonly #modifiers = new WeakMap(); constructor(container: SlowContainer) { super(container); @@ -36,11 +38,29 @@ export class Slower extends ExternalInteractorBase { } clear(particle: Particle, _delta: IDelta, force?: boolean): void { - if (particle.slow.inRange && !force) { + const mod = this.#modifiers.get(particle); + + if (mod?.enabled && !force) { return; } - particle.slow.factor = 1; + particle.removeModifier(slowMode); + + this.#modifiers.delete(particle); + } + + getOrCreateModifier(particle: Particle): SlowModifier { + let mod = this.#modifiers.get(particle); + + if (!mod) { + mod = new SlowModifier(); + + this.#modifiers.set(particle, mod); + + particle.addModifier(mod); + } + + return mod; } init(): void { @@ -73,7 +93,11 @@ export class Slower extends ExternalInteractorBase { } reset(interactivityData: IInteractivityData, particle: Particle): void { - particle.slow.inRange = false; + const mod = this.#modifiers.get(particle); + + if (mod) { + mod.enabled = false; + } const container = this.container, options = container.actualOptions, @@ -88,13 +112,15 @@ export class Slower extends ExternalInteractorBase { const particlePos = particle.getPosition(), dist = getDistance(mousePos, particlePos), proximityFactor = dist / radius, - slowFactor = slowOptions.factor, - { slow } = particle; + slowFactor = slowOptions.factor; + if (dist > radius) { return; } - slow.inRange = true; - slow.factor = proximityFactor / slowFactor; + const activeMod = this.getOrCreateModifier(particle); + + activeMod.enabled = true; + activeMod.speedFactor = proximityFactor / slowFactor; } } diff --git a/interactions/external/slow/src/index.ts b/interactions/external/slow/src/index.ts index b6f74ae53c3..8c99ae31faa 100644 --- a/interactions/external/slow/src/index.ts +++ b/interactions/external/slow/src/index.ts @@ -19,5 +19,6 @@ export async function loadExternalSlowInteraction(engine: Engine): Promise }); } +export * from "./SlowModifier.js"; export * from "./Options/Classes/Slow.js"; export type * from "./Options/Interfaces/ISlow.js"; diff --git a/interactions/external/trail/CHANGELOG.md b/interactions/external/trail/CHANGELOG.md index 96cf35a9374..ab5520a477c 100644 --- a/interactions/external/trail/CHANGELOG.md +++ b/interactions/external/trail/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/interaction-external-trail + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/interaction-external-trail diff --git a/interactions/external/trail/package.dist.json b/interactions/external/trail/package.dist.json index edf82b0551a..ae4b40dc9f8 100644 --- a/interactions/external/trail/package.dist.json +++ b/interactions/external/trail/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-external-trail", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles trail external interaction", "homepage": "https://particles.js.org", "repository": { @@ -97,7 +97,7 @@ }, "type": "module", "peerDependencies": { - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-interactivity": "4.2.1" + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-interactivity": "4.3.0" } } diff --git a/interactions/external/trail/package.json b/interactions/external/trail/package.json index 07a14217f71..eb41004d749 100644 --- a/interactions/external/trail/package.json +++ b/interactions/external/trail/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-external-trail", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles external interaction that creates trailing particle effects behind the cursor movement", "homepage": "https://particles.js.org", "scripts": { diff --git a/interactions/light/CHANGELOG.md b/interactions/light/CHANGELOG.md index 9a9c4bb72b9..be1cf4b35d7 100644 --- a/interactions/light/CHANGELOG.md +++ b/interactions/light/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/interaction-light + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/interaction-light diff --git a/interactions/light/package.dist.json b/interactions/light/package.dist.json index 7ab0b12bb69..825aeac34dd 100644 --- a/interactions/light/package.dist.json +++ b/interactions/light/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-light", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles Light interaction", "homepage": "https://particles.js.org", "repository": { @@ -107,8 +107,8 @@ "./package.json": "./package.json" }, "peerDependencies": { - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-interactivity": "4.2.1" + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-interactivity": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/interactions/light/package.json b/interactions/light/package.json index c5e80cf59fe..77be9dae762 100644 --- a/interactions/light/package.json +++ b/interactions/light/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-light", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles interaction that illuminates particles near a light source, simulating lighting effects", "homepage": "https://particles.js.org", "scripts": { diff --git a/interactions/particles/attract/CHANGELOG.md b/interactions/particles/attract/CHANGELOG.md index cd986c8e5ab..7e9e7a54e9f 100644 --- a/interactions/particles/attract/CHANGELOG.md +++ b/interactions/particles/attract/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/interaction-particles-attract + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/interaction-particles-attract diff --git a/interactions/particles/attract/package.dist.json b/interactions/particles/attract/package.dist.json index 68ceedcb22d..772b7a849e3 100644 --- a/interactions/particles/attract/package.dist.json +++ b/interactions/particles/attract/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-particles-attract", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles attract particles interaction", "homepage": "https://particles.js.org", "repository": { @@ -93,8 +93,8 @@ "./package.json": "./package.json" }, "peerDependencies": { - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-interactivity": "4.2.1" + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-interactivity": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/interactions/particles/attract/package.json b/interactions/particles/attract/package.json index 045f855058d..268e2d318e5 100644 --- a/interactions/particles/attract/package.json +++ b/interactions/particles/attract/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-particles-attract", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles particle interaction for attracting particles toward each other", "homepage": "https://particles.js.org", "scripts": { diff --git a/interactions/particles/collisions/CHANGELOG.md b/interactions/particles/collisions/CHANGELOG.md index c667ec8c8fa..39ae99bd747 100644 --- a/interactions/particles/collisions/CHANGELOG.md +++ b/interactions/particles/collisions/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/interaction-particles-collisions + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/interaction-particles-collisions diff --git a/interactions/particles/collisions/package.dist.json b/interactions/particles/collisions/package.dist.json index b36e9c06427..18f1efdb2ee 100644 --- a/interactions/particles/collisions/package.dist.json +++ b/interactions/particles/collisions/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-particles-collisions", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles collisions particles interaction", "homepage": "https://particles.js.org", "repository": { @@ -97,7 +97,7 @@ }, "type": "module", "peerDependencies": { - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-interactivity": "4.2.1" + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-interactivity": "4.3.0" } } diff --git a/interactions/particles/collisions/package.json b/interactions/particles/collisions/package.json index 2b149dece9f..5c5abb245ac 100644 --- a/interactions/particles/collisions/package.json +++ b/interactions/particles/collisions/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-particles-collisions", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles particle interaction for detecting and resolving collisions between particles", "homepage": "https://particles.js.org", "scripts": { diff --git a/interactions/particles/links/CHANGELOG.md b/interactions/particles/links/CHANGELOG.md index 6ba3ed50ac5..42657c661e3 100644 --- a/interactions/particles/links/CHANGELOG.md +++ b/interactions/particles/links/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/interaction-particles-links + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/interaction-particles-links diff --git a/interactions/particles/links/package.dist.json b/interactions/particles/links/package.dist.json index 012713a7fff..f7a7fad22ce 100644 --- a/interactions/particles/links/package.dist.json +++ b/interactions/particles/links/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-particles-links", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles links particles interaction", "homepage": "https://particles.js.org", "repository": { @@ -97,10 +97,10 @@ }, "type": "module", "peerDependencies": { - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-interactivity": "4.2.1" + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-interactivity": "4.3.0" }, "dependencies": { - "@tsparticles/canvas-utils": "4.2.1" + "@tsparticles/canvas-utils": "4.3.0" } } diff --git a/interactions/particles/links/package.json b/interactions/particles/links/package.json index 215b7302c40..90271d88d8e 100644 --- a/interactions/particles/links/package.json +++ b/interactions/particles/links/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-particles-links", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles particle interaction that draws connecting lines between nearby particles", "homepage": "https://particles.js.org", "scripts": { diff --git a/interactions/particles/repulse/CHANGELOG.md b/interactions/particles/repulse/CHANGELOG.md index 4a17e8673c6..340678a3fba 100644 --- a/interactions/particles/repulse/CHANGELOG.md +++ b/interactions/particles/repulse/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [4.3.0](https://github.com/tsparticles/tsparticles/compare/v4.2.1...v4.3.0) (2026-06-27) + +**Note:** Version bump only for package @tsparticles/interaction-particles-repulse + + + + + ## [4.2.1](https://github.com/tsparticles/tsparticles/compare/v4.2.0...v4.2.1) (2026-06-19) **Note:** Version bump only for package @tsparticles/interaction-particles-repulse diff --git a/interactions/particles/repulse/package.dist.json b/interactions/particles/repulse/package.dist.json index ec086436f62..d6ae852b591 100644 --- a/interactions/particles/repulse/package.dist.json +++ b/interactions/particles/repulse/package.dist.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-particles-repulse", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles repulse particles interaction", "homepage": "https://particles.js.org", "repository": { @@ -107,8 +107,8 @@ "./package.json": "./package.json" }, "peerDependencies": { - "@tsparticles/engine": "4.2.1", - "@tsparticles/plugin-interactivity": "4.2.1" + "@tsparticles/engine": "4.3.0", + "@tsparticles/plugin-interactivity": "4.3.0" }, "publishConfig": { "access": "public" diff --git a/interactions/particles/repulse/package.json b/interactions/particles/repulse/package.json index 334d8577c8d..385d7b29f1d 100644 --- a/interactions/particles/repulse/package.json +++ b/interactions/particles/repulse/package.json @@ -1,6 +1,6 @@ { "name": "@tsparticles/interaction-particles-repulse", - "version": "4.2.1", + "version": "4.3.0", "description": "tsParticles particle interaction for repelling particles away from each other", "homepage": "https://particles.js.org", "scripts": { diff --git a/lerna.json b/lerna.json index bf7d65152b5..75272d76801 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "4.2.1", + "version": "4.3.0", "npmClient": "pnpm", "conventionalCommits": true, "command": { @@ -15,4 +15,4 @@ }, "useNx": true, "$schema": "node_modules/lerna/schemas/lerna-schema.json" -} +} \ No newline at end of file diff --git a/markdown/Options/Background.md b/markdown/Options/Background.md index 09b0eadecad..fef4e0067b5 100644 --- a/markdown/Options/Background.md +++ b/markdown/Options/Background.md @@ -2,16 +2,28 @@ Controls the canvas background layer rendered behind particles. +## Layer order (back to front) + +1. **CSS background** (color, image, position, repeat, size) — applied as DOM canvas style +2. **`clear()`** — canvas pixel clear each frame +3. **`background.element` auto-draw** — if set, `ctx.drawImage(element, ...)` composites the external element as-is +4. **`background.draw` callback** — if set, called with the main rendering context + delta +5. **Particles** — drawn on top + +`element` and `draw` are **independent layers**. Both are optional and can be used together or separately. + ## Properties -| Key | Type | Example | Notes | -| ---------- | ------------------- | ---------------------------------------------------------- | ----------------------------------------- | -| `color` | `string` / `object` | `"#bada55"` / `{ "value": "#bada55" }` | Background color, supports {@link IColor} | -| `opacity` | `number` | `1` / `0.5` | Background color alpha, from `0` to `1` | -| `image` | `string` | `"url('https://particles.js.org/images/background3.jpg')"` | CSS `background-image` value | -| `position` | `string` | `"50% 50%"` | CSS `background-position` value | -| `repeat` | `string` | `"no-repeat"` | CSS `background-repeat` value | -| `size` | `string` | `"cover"` | CSS `background-size` value | +| Key | Type | Example | Notes | +| ---------- | -------------------------------------------------------------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------- | +| `color` | `string` / `object` | `"#bada55"` / `{ "value": "#bada55" }` | Background color, supports {@link IColor} | +| `opacity` | `number` | `1` / `0.5` | Background color alpha, from `0` to `1` | +| `image` | `string` | `"url('...')"` | CSS `background-image` value | +| `position` | `string` | `"50% 50%"` | CSS `background-position` value | +| `repeat` | `string` | `"no-repeat"` | CSS `background-repeat` value | +| `size` | `string` | `"cover"` | CSS `background-size` value | +| `element` | `string` / `HTMLCanvasElement` / `OffscreenCanvas` / `HTMLVideoElement` / `HTMLImageElement` | `"#bg"` / `document.getElementById("bg")` | External element auto-drawn each frame via `drawImage`; not managed by engine | +| `draw` | `function` | `(ctx, delta) => { /* custom draw */ }` | Per-frame custom background callback on main canvas context | ## Quick examples @@ -50,3 +62,76 @@ Controls the canvas background layer rendered behind particles. } } ``` + +### Custom background draw + +```json +{ + "background": { + "draw": "(ctx, delta) => { ctx.fillStyle = 'blue'; ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); }" + } +} +``` + +(TypeScript uses a function reference, not a string.) + +```ts +import { type BackgroundDrawContext, type IDelta } from "@tsparticles/engine"; + +const drawBackground = (ctx: BackgroundDrawContext, delta: IDelta): void => { + ctx.fillStyle = "#ff0000"; + ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); +}; +``` + +### Element auto-draw (external canvas, video, or image) + +```json +{ + "background": { + "element": "#my-bg-canvas" + } +} +``` + +When `element` is set, the element's current visual content is drawn onto the main canvas each frame. The element is **not managed** by the engine — external code handles its rendering. + +```ts +// Auto-draw an external