Shatterbox | Client-Server Voxel destruction, simple and optimized [Release 8]

Current Version: Release 8
Release Date: Feb 3, 2026
Roblox has unflagged the library, I hope it will not happen again for future releases.

Shatterbox Client-Server Voxel Destruction

Discord | Creator Store | GitHub | Test Experience


External Resources

 BlinkLogo is used for client-server communication.
VoxBreaker inspired many features as well as the current syntax of the module.


Hello, I am here presenting a library designed for use in games that require voxel destruction on static maps. It is made to be scalable with performance and maintenance. It is also designed to be very easy to use. If you're looking for a fast destruction library that won't make your buildings flash (with StreamingEnabled), you found it!

In terms of performance, I would say that my system rivals JJS. It might even out-perform it. I am still working on the module.

Cover7


Here is the test place file if you just want to jump into Studio and see it in action:
ShatterboxTestPlace.rbxl (213.1 KB)

There are 7 different tools that showcase various parts of the library. Feel free to explore and use the code from there if you need to.


Watch the video guide on YouTube


Example GIFs

Secure (sanity checks are up to you), seamless client initiated destructions so you can have hitboxes that perfectly predict your Players.

ClientInitiatedDestructions


The optional Puppeteer system creates interpolated debris, for when you just really want to squeeze out as much client side FPS as possible with loads of debris, at the expense of the server speed.

InterpolatedVoxels


True greedy meshing is used (sorry VoxelDestruct 2.1) to minimize the number of static parts resulting from destruction

GreedyMeshing


Texture instances maintain their proper offset on voxels and static parts

DivisibleTextures


Encapsulation checks are used to make larger operations insanely fast. (SkipEncapsulatedVoxels)

_EncapsulationCheck


Any Part shape is supported when using the destruction functions. MeshParts are not supported due to me using math under the hood to minimize calls to spatial query functions.

Encapsulation checks are used even when SkipEncapsulatedVoxels = false, which is a key difference in my subdivision algorithm compared to others. When a part is fully encapsulated, I either voxelize it entirely or just destroy it rather than doing expensive subdivisions and intersection checks.

(notice the player is 1 pixel large in this gif, SkipEncapsulatedVoxels = true):

_AllPartTypes


The Reset function will reset all modified objects to the state they were in before subdividing. Use this before you change maps, to properly reset your map to the state it was in before Shatterbox touched it.

_ResetDirties


There is configurable smooth cleanup for destructions (you can turn it off with a setting or by setting CleanupDelay = 0)

SmoothCleanup


There are 3 built-in destruction effects, one which is the first gif shown in this thread, the second is a re-creation of JJS M1 destructions (with interpolated voxels). It’s called “BumpyFloorBreakWalls”:

JJSM1Replica


The final built in effect is called “MappingVoxelSpace” which is an example on how to use voxel space coordinates to perform voxel destruction effects regardless of the voxel size. All of these effects are found in the Shatterbox/effects modules

MappingVoxelSpace


How does it work?
The voxel destruction algorithm

Part divisions use a modified form of octree subdividing, where parts can either divide into 8, 4, or just 2 pieces. Shatterbox decides when it is best to use KD subdivisioning instead (CutPartInHalf like VoxBreaker).

To explain my ImaginaryVoxels algorithm, which is one of the key differences between my library and others, I will first explain the standard algorithm for voxel destruction:

The first step is to use GetPartsInPart on your “CuttingPart” to find all of the parts you need to subdivide. Then you subdivide all of them, and immediately put them in the workspace. If a part cannot be subdivided, it’s returned as a voxel. Repeat this process over and over until you have no more parts to subdivide. This is how VoxelDestruct 2.1, VoxBreaker, and presumably everyone else handles their voxel destruction.

My algorithm is different in the sense that it may only use one singular call to GetPartsInPart to find the destructible parts, and then I use pure subdivision/intersection/encapsulation math to generate the final product with no intermediate parts (unless you have the frame limit enabled).

That is why it’s called ImaginaryVoxels, because in a sense, the computer is doing it all “in its head” before displaying to you what it already knew. This algorithm is insanely efficient, where most of the performance loss comes from creating new necessary parts and destroying old ones, rather than the voxel destruction calculation itself.

Both of the destruction functions use ImaginaryVoxels under the hood. Currently, GreedyMeshing happens after these final static parts are created, which is room for potential improvement

If an overlapping Block is fully inside of the intersecting part, it either gets deleted or voxelized using ImaginaryVoxelize (according to SkipEncapsulatedVoxels). Otherwise, it gets divided. If a division is attempted but the part is at the minimum voxel size, it is considered a voxel.


Client-Server

The Client-Server algorithm just tells clients to copy the map before the server breaks it. When the client is done copying, it instantly starts its own destruction. The server-owned parts are not replicated to clients unless a new player joins, that new player gets fresh parts. This helps network usage massively since only the original parts get replicated, and reduces the part flashing caused by having StreamingEnabled = true.

When a client performs voxel destruction with Client-Server enabled, they are given permission to create dirty groups for the server and other clients. Visually this does nothing. This is how Shatterbox allows secure client sided destructions. If you want a client sided destruction to replicate, you have to do it yourself by performing the same destruction on the server side, making sure to put your own sanity checks in there so you don’t get hacked.


The Puppeteer system was gracefully explained below by @Impermanently, it also utilizes buffers. Unlike JJS, I handle interpolation through CFrame:Lerp() which has less memory churn compared to having to manage Tweens.
https://devforum.roblox.com/t/shatterbox-client-server-voxel-destruction-simple-and-optimized-release-6/3674163/91?u=azavier123


Optimization tips
  • The key to efficient destructions is to use GridSize according to part sizes. Large parts should have a larger GridSize. This keeps the number of divisions required for the average operation consistent

  • Consider “chunking” up large parts like the ground. This saves operation steps, allows encapsulation checks to work their magic faster, and makes greedy meshing appear faster (since greedy meshing only goes as far as the original part did).


Changelog

Changelog has been moved to GitHub. You can scroll through the commit history to see the changes each commit brought, as I provide a changelog for each of them. I know it’s not perfect, but there are simply too many changes to list at this point.


Known issues
  • None currently. Let me know if you find any bugs in this release, and tell me how I can reproduce it.

Planned features
  • Optionally, a more smooth “Smooth cleanup” algorithm which will dynamically remove operations, while preserving present ones.

  • Optional usage of the “ObjectCache” module.

  • Optional dynamic welding, for anyone who wants falling buildings instead of levitating ones.

  • Removal of the “static map” restriction. In the future, I plan to make Shatterbox a system akin to the “Clone Drone in the Danger Zone” so that resetting of moved divisions is possible.

  • Union “slice” style destructions, which are not voxel destruction, but I think are cool.

  • Some sort of EditableMesh destructions, perhaps with Marching Cubes?


Current development sneak peeks

Falling buildings / unanchored parts (people have been asking for this for so long)

FallingBuildings


I know it’s not perfect, and I am all ears for any possible optimizations. I am actively developing this and will update the thread if any information changes accordingly. I hope you guys like it!

Join the discord server if you need assistance: https://discord.gg/WRfz79uRTy

BigDestruction
(I am thinking of ways to mitigate the part flashing even further. This gif shows that Client-Server currently isn’t foolproof, and if your server is extremely laggy part flashing can still happen)

125 Likes

Does this work on wedges? Support for all part shapes would be amazing

3 Likes

For part intersections, any shape is supported as the part of intersection. This is because GetPartsInPart is used for collision checking. It should even work with custom meshes if they have the proper CollisionFidelity. In effect, you can make whatever destruction shape you desire.

For part divisions, the algorithm will work the same for any part type. The box type is the only one that is gonna look good as of now. I have been considering how I would implement divisions with wedge parts to smooth the edges, like this:

But this is not yet supported

4 Likes

Bump for Release 3. Thread contains new information and examples. Shatterbox has had its internals completely re-worked. This resulted in an optimization breakthrough (encapsulation checking):

_EncapsulationCheck

10 Likes

This is absolute Peak bro, Respect!!!

2 Likes

hi could u make a rbxl cuz like idk how to use it i tried,

1 Like

that cool ty
does it suffer with big parts?

1 Like

things if u did its will be so perfect :
make a cleanup method that clean destroyed part
make it 2 styles all part or just the part that just got destroyed by the module not all of them
and make a way for debris.

for me ill try to figure out the debris

1 Like

The Reset function cleans the map, but all operations have a 60 second smooth cleanup duration. This is configurable as the 5th parameter of the destruction functions.

To answer your question about performance, it’s a little complicated. When using encapsulation checking (fast destructions), I only have to worry about divisions along the boundary of the volume, instead of every single division contained within the volume. Consider the difference between the volume of a sphere and its surface area, that is the difference between MeshPart destructions and Part destructions.

TL:DR

Fast Destruction (only with Parts): Scales amazing with part size, you might see your performance increase as it gets bigger. See the first gif in examples where I delete a huge map using a sphere at max size

All other destruction: Scales horribly with part size, because each part must be subdivided all the way down into its constituent voxels

just a suggestion make a way so we take the part have been destroyed so
i can make a debris from it like :

local Debris = game:GetService("Debris")

local function getDestroyedPart(part, chanceForDebris)
	if not part or not part:IsA("BasePart") then return end

	
	if Random.new():NextNumber(0, 1) > (chanceForDebris / 100) then
		part:Destroy()
		return
	end

	
	part.Size -= Vector3.new(0.2, 0.2, 0.2)
	part.Anchored = false
	part.CanCollide = true
	part.CanTouch = false
	part.Position += Vector3.new(0, 0.5, 0)

	


	Debris:AddItem(part, 13.5)
 
end

thats just a example from what i mean u could make it better or a function

1 Like

Yes, that feature is coming in release 4! It’s almost done, sorry for the delay :sweat_smile:

Edit: I just posted release 4 in the Creator Store. Give me time to update the thread, although you should be able to use it without any issues.

This is what a setup looks like in Release 4:

local Shatterbox = require(game:GetService("ServerScriptService").Shatterbox)

local b = workspace.Ball


local function OnVoxelDestruct(Part : Part)

	local GridSize = Part:GetAttribute("GridSize") or 1

	if math.random() > 0.001 * GridSize * GridSize then Part:Destroy() return end

	Part.Anchored = false

	Part.CanCollide = false

	Part.AssemblyLinearVelocity = (Vector3.new(math.random(), math.random(), math.random()) - Vector3.one * 0.5) * 80

	Part.AssemblyAngularVelocity = (Vector3.new(math.random(), math.random(), math.random()) - Vector3.one * 0.5) * 20
end


local overlapParams = OverlapParams.new()
overlapParams.FilterType = Enum.RaycastFilterType.Include
overlapParams.FilterDescendantsInstances = { workspace.Map }



Shatterbox.FastDestroy(b, overlapParams, 1, OnVoxelDestruct)

1 Like

kk ill see and give u feedback!!

1 Like

This is the best voxel destruction system I’ve ever seen, It was even better after the update. I’m definitely i am adding this into my projects, so keep up the good work, dude.

1 Like


so when i tested before i didnt have time tbh and didnt test debris this is a bug i got
its keep making debris and its like this

1 Like

After the fourth release comes out, can you please post it along with a test place?

1 Like

4th release is out, I will work on a test place ASAP

1 Like

Hey, thank you for letting me know about this. I just pushed a fix for it. It was a rather silly bug; I wasn’t readjusting the parts correctly. Sorry about that.

1 Like

ty for fixing it ill try it now!!


this is so cool right now!!
i really appreciate ur work

2 Likes

How did you create moving hitboxes? Can you place those into the test place?

1 Like