Voxel Particle System

Hi everyone! This is my first post here.

I came to Roblox from non-Roblox gamedev. While making my own game I felt a lack of per-particle controls, so I built a voxel particle plugin. I’m new to programming, but I have strong Cinema/VFX background. I added the essentials first and still have many ideas to expand.

Video demo:

Performance place (flamethrower scene—also lets you toast poops):
https://www.roblox.com/games/132587008195181/Voxel-Particles-Demo

ps: not sure it’s “donation-ready”, but the demo page can accept small tips.

Try the plugin (free & open-source):
https://create.roblox.com/store/asset/130639628121420/Voxel-Particles-System
If you want something added—post in the thread; I’ll review the code and ship it in the next update (waiting for proper Git on Roblox…).

How to use (quick start)

  1. Create an Emitter in the plugin. A default preset is applied; switch between several starters.
  2. Any parameter change overwrites the current preset—better Save as preset first, then edit.
  3. Play button = real-time preview in Workspace. Press Stop before playtesting, or some particles may remain (will fix next update).
  4. Burst mode emits in batches once per second (set emission rate = 0 and burst count > 0). Trigger it from your code whenever you like.
  5. Many params have 3 time curves (start/mid/end).
  6. Some params support noise; same amount/frequency/seed = synced modulation (e.g., lifetime + rate for fire flicker).
  7. Face movement direction makes particles align to their velocity.
  8. Spawn surface only also works on flat shapes (spawns along perimeter).
  9. Update & LOD: higher update steps (e.g., 3) reduce cost for size/opacity updates.
  10. Total particles: the per-emitter cap exists; global cap can be tuned in the system code.

Everyone who tries it—please share how comfortable it feels and what you miss most. I’ll iterate soon.

UPD:
GIT: GitHub - WildCake/Voxel-Particles-Plugin: Roblox Studio plugin for authoring, previewing, and installing voxel particle effects. · GitHub

48 Likes

Amazing work! My only suggestion would be particle prewarming (as seen in unity), where the complete cycle is pre-generated instead of only observing the start when enabled

1 Like

Wow! This is pretty cool! Right now, I would say it’s great, but not any better than the current Roblox particles, but as you mentioned, these are just the essentials. I can’t wait to see the things you will accomplish - I know this is going to go far!

1 Like

Very cool plugin, i have made this so far


I feel like this should be in Resources > Community Resources as youre giving people a resource

Also

What?

5 Likes

haha, i meant open my test place to check flamethrower (just wanted to add any enemies to test, need to aim first then press LMB):

4 Likes

Actually this is good idea, thanks! Will add definetely!

1 Like

moved topic to Community Resources

1 Like

NEW UPDATE
math.noise → simple curves (was too complicated per particle)
added 30FPS mode (light interpolation between frames)
This reduced the CPU load by 30%

Tutorials on the way
UPD (CPU spike on video due to another game system)

4 Likes

when tutorial?

iiiiiiiiiiiiiiiiiiiiiii < (ignore)

1 Like

Hi everyone!

I’ve rolled out a new update. Some people didn’t like that the particle system’s emission vector was defined in world space, and the binder had to convert it to local space when needed. I’ve moved this logic from the binder script into the core system. Now you can skip using the binder entirely and trigger particles directly — they will automatically use the emitter’s rotation for their emission angle (for example, for a flamethrower).

I’ve also added a Line of Sight (LOS) system so emitters won’t render particles through walls. (This is separate from the camera-angle check — that feature was already implemented: if you look away from an emitter, it stops emitting. Now it also stops emitting if you’re looking at it but it’s behind a wall or blocked by an object.)
By default, objects that only have “CanQuery” enabled are ignored, as well as the emitter itself. If you want an emitter to ignore LOS entirely, just add the attribute VoxelIgnoreCulling = true.

I also added smooth rate scaling: if the total number of emitters is getting close to the emission limit, all rates will gradually decrease. Previously the system would simply disable one of the emitters abruptly.

I’ve added rate scaling based on graphics settings as well — if someone forces manual low settings, the emission rate will adjust accordingly.

And lastly, I’ve made a full game that uses the voxel particle system for all its effects — here’s a demo video:

TUTORIAL ON THE WAY, in a day or even today

1 Like

It’s pretty nice, but the code comments should be in english.

1 Like

Yes, forgot to fix, will update soon

1 Like

hey there!

im attempting to learn how to use this in my game and so far its kinda working but how do you code it correctly? ive been reading the actual code but couldn’t find a way to use my presets when i trigger the particle in a script.

this is what im attempting to do:

local particleAPI = require(game.ReplicatedStorage.Shared.VoxelParticleSystem)
local particlePreset = require(game.ReplicatedStorage.Shared.VoxelEmitterPresets:WaitForChild("DashSmoke"))

local dashParticle = particleAPI.Attach(HumanoidRootPart, particlePreset)

this should work on paper (i think) and gives no errors but it always defaults to the default configuration

do you have a sample or an example of how to do it correctly? otherwise ill just keep trying until i figure it out : O

thank you for the help : )

1 Like

Your preset ModuleScripts don’t return the emitter config directly — they return a “wrapper” table like:

return {
    name = "...",
    displayName = "...",
    emitterWorldCFrame = ...,
    state = { ... ACTUAL EMITTER CONFIG ... }
}

VoxelParticleSystem.Attach(anchor, config) expects the config table, so if you pass the whole preset table it won’t see rate/color/etc at the top level and will fall back to defaults. Fix: pass preset.state (or preset.state or preset).

Direct Attach sample:

local RS = game:GetService("ReplicatedStorage")
local Shared = RS:WaitForChild("Shared")

local VPS = require(Shared:WaitForChild("VoxelParticleSystem"))

local preset = require(Shared:WaitForChild("VoxelEmitterPresets"):WaitForChild("Dash")) -- your preset module
local cfg = preset.state or preset -- IMPORTANT

local emitter = VPS.Attach(HumanoidRootPart, cfg)

-- If you want a burst:
emitter:Emit(cfg.burstCount > 0 and cfg.burstCount or 25)

-- Optional cleanup if it’s a one-shot effect:
task.delay(2, function()
	emitter:Destroy()
end)

If you’re using the included binder (attributes way)

The plugin’s VoxelEmitterBinder listens for:

  • tag: "VoxelEmitter"
  • attribute: "VoxelPreset" (string, preset ModuleScript name)
  • attribute: "VoxelBurst" (number; -1 = use preset’s burstCount)
local CollectionService = game:GetService("CollectionService")

CollectionService:AddTag(HumanoidRootPart, "VoxelEmitter")
HumanoidRootPart:SetAttribute("VoxelPreset", "Dash")

-- trigger:
HumanoidRootPart:SetAttribute("VoxelBurst", -1)   -- uses preset burstCount
-- or:
HumanoidRootPart:SetAttribute("VoxelBurst", 40)   -- explicit amount

Recommended to run effects from a LocalScript; if you trigger from server, fire a RemoteEvent or set attributes on the server and let the client binder play it

Hope it helps :smiley: Im pretty busy with my Astro Farm game and can’t finish tutorial right now or translate comments in code

1 Like

OHHHHHHHHHHHHHHHHHHHHHHHHHHHH thank you this makes a LOT more sense king thank you and good luck with Astro Farm!

1 Like

New update!

Voxel Particles v11

Updating

Go to Plugins → Manage Plugins → Voxel Particles → Update, then restart Studio and reopen your place in Edit Mode.

Plugin-managed runtime files update automatically. Manually edited files and native Script Sync sources are never overwritten.

Performance and Stability

  • The 512-Part pool now warms gradually at a maximum of 8 creations per frame instead of causing a startup spike.
  • Explicit bursts use the pool and are not restricted by the background creation budget. Existing emitter and global spawn limits remain active.
  • Fixed fair-share scheduling, spawn-demand accounting, quality scaling, emitter rebinding, and cleanup.

Motion

  • Fixed frame-rate-independent Acceleration integration.
  • Added accelerationDrag to prevent unlimited acceleration. Default: 20; use 0 for unlimited acceleration.
  • Acceleration curves now support -5 to 5 for fading, braking, or reversing forces.
  • Added the cylinderStream emission shape.

Presets

  • Added explicit Acceleration Drag values to bundled presets.
  • Existing custom presets are preserved.

For older custom effects, start with:

accelerationDrag = 20

Then reduce old Acceleration values to roughly 5–10% and retune as needed.

Plugin Editor and Runtime Updates

  • A lot UI improvements
2 Likes

Voxel Particles Plugin v12

Version 12 is now available, and the source code is public.

  • Adaptive VFX quality based on graphics settings and FPS
  • Radial outward and tangential particle motion
  • Uniform annulus emission
  • Updated editor and safer runtime installation

Now on git as well, feel free to add ideas:

Skill and agents.md there as well to easiest understanding and usage

1 Like

Hi, can you make the demo place editable ? and add some more cool stuff to check out ?

Thanks

1 Like

Added a demo gallery with labeled presets, looping bursts, Bézier effects, and preset combinations!

Since the curve update, I’ve added shared particle/emitter budgets, improved off-screen culling and pool prewarming, and fixed errors when editing presets. Plugin and runtime versions are now unified.

After updating the plugin, click Update project to update your project’s runtime. For native Script Sync projects, follow the update instructions in the README on Git.

Sorry can’t do editable atm, will do it later, need to cleanup server folders from my models (they are hidden in public place)


ALL thе presets from demo scene was added into plugin presets.
link again:

1 Like