Skip to content

feat!: Replace the particle system with a data-oriented particle system - #3948

Open
spydon wants to merge 3 commits into
mainfrom
new-particle-system
Open

feat!: Replace the particle system with a data-oriented particle system#3948
spydon wants to merge 3 commits into
mainfrom
new-particle-system

Conversation

@spydon

@spydon spydon commented Jul 19, 2026

Copy link
Copy Markdown
Member

Description

Completely removes the old particle system and replaces it with a new data-oriented one built for large particle counts and a declarative developer experience.

Stacked on top of #3947, since flame_oxygen (removed there) depended on the old particle API.

Removed: Particle and all 15 subclasses (AcceleratedParticle, CircleParticle, ComponentParticle, ComposedParticle, ComputedParticle, CurvedParticle, ImageParticle, MovingParticle, PaintParticle, RotatingParticle, ScaledParticle, ScalingParticle, SpriteAnimationParticle, SpriteParticle, TranslatedParticle), the SingleChildParticle mixin, and ParticleSystemComponent.

Added (in package:flame/particles.dart):

  • ParticleEmitter: a declarative, reusable preset describing emission (continuous rate, timed EmitterBursts, duration/loop), spawn shape (point, circle, rectangle, or a custom EmitterShape), polar initial velocity (speed, direction, spread), forces (gravity, drag), rotation (rotation, spin, rotateToVelocity), and over-life behavior (scaleOverLife, opacityOverLife, colorOverLife). Per-particle variation is expressed as (min, max) records (ParticleRange).
  • ParticleCurve and ColorRamp: over-life curves and gradients, baked into lookup tables at construction so per-particle per-frame evaluation is an array read.
  • ParticleBuffer: struct-of-arrays storage over Float32List/Int32List, preallocated at maxParticles, with constant-time swap-removal. A running effect performs no allocations.
  • ParticleRenderer with batched built-ins: CircleParticleRenderer (one-time rasterized circle texture with a softness knob) and SpriteParticleRenderer render all particles of an emitter in a single Canvas.drawRawAtlas call with per-particle transform and tint; CallbackParticleRenderer gives direct canvas access.
  • ParticleEmitterComponent: a PositionComponent tying it together, with start()/stop(), immediate emit(n), removeOnFinish for fire-and-forget one-shots, a seedable Random for determinism, and worldSpace: true to leave live particles behind while the emitter moves (trails, exhaust).

The particles documentation page has been rewritten, both particle example stories have been rebuilt on the new API, and the new system is covered by 49 tests.

Checklist

  • I have followed the Contributor Guide when preparing my PR.
  • I have updated/added tests for ALL new/updated/fixed functionality.
  • I have updated/added relevant documentation in docs and added dartdoc comments with ///.
  • I have updated/added relevant examples in examples or docs.

Breaking Change?

  • Yes, this PR is a breaking change.
  • No, this PR is not a breaking change.

Migration instructions

The old Particle hierarchy and ParticleSystemComponent are gone; effects are now described declaratively instead of composed from per-particle object trees. An old-style effect like:

add(
  ParticleSystemComponent(
    position: position,
    particle: Particle.generate(
      count: 40,
      generator: (i) => AcceleratedParticle(
        lifespan: 2,
        acceleration: Vector2(0, 100),
        speed: randomVector2(),
        child: CircleParticle(radius: 2, paint: paint),
      ),
    ),
  ),
);

becomes:

add(
  ParticleEmitterComponent(
    position: position,
    emitter: ParticleEmitter(
      bursts: [EmitterBurst(0, 40)],
      lifespan: (2, 2),
      speed: (0, maxSpeed),
      gravity: Vector2(0, 100),
      size: (4, 4),
      colorOverLife: ColorRamp.solid(color),
    ),
    renderer: CircleParticleRenderer(),
  ),
);

Rough mapping from the old API:

  • ParticleSystemComponent + Particle.generate: ParticleEmitterComponent with an EmitterBurst (or rate for continuous emission).
  • MovingParticle/AcceleratedParticle: speed, direction, spread, gravity, drag on ParticleEmitter.
  • CircleParticle: CircleParticleRenderer; SpriteParticle/ImageParticle: SpriteParticleRenderer.
  • ScalingParticle/ScaledParticle: size plus scaleOverLife.
  • RotatingParticle: rotation and spin ranges, or rotateToVelocity.
  • PaintParticle color effects: colorOverLife (ColorRamp) and opacityOverLife.
  • ComputedParticle/ComposedParticle/ComponentParticle: CallbackParticleRenderer or a custom ParticleRenderer/EmitterShape; compose several ParticleEmitterComponents for layered effects.

Related Issues

Base automatically changed from remove-flame-oxygen to main July 19, 2026 15:32
@luanpotter luanpotter added the v2 A feature or fix needed before the release of V2 label Jul 19, 2026
@spydon
spydon force-pushed the new-particle-system branch from a85c897 to 39cb748 Compare July 19, 2026 15:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 A feature or fix needed before the release of V2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants