|
1 | | -# ARCHITECTURE |
| 1 | +# Architecture |
2 | 2 |
|
3 | | -High-level architecture |
| 3 | +**Analysis Date:** 2026-04-10 |
4 | 4 |
|
5 | | -- 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. |
| 5 | +## Pattern Overview |
6 | 6 |
|
7 | | -Primary layers |
| 7 | +**Overall:** Modular plugin-based monorepo architecture centered on a shared engine kernel. |
8 | 8 |
|
9 | | -- Engine (runtime): `engine/src/` — core particle system, utilities, and public exports (`engine/src/index.ts`). |
10 | | -- Plugins: `plugins/*/src/` — extend engine features (themes, etc.). |
11 | | -- Paths & generators: `paths/*/src/` — path generation algorithms and types. |
12 | | -- Utilities: `utils/*/src/` — helper libs (e.g., Perlin noise). |
13 | | -- Bundles: `bundles/*/` — assembly of UMD/ESM bundles through webpack. |
| 9 | +**Key Characteristics:** |
14 | 10 |
|
15 | | -Public entry points |
| 11 | +- Core runtime is isolated in `engine/src/*` and exposed through stable package entrypoints in `engine/src/index.ts` and `engine/src/exports.ts`. |
| 12 | +- 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`. |
| 13 | +- Consumer-facing bundles (`bundles/basic`, `bundles/slim`, `bundles/full`, `bundles/all`) aggregate sets of plugin loaders with lazy `import(...)` orchestration. |
16 | 14 |
|
17 | | -- Main runtime entry: `engine/src/index.ts` exports the core API. |
18 | | -- Bundled distribution entry: `bundles/*/src/index.ts` and `bundles/*/src/bundle.ts` for assembled bundles. |
| 15 | +## Layers |
19 | 16 |
|
20 | | -Data flow |
| 17 | +**Engine Kernel Layer:** |
21 | 18 |
|
22 | | -- Configuration (user options) flows into the Engine API which instantiates containers and particles. |
23 | | -- Plugins register updaters and renderers via plugin registration points; look for `Plugin` classes in `plugins/*/src/`. |
| 19 | +- Purpose: Own engine lifecycle, container orchestration, particle update/render loops, and plugin registration infrastructure. |
| 20 | +- Location: `engine/src/Core/*`, `engine/src/Utils/*`, `engine/src/Options/*`, `engine/src/index.ts`. |
| 21 | +- Contains: `Engine`, `Container`, `ParticlesManager`, `RenderManager`, options model classes, shared math/utils. |
| 22 | +- Depends on: Internal engine modules and browser globals (`globalThis`, canvas APIs, `fetch` in `engine/src/Core/Engine.ts`). |
| 23 | +- Used by: All workspace feature packages and all published bundles via `@tsparticles/engine`. |
24 | 24 |
|
25 | | -Extensibility |
| 25 | +**Feature Package Layer (Plugins / Interactions / Shapes / Updaters / Paths / Effects):** |
26 | 26 |
|
27 | | -- Plugin system with clear plugin interfaces (inspect `plugins/*/src/*Plugin.ts` and `ThemesPlugin.ts`). |
28 | | -- Paths and generators are separate packages that implement specific interfaces (e.g., `GridPathGenerator.ts`). |
| 27 | +- Purpose: Encapsulate one behavior per package and register that behavior into the engine. |
| 28 | +- Location: `plugins/*/src/*`, `interactions/*/*/src/*`, `shapes/*/src/*`, `updaters/*/src/*`, `paths/*/src/*`, `effects/*/src/*`. |
| 29 | +- Contains: `load*` functions that call `engine.checkVersion(__VERSION__)` and `engine.pluginManager.register(...)`. |
| 30 | +- Depends on: `@tsparticles/engine` and sometimes other feature packages (for example interactivity dependencies in `interactions/external/repulse/src/index.ts`). |
| 31 | +- Used by: Bundle packages and direct consumers. |
29 | 32 |
|
30 | | -Where to find architectural decisions |
| 33 | +**Bundle Composition Layer:** |
31 | 34 |
|
32 | | -- `engine/src/` — core abstractions and utility helpers (`EventDispatcher.ts`, `CanvasUtils.ts`). |
33 | | -- `plugins/*/` — plugin lifecycle and extension patterns. |
| 35 | +- Purpose: Define opinionated feature sets (basic/slim/full/all/confetti/fireworks/pjs compatibility) and load dependencies in one call. |
| 36 | +- Location: `bundles/*/src/index.ts`, `bundles/*/src/bundle.ts`. |
| 37 | +- Contains: Aggregator loaders (`loadBasic`, `loadSlim`, `loadFull`, `loadAll`) with staged dynamic imports and `Promise.all` fan-out. |
| 38 | +- Depends on: Engine package plus many feature packages (for example `bundles/all/src/index.ts`). |
| 39 | +- Used by: Apps, demos, and end users importing bundle packages (`tsparticles`, `@tsparticles/all`, etc.). |
34 | 40 |
|
35 | | -Notes on build & distribution |
| 41 | +**Application / Demo Layer:** |
36 | 42 |
|
37 | | -- Bundles are constructed via webpack, producing format-specific outputs. `bundles/slim/` contains a trimmed bundle implementation. |
| 43 | +- Purpose: Run and demonstrate engine + bundles in runtime hosts. |
| 44 | +- Location: `demo/vite/src/main.ts`, `demo/vanilla/app.ts`, `demo/electron/client/client.js`, `demo/vanilla_new/*`. |
| 45 | +- Contains: Environment bootstrap, server/electron glue, and sample `engine.load(...)` usage. |
| 46 | +- Depends on: Published workspace packages and host runtime frameworks (Vite/Express/Electron). |
| 47 | +- Used by: Development, documentation, and manual verification. |
38 | 48 |
|
39 | | -Limitations & boundaries |
| 49 | +**Workspace Orchestration Layer:** |
40 | 50 |
|
41 | | -- No server components; architecture assumes client-side/browser execution for rendering, and Node only for tooling/builds. |
| 51 | +- Purpose: Coordinate multi-package builds, caching, and dependency execution. |
| 52 | +- Location: `nx.json`, `pnpm-workspace.yaml`, root `package.json`. |
| 53 | +- Contains: Nx target defaults, package globs, root scripts (`nx run-many`, `nx affected`). |
| 54 | +- Depends on: Nx + pnpm workspace metadata. |
| 55 | +- Used by: CI and local development workflows. |
| 56 | + |
| 57 | +## Data Flow |
| 58 | + |
| 59 | +**Runtime Initialization and Animation Flow:** |
| 60 | + |
| 61 | +1. Importing engine entrypoint creates singleton instance (`engine/src/index.ts`) and assigns `globalThis.tsParticles`. |
| 62 | +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. |
| 63 | +3. `Container.start()` in `engine/src/Core/Container.ts` initializes plugins/drawers/updaters, computes effective options, initializes canvas + particles, and starts draw loop. |
| 64 | +4. `RenderManager.drawParticles(...)` in `engine/src/Core/RenderManager.ts` clears canvas, updates particles through `ParticlesManager.update(...)`, then renders particles and plugin overlays each frame. |
| 65 | +5. Event dispatch (`EventDispatcher`, `EventType`) propagates lifecycle and particle events to plugins and consumers. |
| 66 | + |
| 67 | +**Bundle and Plugin Loading Flow:** |
| 68 | + |
| 69 | +1. A bundle loader (for example `bundles/slim/src/index.ts`) receives `Engine` and validates version with `engine.checkVersion(__VERSION__)`. |
| 70 | +2. Bundle dynamically imports required feature loaders and calls each loader. |
| 71 | +3. Each feature loader registers behavior using `engine.pluginManager.register(...)` and adds updaters/shapes/interactors/plugins. |
| 72 | +4. Registered initializers are materialized per-container via `PluginManager.getEffectDrawers/getShapeDrawers/getUpdaters` when container starts. |
| 73 | + |
| 74 | +**State Management:** |
| 75 | + |
| 76 | +- 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`). |
| 77 | +- Container-level mutable state (running/paused/destroyed/options/plugins) is maintained in instance fields in `engine/src/Core/Container.ts`. |
| 78 | +- Particle-level state is maintained in arrays plus spatial hash grid in `engine/src/Core/ParticlesManager.ts`. |
| 79 | + |
| 80 | +## Key Abstractions |
| 81 | + |
| 82 | +**Engine:** |
| 83 | + |
| 84 | +- Purpose: Global orchestrator for containers and plugin lifecycle. |
| 85 | +- Examples: `engine/src/Core/Engine.ts`, `engine/src/initEngine.ts`, `engine/src/index.ts`. |
| 86 | +- Pattern: Singleton-like exported instance + reusable `Engine` class. |
| 87 | + |
| 88 | +**Container:** |
| 89 | + |
| 90 | +- Purpose: One rendering/runtime instance bound to one canvas/DOM scope. |
| 91 | +- Examples: `engine/src/Core/Container.ts`, `engine/src/Core/CanvasManager.ts`, `engine/src/Core/Retina.ts`. |
| 92 | +- Pattern: Stateful lifecycle object (`init/start/play/pause/stop/destroy`). |
| 93 | + |
| 94 | +**PluginManager:** |
| 95 | + |
| 96 | +- Purpose: Registry and instantiation boundary for plugins, shapes, effects, updaters, easings, presets, and configs. |
| 97 | +- Examples: `engine/src/Core/Utils/PluginManager.ts`. |
| 98 | +- Pattern: Registry + deferred initializer execution. |
| 99 | + |
| 100 | +**Feature Loaders (`load*`):** |
| 101 | + |
| 102 | +- Purpose: Install one feature package into engine. |
| 103 | +- Examples: `shapes/circle/src/index.ts`, `updaters/opacity/src/index.ts`, `interactions/external/repulse/src/index.ts`, `plugins/absorbers/src/index.ts`. |
| 104 | +- Pattern: Version gate + `pluginManager.register(...)` + lazy import. |
| 105 | + |
| 106 | +**Bundle Loaders (`loadBasic/loadSlim/loadFull/loadAll`):** |
| 107 | + |
| 108 | +- Purpose: Compose many feature loaders into curated distributions. |
| 109 | +- Examples: `bundles/basic/src/index.ts`, `bundles/slim/src/index.ts`, `bundles/full/src/index.ts`, `bundles/all/src/index.ts`. |
| 110 | +- Pattern: Dependency fan-out with staged dynamic imports and `Promise.all`. |
| 111 | + |
| 112 | +## Entry Points |
| 113 | + |
| 114 | +**Engine Public Entrypoint:** |
| 115 | + |
| 116 | +- Location: `engine/src/index.ts` |
| 117 | +- Triggers: Package import of `@tsparticles/engine`. |
| 118 | +- Responsibilities: Create singleton engine (`tsParticles`), publish on `globalThis`, re-export public API/types. |
| 119 | + |
| 120 | +**Engine Bundle Entrypoint (no type exports):** |
| 121 | + |
| 122 | +- Location: `engine/src/bundle.ts` |
| 123 | +- Triggers: Bundle-oriented engine consumption. |
| 124 | +- Responsibilities: Create global `tsParticles` and export runtime API. |
| 125 | + |
| 126 | +**Bundle Entrypoints:** |
| 127 | + |
| 128 | +- Location: `bundles/*/src/index.ts` and `bundles/*/src/bundle.ts` |
| 129 | +- Triggers: Import of bundle packages like `tsparticles` or `@tsparticles/slim`. |
| 130 | +- Responsibilities: Register predefined feature sets and expose one `load*` entrypoint. |
| 131 | + |
| 132 | +**Demo Entrypoints:** |
| 133 | + |
| 134 | +- Location: `demo/vite/src/main.ts`, `demo/vanilla/app.ts`, `demo/electron/client/client.js`, `demo/electron/app/index.js` |
| 135 | +- Triggers: Dev server startup or browser/electron app load. |
| 136 | +- Responsibilities: Host runtime bootstrapping and `engine.load(...)` invocation. |
| 137 | + |
| 138 | +## Error Handling |
| 139 | + |
| 140 | +**Strategy:** Fail fast on version/runtime contract violations, log recoverable runtime failures, and return `undefined` for optional result paths. |
| 141 | + |
| 142 | +**Patterns:** |
| 143 | + |
| 144 | +- Version mismatch is thrown as `Error` via `Engine.checkVersion(...)` in `engine/src/Core/Engine.ts`. |
| 145 | +- 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`. |
| 146 | +- 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`). |
| 147 | + |
| 148 | +## Cross-Cutting Concerns |
| 149 | + |
| 150 | +**Logging:** `getLogger()` from `engine/src/Utils/LogUtils.ts` is used across engine core for warnings/errors. |
| 151 | +**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`). |
| 152 | +**Authentication:** Not applicable in core architecture; no auth layer exists in engine packages. |
| 153 | + |
| 154 | +--- |
| 155 | + |
| 156 | +_Architecture analysis: 2026-04-10_ |
0 commit comments