tsParticles - v4.0.0-beta.12
    Preparing search index...

    UMD Namespace Policy Implementation Plan

    Status: implemented in Rollup plugin (UMD path).

    Completed:

    • UMD public/internal export split with minimal top-level globals.
    • Internal shared namespace bootstrap and scoped writes under globalThis.__tsParticlesInternals.
    • UMD externals mapping for tsparticles, tsparticles-*, @tsparticles/* to internals paths.
    • Build-time hard-fail validation for public globals matrix (policy violations fail bundling).

    Notes:

    • Policy enforcement is UMD-only and does not alter ESM/CJS APIs.
    • __tsParticlesInternals remains internal and non-semver-stable.

    This document defines the implementation details for the UMD global namespace policy.

    • Applies only to UMD/browser global outputs generated by Rollup.
    • Does not change ESM/CJS exports, TypeScript imports, or runtime APIs used by import-based consumers.
    • Keeps backward compatibility for expected public globals while moving non-public exports to an internal shared namespace.
    1. Keep window clean and predictable.
    2. Preserve expected public UMD APIs.
    3. Make script include order as non-blocking as possible.
    4. Keep non-public exports available for UMD inter-package resolution.
    5. Avoid touching package source logic (engine/plugins/bundles) unless strictly required.
    • No API redesign for ESM/CJS modules.
    • No refactor of package internals to consume a new runtime object directly.
    • No removal of deprecated @tsparticles/pjs behavior in this phase.
    • Public on window: tsParticles
    • Not public on window: all other engine exports
    • Internal namespace: __tsParticlesInternals.engine.*
    • Public on window: only their own load* functions (including multiple load* exports if present)
    • Public load functions must be discoverable and callable from globalThis/window.
    • Not public on window: all non-load* exports
    • Internal namespace: category-based plural path under __tsParticlesInternals
    • Public on window: only their own load* functions
    • Not public on window: all non-load* exports
    • Internal namespace: __tsParticlesInternals.bundles.<bundleName>.*
    • Public on window: only initPjs
    • Runtime side-effects from initPjs stay unchanged:
      • globalThis.particlesJS
      • globalThis.Particles
      • globalThis.pJSDom
    • Internal namespace for non-public exports: __tsParticlesInternals.bundles.pjs.*
    • Public on window:
      • confetti bundle: only confetti
      • fireworks bundle: only fireworks
    • window.tsParticles is not part of their public API in this policy
    • They are excluded from engine/top-level internals coupling

    Use a global shared object:

    • globalThis.__tsParticlesInternals

    Characteristics:

    • UMD-only implementation detail
    • Not semver-stable public API
    • Safe to initialize multiple times
    • Must be initialized before writing internal exports
    • Must be used as the source of truth for inter-package UMD symbol resolution (for example isNull, PerlinNoise, ensureInteractivityPluginLoaded)
    • bundles
    • plugins
    • interactions
    • effects
    • paths
    • shapes
    • updaters
    • palettes
    • presets
    • utils
    • engine (intentional singular exception)

    For package @tsparticles/<name>:

    1. Determine category (plural) from package type.
    2. Map the package leaf to a single scope segment that follows workspace folder/project naming.
    3. Do not split package leaves into multiple nested objects unless the package is actually modeled as multiple folders/domains.
    4. Exception for emitters shapes: use emittersShapes intermediate segment to avoid collisions with plugins.emitters.*.

    Examples:

    • @tsparticles/path-perlin-noise -> __tsParticlesInternals.paths.perlinNoise
    • @tsparticles/plugin-interactivity -> __tsParticlesInternals.plugins.interactivity
    • @tsparticles/updater-out-modes -> __tsParticlesInternals.updaters.outModes
    • @tsparticles/plugin-emitters -> __tsParticlesInternals.plugins.emitters
    • @tsparticles/plugin-emitters-shape-canvas -> __tsParticlesInternals.plugins.emittersShapes.canvas
    • tsparticles (full bundle) -> __tsParticlesInternals.bundles.full
    • @tsparticles/slim -> __tsParticlesInternals.bundles.slim
    • @tsparticles/basic -> __tsParticlesInternals.bundles.basic
    • @tsparticles/all -> __tsParticlesInternals.bundles.all
    • @tsparticles/pjs -> __tsParticlesInternals.bundles.pjs
    • @tsparticles/confetti -> __tsParticlesInternals.bundles.confetti
    • @tsparticles/fireworks -> __tsParticlesInternals.bundles.fireworks
    • @tsparticles/engine -> __tsParticlesInternals.engine

    If category inference is ambiguous, fallback to package name path segments without blocking build.

    Primary implementation files:

    • cli/utils/rollup-plugin/src/config/createSingleConfig.ts
    • cli/utils/rollup-plugin/src/config/externals.ts
    • cli/utils/rollup-plugin/src/types.ts
    • cli/utils/rollup-plugin/src/createParticlesBuild.ts
    • cli/utils/rollup-plugin/src/config/entry.ts (if needed for stable scope computation)

    At UMD render stage, split entry exports into:

    • publicExports: eligible for window top-level
    • internalExports: written to __tsParticlesInternals.<scope>
    • engine: allow only tsParticles
    • pjs: allow only initPjs
    • confetti: allow only confetti
    • fireworks: allow only fireworks
    • all other non-engine packages: allow only exports matching ^load[A-Z]

    For each internal export symbol X in a package scope:

    • ensure path exists in __tsParticlesInternals
    • assign scope.X = X

    Update UMD externals mapping so tsparticles package references resolve through internals namespace instead of top-level window:

    • tsparticles, tsparticles-*, @tsparticles/* -> __tsParticlesInternals... paths

    This is a required compatibility point. Symbols imported across packages must be found and callable from internals, including but not limited to:

    • __tsParticlesInternals.engine.isNull
    • __tsParticlesInternals.paths.perlinNoise.PerlinNoise
    • __tsParticlesInternals.plugins.interactivity.ensureInteractivityPluginLoaded

    Every UMD chunk that writes internals must bootstrap safely:

    • initialize globalThis.__tsParticlesInternals if absent
    • initialize required nested scope objects before assignment

    This allows loading plugin script before engine script without immediate failures due to missing internal root object.

    • Do not change source exports in package src/index.ts files for this phase.
    • Do not alter runtime behavior of initPjs side-effects.
    • Keep current import paths and package boundaries.
    • Keep lazy/index strategy unchanged when currently excluded from UMD workflow.
    1. UMD top-level window only contains expected public symbols per matrix.
    2. Non-public exports remain accessible through globalThis.__tsParticlesInternals in correct scope.
    3. Existing import-based usage (ESM/CJS) is unaffected.
    4. Loading order is tolerant for internals root initialization.
    5. confetti and fireworks expose only their public callable globals.
    6. @tsparticles/pjs exposes only initPjs automatically; legacy globals appear only after calling it.
    7. UMD inter-package imports resolve from internals for runtime helpers (isNull, PerlinNoise, ensureInteractivityPluginLoaded, etc.).
    8. Public load* APIs are always available on globalThis/window as defined by the matrix.
    • Build at least representative packages:
      • engine
      • one plugin with helper exports (plugin-interactivity)
      • one path package (path-perlin-noise)
      • one bundle (full)
      • pjs
      • confetti/fireworks
    • Inspect UMD output headers/footers for global assignments.
    • Verify public globals matrix in a browser-like environment.
    • Verify internals lookups for known symbols:
      • __tsParticlesInternals.engine.isNull
      • __tsParticlesInternals.paths.perlinNoise.PerlinNoise
      • __tsParticlesInternals.plugins.interactivity.ensureInteractivityPluginLoaded
    1. Implement behind strict matrix in Rollup plugin.
    2. Add build-time validation (hard fail) when public global set violates policy.
    3. Update docs with explicit UMD public surface + internal namespace disclaimer.

    Update docs to state:

    • UMD public globals are intentionally minimal.
    • __tsParticlesInternals is implementation/internal support for UMD package interoperability.
    • It is not a stable public API and may change without semver guarantees.