ParticleEmitter
1.1.0indexedPhysics-driven particle effects with two renderers: layout-based custom particle content and high-performance canvas; directional gravity, edge behaviors (bounce/stick/wrap), blend modes, multi-emitter orchestration.
Physics-driven particle effects with two renderers: layout-based custom particle content and high-performance canvas; directional gravity, edge behaviors (bounce/stick/wrap), blend modes, multi-emitter orchestration.
A Compose Multiplatform particle effects library for Android, iOS, desktop, and web. Create beautiful, physics-based particle animations with two rendering approaches optimized for different use cases.
📖 API documentation — generated with Dokka, published on every push to main.
ParticlesEmitter — Compose layout-based, supports custom @Composable particles (text, images, shapes)CanvasParticleEmitter — Canvas-based, high-performance rendering for 1 000+ particlesMultiEmitterSOLID_OVAL / SOLID_RECT that emit from the whole areaSee PERFORMANCE.md for measured particle-count budgets per target frame rate (30 / 60 / 120 FPS), benchmark methodology, and sizing guidance for CanvasParticleEmitter on real hardware.
Want a project pre-wired with the library? Use one of the starter template repos — click Use this
template on GitHub to create your own copy. Each shows the simplest possible scene: a single
CanvasParticleEmitter centered on screen.
For Android projects, add the dependency to your module's build file:
dependencies {
implementation("io.github.piotrprus:particle-emitter:1.0.5")
}
For KMP projects, add the dependency like this:
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.piotrprus:particle-emitter:1.0.5")
}
}
}
| Module | Description |
|---|---|
particle-emitter | Core library — emitters, particle models, configs, rendering |
samples | Demo app showcasing different particle effects on all supported platforms |
CanvasParticleEmitter(
modifier = Modifier.fillMaxSize(),
config = CanvasEmitterConfig(
particlePerSecond = 50,
emitterCenter = DpOffset(200.dp, 400.dp),
startRegionShape = CanvasEmitterConfig.Shape.POINT,
startRegionSize = DpSize(dp, dp),
particleShapes = listOf(ParticleShape.Circle),
lifespanRange = ,
fadeOutTime = ,
scaleTime = ,
colors = listOf(Color.Cyan, Color.Magenta, Color.Yellow),
particleSizes = listOf(DpSize(dp, dp), DpSize(dp, dp)),
spread = IntRange(-, ),
blendMode = BlendMode.Screen,
initialForce = IntRange(, ),
)
)
ParticlesEmitter(
config = EmitterConfig(
particlesCount = 30,
emitDurationMillis = 1000L,
particleLifespanMillis = 2000L,
initialForce = 80,
gravityStrength = 1f,
gravityAngle = 0, // 0 = down
spread = IntRange(-45, 45),
) {
// Any @Composable content as a particle
Text("✨", fontSize = 20.sp)
}
)
MultiEmitter(
modifier = Modifier.fillMaxSize(),
emitterCount = 5,
emitterDelay = 200L,
emitterConfig = EmitterConfig(
particlesCount = 20,
particleLifespanMillis = 1500L,
) {
Box(
modifier = Modifier
.size(8.dp)
.background(Color.White, CircleShape)
)
}
)
Both emitters support configurable directional gravity via two parameters:
// Falling confetti — gravity pulls particles downward
CanvasEmitterConfig(
gravityStrength = 120f,
gravityAngle = 0, // down
spread = IntRange(-45, 45),
initialForce = IntRange(80, ),
)
CanvasEmitterConfig(
gravityStrength = ,
gravityAngle = ,
)
CanvasEmitterConfig(
gravityStrength = ,
gravityAngle = -,
)
The CanvasParticleEmitter uses physics-based motion: each particle has an initial velocity (from initialForce and spread angle) and is continuously accelerated by the gravity vector. This produces natural parabolic arcs — particles launched upward will curve back down, particles with sideways gravity will drift horizontally.
The ParticlesEmitter applies the same directional gravity to its kinematic equations, allowing custom composable particles to follow realistic trajectories.
The CanvasParticleEmitter supports configurable edge behavior — controlling what happens when particles reach the composable boundary.
// Bouncing particles with 70% energy retention
CanvasEmitterConfig(
edgeBehavior = EdgeBehavior.Bounce(damping = 0.7f),
// ...
)
// Particles stick to edges
CanvasEmitterConfig(
edgeBehavior = EdgeBehavior.Stick,
// ...
)
// Particles wrap around
CanvasEmitterConfig(
edgeBehavior = EdgeBehavior.Wrap,
// ...
)
Edge collision accounts for particle size — the visual edge of the particle touches the boundary, not the center.
startRegionShape controls where inside the startRegionSize box each particle is born, centered on emitterCenter. Outline shapes spawn along the perimeter; solid shapes spawn uniformly across the whole filled area.
The solid variants pick a point inside the region rather than on its edge, so a burst looks like the whole body breaking apart instead of just its border. SOLID_OVAL samples uniformly over the ellipse's area (no clustering near the center).
// A filled rectangle that disintegrates from its whole body
CanvasEmitterConfig(
startRegionShape = CanvasEmitterConfig.Shape.SOLID_RECT,
startRegionSize = DpSize(200.dp, 150.dp),
spread = IntRange(-180, 180),
gravityStrength = 550f,
// ...
)
See the Disintegrate sample for an interactive SOLID_RECT / SOLID_OVAL demo.
With a ring-shaped emitter (Shape.OVAL) and a 360° spread, some of the particles travel through the interior of the ring, cluttering the center. Set hideInStartRegion = true to skip drawing any particle whose current position is inside the start region — particles that leave the region become visible again on the far side.
// Ring emitter that keeps its interior clean
CanvasEmitterConfig(
startRegionShape = CanvasEmitterConfig.Shape.OVAL,
startRegionSize = DpSize(180.dp, 180.dp),
spread = IntRange(0, 360),
hideInStartRegion = true,
// ...
)
Particles still exist and move through the region (physics is untouched); they're just invisible while their position falls inside.
// Circle
ParticleShape.Circle
// Image with tinting
ParticleShape.Image(ImageBitmap.imageResource(R.drawable.star))
// Custom path
ParticleShape.PathShape(myCustomPath)
// Text (emoji or regular text) — requires a TextMeasurer
ParticleShape.Text(
text = "🎉",
textStyle = TextStyle(fontSize = 20.sp),
textMeasurer = rememberTextMeasurer(),
)
The sample app includes interactive demos:
| Canvas Emitter | Confetti | Glow Particles |
|---|---|---|
![]() |
| Gravity | Gravity Point | Sticky Edges |
|---|---|---|
![]() |
| Magic Wand | Emoji Rain |
|---|---|
![]() | ![]() |
| Drag a wand to leave a sparkling trail of stars | Fullscreen emoji particles using the Text shape |
Apache License 2.0
| Parameter | Type | Default | Description |
|---|
gravityStrength | Float | 0f (Canvas) / 1f (Compose) | Force magnitude in Dp/s². 0 = no gravity. |
gravityAngle | Int | 0 | Direction in degrees. 0 = down, 180 = up, -90 = right, 90 = left. |
| Behavior | Description |
|---|
EdgeBehavior.None | Particles pass through edges freely (default) |
EdgeBehavior.Bounce(damping) | Particles reflect off edges. damping controls velocity retained per bounce (0–1, default 0.7) |
EdgeBehavior.Stick | Particles stop at the edge and remain there for the rest of their lifespan |
EdgeBehavior.Wrap | Particles exiting one edge reappear on the opposite side |
| Shape | Emission | Notes |
|---|
POINT | The single emitterCenter point | startRegionSize is ignored |
OVAL | The perimeter of an ellipse (a ring) | Great for ring emitters with a 360° spread |
RECT | The perimeter of a rectangle | Hollow outline |
V_LINE | A vertical line segment | |
H_LINE | A horizontal line segment | |
SOLID_OVAL | Anywhere inside the ellipse, uniform over area | Reads as the whole shape turning into particles |
SOLID_RECT | Anywhere inside the rectangle, uniform over area | Bursts, disintegration, area fills |
| Parameter | Type | Default | Description |
|---|
hideInStartRegion | Boolean | false | When true, particles currently inside the startRegionShape + startRegionSize bounds are not drawn. Applies to the OVAL/SOLID_OVAL and RECT/SOLID_RECT regions. POINT, H_LINE, and V_LINE have no interior and the flag is a no-op. |
![]() |
![]() |
| Star particles with birth rate slider | Multi-emitter confetti with emoji and glowing stars | Glowing particles with blur and color animations |
![]() |
![]() |
| Canvas particles with gravity on/off toggle | Draggable gravity attractor with force slider | Particles bounce, stick, or wrap at edges |
Surfaced from shared tags and platforms — no rankings paid for.