Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
05cdfbd
build(deps-dev): bump vite from 8.0.7 to 8.0.8
dependabot[bot] Apr 10, 2026
4d252e7
docs: map existing codebase
matteobruni Apr 10, 2026
172047d
docs: updated scripts/nx configuration/workflows
matteobruni Apr 10, 2026
1f0c668
Merge branch 'main' into v4
matteobruni Apr 10, 2026
1a14ff4
build: updated ci scripts
matteobruni Apr 10, 2026
7925303
Merge pull request #5675 from tsparticles/dependabot/npm_and_yarn/v4/…
matteobruni Apr 10, 2026
b8a4835
build(deps-dev): bump @vitest/ui from 4.1.2 to 4.1.4
dependabot[bot] Apr 10, 2026
b4d672e
build(deps-dev): bump webpack from 5.105.4 to 5.106.0
dependabot[bot] Apr 10, 2026
1a3c3c8
build(deps-dev): bump electron from 41.1.1 to 41.2.0
dependabot[bot] Apr 10, 2026
bcffdea
Merge pull request #5678 from tsparticles/v4
matteobruni Apr 10, 2026
a44fdf4
Merge pull request #5672 from tsparticles/dependabot/npm_and_yarn/v4/…
matteobruni Apr 10, 2026
7733942
Merge pull request #5673 from tsparticles/dependabot/npm_and_yarn/v4/…
matteobruni Apr 10, 2026
88ea7d4
Merge pull request #5676 from tsparticles/dependabot/npm_and_yarn/v4/…
matteobruni Apr 10, 2026
3e24e7b
build(deps-dev): bump @vitest/coverage-v8 from 4.1.3 to 4.1.4
dependabot[bot] Apr 10, 2026
3876805
Merge pull request #5677 from tsparticles/dependabot/npm_and_yarn/v4/…
matteobruni Apr 10, 2026
7588967
Merge branch 'main' into v4
matteobruni Apr 10, 2026
359f626
build: updated deps
matteobruni Apr 10, 2026
ef835f6
Merge pull request #5679 from tsparticles/v4
matteobruni Apr 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ jobs:
run: pnpm run prettify:ci:readme

- name: Build packages
run: npx nx affected -t build:ci
run: pnpm run build:affected:ci

- name: Deploy to Firebase (production)
if: env.firebaseToken != '' && github.ref == 'refs/heads/main' && github.event_name == 'push'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
run: pnpm exec nx-cloud start-ci-run --distribute-on="5 linux-medium-js"

- name: Build All Packages
run: pnpm nx run-many -t build:ci
run: pnpm run slimbuild:ci
env:
CI: true

Expand Down
165 changes: 140 additions & 25 deletions .planning/codebase/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,156 @@
# ARCHITECTURE
# Architecture

High-level architecture
**Analysis Date:** 2026-04-10

- Purpose: tsParticles is a TypeScript-based particle engine and collection of plugins and paths. The repository is a monorepo containing engine core, plugins, utility libraries, and bundles.
## Pattern Overview

Primary layers
**Overall:** Modular plugin-based monorepo architecture centered on a shared engine kernel.

- Engine (runtime): `engine/src/` — core particle system, utilities, and public exports (`engine/src/index.ts`).
- Plugins: `plugins/*/src/` — extend engine features (themes, etc.).
- Paths & generators: `paths/*/src/` — path generation algorithms and types.
- Utilities: `utils/*/src/` — helper libs (e.g., Perlin noise).
- Bundles: `bundles/*/` — assembly of UMD/ESM bundles through webpack.
**Key Characteristics:**

Public entry points
- Core runtime is isolated in `engine/src/*` and exposed through stable package entrypoints in `engine/src/index.ts` and `engine/src/exports.ts`.
- Feature behavior is composed at runtime through plugin registration (`engine.pluginManager.register(...)`) from package-local loaders like `plugins/*/src/index.ts`, `interactions/*/src/index.ts`, `updaters/*/src/index.ts`, and `shapes/*/src/index.ts`.
- Consumer-facing bundles (`bundles/basic`, `bundles/slim`, `bundles/full`, `bundles/all`) aggregate sets of plugin loaders with lazy `import(...)` orchestration.

- Main runtime entry: `engine/src/index.ts` exports the core API.
- Bundled distribution entry: `bundles/*/src/index.ts` and `bundles/*/src/bundle.ts` for assembled bundles.
## Layers

Data flow
**Engine Kernel Layer:**

- Configuration (user options) flows into the Engine API which instantiates containers and particles.
- Plugins register updaters and renderers via plugin registration points; look for `Plugin` classes in `plugins/*/src/`.
- Purpose: Own engine lifecycle, container orchestration, particle update/render loops, and plugin registration infrastructure.
- Location: `engine/src/Core/*`, `engine/src/Utils/*`, `engine/src/Options/*`, `engine/src/index.ts`.
- Contains: `Engine`, `Container`, `ParticlesManager`, `RenderManager`, options model classes, shared math/utils.
- Depends on: Internal engine modules and browser globals (`globalThis`, canvas APIs, `fetch` in `engine/src/Core/Engine.ts`).
- Used by: All workspace feature packages and all published bundles via `@tsparticles/engine`.

Extensibility
**Feature Package Layer (Plugins / Interactions / Shapes / Updaters / Paths / Effects):**

- Plugin system with clear plugin interfaces (inspect `plugins/*/src/*Plugin.ts` and `ThemesPlugin.ts`).
- Paths and generators are separate packages that implement specific interfaces (e.g., `GridPathGenerator.ts`).
- Purpose: Encapsulate one behavior per package and register that behavior into the engine.
- Location: `plugins/*/src/*`, `interactions/*/*/src/*`, `shapes/*/src/*`, `updaters/*/src/*`, `paths/*/src/*`, `effects/*/src/*`.
- Contains: `load*` functions that call `engine.checkVersion(__VERSION__)` and `engine.pluginManager.register(...)`.
- Depends on: `@tsparticles/engine` and sometimes other feature packages (for example interactivity dependencies in `interactions/external/repulse/src/index.ts`).
- Used by: Bundle packages and direct consumers.

Where to find architectural decisions
**Bundle Composition Layer:**

- `engine/src/` — core abstractions and utility helpers (`EventDispatcher.ts`, `CanvasUtils.ts`).
- `plugins/*/` — plugin lifecycle and extension patterns.
- Purpose: Define opinionated feature sets (basic/slim/full/all/confetti/fireworks/pjs compatibility) and load dependencies in one call.
- Location: `bundles/*/src/index.ts`, `bundles/*/src/bundle.ts`.
- Contains: Aggregator loaders (`loadBasic`, `loadSlim`, `loadFull`, `loadAll`) with staged dynamic imports and `Promise.all` fan-out.
- Depends on: Engine package plus many feature packages (for example `bundles/all/src/index.ts`).
- Used by: Apps, demos, and end users importing bundle packages (`tsparticles`, `@tsparticles/all`, etc.).

Notes on build & distribution
**Application / Demo Layer:**

- Bundles are constructed via webpack, producing format-specific outputs. `bundles/slim/` contains a trimmed bundle implementation.
- Purpose: Run and demonstrate engine + bundles in runtime hosts.
- Location: `demo/vite/src/main.ts`, `demo/vanilla/app.ts`, `demo/electron/client/client.js`, `demo/vanilla_new/*`.
- Contains: Environment bootstrap, server/electron glue, and sample `engine.load(...)` usage.
- Depends on: Published workspace packages and host runtime frameworks (Vite/Express/Electron).
- Used by: Development, documentation, and manual verification.

Limitations & boundaries
**Workspace Orchestration Layer:**

- No server components; architecture assumes client-side/browser execution for rendering, and Node only for tooling/builds.
- Purpose: Coordinate multi-package builds, caching, and dependency execution.
- Location: `nx.json`, `pnpm-workspace.yaml`, root `package.json`.
- Contains: Nx target defaults, package globs, root scripts (`nx run-many`, `nx affected`).
- Depends on: Nx + pnpm workspace metadata.
- Used by: CI and local development workflows.

## Data Flow

**Runtime Initialization and Animation Flow:**

1. Importing engine entrypoint creates singleton instance (`engine/src/index.ts`) and assigns `globalThis.tsParticles`.
2. Consumer calls `engine.load(...)` (implemented in `engine/src/Core/Engine.ts`), which initializes plugin manager, resolves options (including optional URL fetch), creates/replaces a `Container`, and binds/creates canvas.
3. `Container.start()` in `engine/src/Core/Container.ts` initializes plugins/drawers/updaters, computes effective options, initializes canvas + particles, and starts draw loop.
4. `RenderManager.drawParticles(...)` in `engine/src/Core/RenderManager.ts` clears canvas, updates particles through `ParticlesManager.update(...)`, then renders particles and plugin overlays each frame.
5. Event dispatch (`EventDispatcher`, `EventType`) propagates lifecycle and particle events to plugins and consumers.

**Bundle and Plugin Loading Flow:**

1. A bundle loader (for example `bundles/slim/src/index.ts`) receives `Engine` and validates version with `engine.checkVersion(__VERSION__)`.
2. Bundle dynamically imports required feature loaders and calls each loader.
3. Each feature loader registers behavior using `engine.pluginManager.register(...)` and adds updaters/shapes/interactors/plugins.
4. Registered initializers are materialized per-container via `PluginManager.getEffectDrawers/getShapeDrawers/getUpdaters` when container starts.

**State Management:**

- Engine-level state is centralized in in-memory registries/maps: `Engine._domArray` (`engine/src/Core/Engine.ts`) and `PluginManager` maps/sets (`engine/src/Core/Utils/PluginManager.ts`).
- Container-level mutable state (running/paused/destroyed/options/plugins) is maintained in instance fields in `engine/src/Core/Container.ts`.
- Particle-level state is maintained in arrays plus spatial hash grid in `engine/src/Core/ParticlesManager.ts`.

## Key Abstractions

**Engine:**

- Purpose: Global orchestrator for containers and plugin lifecycle.
- Examples: `engine/src/Core/Engine.ts`, `engine/src/initEngine.ts`, `engine/src/index.ts`.
- Pattern: Singleton-like exported instance + reusable `Engine` class.

**Container:**

- Purpose: One rendering/runtime instance bound to one canvas/DOM scope.
- Examples: `engine/src/Core/Container.ts`, `engine/src/Core/CanvasManager.ts`, `engine/src/Core/Retina.ts`.
- Pattern: Stateful lifecycle object (`init/start/play/pause/stop/destroy`).

**PluginManager:**

- Purpose: Registry and instantiation boundary for plugins, shapes, effects, updaters, easings, presets, and configs.
- Examples: `engine/src/Core/Utils/PluginManager.ts`.
- Pattern: Registry + deferred initializer execution.

**Feature Loaders (`load*`):**

- Purpose: Install one feature package into engine.
- Examples: `shapes/circle/src/index.ts`, `updaters/opacity/src/index.ts`, `interactions/external/repulse/src/index.ts`, `plugins/absorbers/src/index.ts`.
- Pattern: Version gate + `pluginManager.register(...)` + lazy import.

**Bundle Loaders (`loadBasic/loadSlim/loadFull/loadAll`):**

- Purpose: Compose many feature loaders into curated distributions.
- Examples: `bundles/basic/src/index.ts`, `bundles/slim/src/index.ts`, `bundles/full/src/index.ts`, `bundles/all/src/index.ts`.
- Pattern: Dependency fan-out with staged dynamic imports and `Promise.all`.

## Entry Points

**Engine Public Entrypoint:**

- Location: `engine/src/index.ts`
- Triggers: Package import of `@tsparticles/engine`.
- Responsibilities: Create singleton engine (`tsParticles`), publish on `globalThis`, re-export public API/types.

**Engine Bundle Entrypoint (no type exports):**

- Location: `engine/src/bundle.ts`
- Triggers: Bundle-oriented engine consumption.
- Responsibilities: Create global `tsParticles` and export runtime API.

**Bundle Entrypoints:**

- Location: `bundles/*/src/index.ts` and `bundles/*/src/bundle.ts`
- Triggers: Import of bundle packages like `tsparticles` or `@tsparticles/slim`.
- Responsibilities: Register predefined feature sets and expose one `load*` entrypoint.

**Demo Entrypoints:**

- Location: `demo/vite/src/main.ts`, `demo/vanilla/app.ts`, `demo/electron/client/client.js`, `demo/electron/app/index.js`
- Triggers: Dev server startup or browser/electron app load.
- Responsibilities: Host runtime bootstrapping and `engine.load(...)` invocation.

## Error Handling

**Strategy:** Fail fast on version/runtime contract violations, log recoverable runtime failures, and return `undefined` for optional result paths.

**Patterns:**

- Version mismatch is thrown as `Error` via `Engine.checkVersion(...)` in `engine/src/Core/Engine.ts`.
- Runtime loop and recoverable operations use logger-based reporting (`getLogger().error/warning`) in `engine/src/Core/Container.ts`, `engine/src/Core/ParticlesManager.ts`, `engine/src/Core/Engine.ts`.
- Optional workflows return `undefined` instead of throwing (for example `Engine.load(...)` fallback path in `engine/src/Core/Engine.ts`, particle add failures in `engine/src/Core/ParticlesManager.ts`).

## Cross-Cutting Concerns

**Logging:** `getLogger()` from `engine/src/Utils/LogUtils.ts` is used across engine core for warnings/errors.
**Validation:** Runtime API contract validation is performed via `engine.checkVersion(__VERSION__)` in every loadable package entrypoint (for example `bundles/full/src/index.ts`, `shapes/circle/src/index.ts`).
**Authentication:** Not applicable in core architecture; no auth layer exists in engine packages.

---

_Architecture analysis: 2026-04-10_
Loading
Loading