# Pixeldex · LÖVE Particle System Starter

Custom particle module for LÖVE 11.x in pure Lua. No shaders, no SpriteBatch tricks. Configurable emitters with lifetimes, velocities, gravity, size lerp, color lerp. Drop into any project.

License: **CC0**.
Source: https://pixeldex.dev/prompts/love2d-particle-system

---

## What's in this folder

| File | Purpose |
|---|---|
| `particles.lua` | The particle module. Drop into your project. |
| `main.lua` | Demo: click anywhere to get a coin-pickup sparkle. Ambient dust drifts upward in the background. |
| `conf.lua` | LÖVE config. |

---

## Fastest path (~10 seconds)

```bash
love .
```

(from inside this folder), or drag the folder onto LÖVE. Click anywhere in the 800×600 window to see particles burst. The HUD shows the active particle count.

---

## Using just the particle module

```lua
local Particles = require("particles")

local sparks = Particles.new_emitter({
 position = { x = 400, y = 300 },
 lifetime = { min = 0.4, max = 0.9 }, -- seconds
 speed = { min = 40, max = 140 }, -- pixels per second
 direction = { angle = -math.pi/2, spread = math.pi }, -- upward, full spread
 gravity = { x = 0, y = 200 }, -- pixels per second per second
 size = { start_size = 5, end_size = 1 }, -- linear lerp over lifetime
 colors = {
 start_color = {1, 0.83, 0.4, 1}, -- {r, g, b, a} in 0..1
 end_color = {1, 0.18, 0.43, 0}, -- fades to transparent pink
 },
})

function love.update(dt)
 sparks:update(dt)
end

function love.mousepressed(x, y)
 sparks:set_position(x, y)
 sparks:emit(20) -- spawn 20 particles right now
end

function love.draw()
 sparks:draw()
end
```

---

## Recipe book

**Coin pickup sparkle**: yellow → transparent pink, gravity 200, brief lifetime (0.4-0.8s).

**Hit spark**: bright red → black, no gravity, spread = 2π (radial), 0.2-0.4s lifetime.

**Dust under feet** (player landing): brown, gravity 100 (settles down), narrow spread, 0.6-1.0s.

**Smoke trail**: gray → transparent, gravity NEGATIVE (drifts up), wide lifetime (1-3s), narrow spread.

**Magic sparkle**: cyan → white, gravity 0, slow speeds, twinkling 0.8-1.5s lifetimes.

Each "feel" is just a different config object passed to `new_emitter`. The math is the same.

---

## Performance

Capped at **500 particles per emitter**. The update loop uses swap-and-pop removal (O(1) per dead particle, no table reshuffling). At 60fps with 5 emitters maxed out at 500 each, you're drawing 2500 small rectangles per frame, still buttery on a 2020 MacBook Air.

---

## Pairing ideas

- Pair with the [LOVE2D collision starter](https://pixeldex.dev/prompts/love2d-bump-collision) for hit sparks when the player bonks a wall.
- Pair with the [Phaser walkthrough](https://pixeldex.dev/walkthroughs/ship-a-phaser-web-game-in-an-evening), the same particle pattern translates to Phaser with minor API changes.

---

If you ship something with this, a link to https://pixeldex.dev helps. Not required.
