Distortion Effect Module -- Type Checked

I’m planning on using this effect for a game, so I spent a few hours messing with it and made my own module with type checking. It’s based from the Bubble Module - Distortion Effect. Thought it may be useful to share it with other developers.

note that your graphics need to be level 8 or higher or the effect won't work

Here is a baseplate thats already setup if u dont want to follow the steps below

Distortion.rbxl (97.0 KB)

Setting Up The Module


Parent a ModuleScript named “Distortion” to ReplicatedStorage and paste the code below.


If you want a mesh that already works well with this effect then Parent one named “DefaultDistortion”. Then change the color of the mesh to fully white and change the MeshID to rbxassetid://10691561431. After that add the mesh to a variable that we can fetch through the module.

Here is an example that fetches our mesh, add it under the “Distortion” table:
Distortion.DefaultDistortion = script:WaitForChild("DefaultDistortion")


local MIN_CLAMPED_TIME = 0.1

export type TransitionInfo = {


local Debris = game:GetService("Debris")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")

local distortionFolder = Instance.new("Folder")
distortionFolder.Name = "DistortionEffect"
distortionFolder.Parent = workspace

local Distortion = {}

Distortion.DefaultDistortion = script:WaitForChild("DefaultDistortion")

function Distortion.DefaultTweenInfo(tweenTime:number?):TweenInfo
	return TweenInfo.new(
		tweenTime or 1,

function Distortion.DefaultTransitionInfo(tStart:number?, tEnd:number?, sStart:Vector3?, sEnd:Vector3?):TransitionInfo
	return {
		TransparencyStart = tStart or 0.5,
		TransparencyEnd = tEnd or 1,

		SizeStart = sStart or Vector3.new(0.1,0.1,0.1),
		SizeEnd = sEnd or Vector3.new(5,5,5),

function Distortion.CreateDistortion(distortion:BasePart, track:CFrame|BasePart, tweenInfo:TweenInfo, transitionInfo:TransitionInfo):number
	local function distortionPart()
		local part = distortion:Clone()
		part.CastShadow = false
		part.CanCollide = false
		part.CanQuery = false
		part.CanTouch = false
		part.Massless = true
		part.Material = Enum.Material.Glass
		part.Size = transitionInfo.SizeStart
		part.Transparency = transitionInfo.TransparencyStart
		local highlight = Instance.new("Highlight")
		highlight.Enabled = false
		highlight.Parent = part
		return part
	local function tweenPart(part:BasePart)
		local fullTweenTime = math.clamp(tweenInfo.Time + tweenInfo.DelayTime, MIN_CLAMPED_TIME, math.huge)
		Debris:addItem(part, fullTweenTime)

		local propertyInfo = {
			Transparency = transitionInfo.TransparencyEnd,
			Size = transitionInfo.SizeEnd

		TweenService:Create(part, tweenInfo, propertyInfo):Play()
		return fullTweenTime
	if typeof(track) == "CFrame" then
		local part = distortionPart()
		part.CFrame = track
		part.Anchored = true
		part.Parent = distortionFolder
		return tweenPart(part)
	elseif typeof(track) == "Instance" and track:IsA("BasePart") then
		local part = distortionPart()
		part.CFrame = track.CFrame
		part.Anchored = false
		part.Parent = distortionFolder
		local weld = Instance.new("WeldConstraint")
		weld.Part0 = part
		weld.Part1 = track
		weld.Parent = part
		return tweenPart(part)

function Distortion.CreateContinuousDistortion(distortion:BasePart, track:CFrame|BasePart, tweenInfo:TweenInfo, transitionInfo:TransitionInfo, rate:number?):RBXScriptConnection
	local clampedRate = math.clamp(rate or 0, MIN_CLAMPED_TIME, math.huge)
	local prevTime = time()
	local waitTime = 0
	return RunService.Heartbeat:Connect(function()
		if time() - prevTime < waitTime then return end
		prevTime = time()
		local tweenTime = Distortion.CreateDistortion(distortion, track, tweenInfo, transitionInfo)
		waitTime = rate and clampedRate or tweenTime

return Distortion

After that the module should be all good to go, now you just need to require it.

Usage Example

If you want to see the effect in game put this code below into a LocalScript in StarterPlayerScripts. If you didn’t do the optional part for setting up the module then replace the first parameter of the CreateContinuousDistortion Function to the mesh you want it to use.


local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Distortion = require(ReplicatedStorage.Distortion)

local tweenInfo = Distortion.DefaultTweenInfo(10)
local transistionInfo = Distortion.DefaultTransitionInfo()
Distortion.CreateContinuousDistortion(Distortion.DefaultDistortion, CFrame.new(0,5,0), tweenInfo, transistionInfo, 1)


Could you add a video or screenshot please ? I don’t really understand what it does, is it animating a mesh part ? Or the camera ?

1 Like

This makes a part infront of the camera and using roblox default refraction system “distorts” the view.

To OP:
Cool but don’t alot of people already made this? And this would only work for people on max graphics so rip for the <8 graphics level people.

1 Like

I don’t plan on using it for camera distortion, though you probably can, I believe there is already a topic that goes over that with a module that works well. I myself will be using this for an in-game indicator. The only topic with a similar module that I know of is the Bubble Module - Distortion Effect.

The module they provide wasn’t the best for what I needed it todo, so that’s why I made this one.

I added a video and baseplate, hope that helps.

1 Like

Hey I have a question. Does this still hide particles and beams behind the distortion, or does it have a way around it that makes it unique from the other bubble module? :thinking:

Thanks for the resource btw! The option to select a distortion shape is helpful for unique distortion patterns. :slight_smile:

yes, it still hides particles behind it, I don’t know any way around that. The main difference between the other module and mine is that its written differently, has some extra functions, and is type checked. I could look into adding more features like that if it poses useful.

nice module but you might want to change the default starting transparency to something greater than 1. I’ve made my module that way so it doesn’t show any colors but still has the distortion shaders

Ah alright! I appreciate the extensive use of modularity by using type checking! Thanks for the response. :slight_smile: