"Symbiote Shader" - Exemple of how to use Editable Image

Hello everyone,

I wanted to share something I made using the Editable Image API in an optimized way. If you’re looking to learn how to use it efficiently or just need some useful code, this might help. I used Perlin noise to generate smooth patterns and took advantage of the new buffer class for better performance. Everything runs at a stable 30 FPS without causing performance issues, so it works smoothly on any machine.

I made It very quickly (~15min) after seing this shader made in unity so if you find any problem I’d be happy to receive feedbacks.

I’ll post the source code below so you can check it out, learn from it, or use it in your own projects. Let me know if you have any thoughts or questions!

Code here:

Expend Me!
--[[

Created by: 
@Ph0enixx_31 (TR-MZ) on 2025-11-02

Description: 
This script creates a shader like noise effect on an image using the buffer module and the Editable Image API.

Note: 
I'm sure this can be optimized and made better, but this is just a simple example of how you can use the buffer module and the Editable Image API to create a shader like effect on an image.
You are free to use this code in any way you want, but it would be nice if you could credit me if you use it in a project or something.

My patreon: https://www.patreon.com/trmz
My X: https://x.com/tr_mz_
]]

----[[ Services ]]-----------------------------------------------------------------------------

local AssetService = game:GetService("AssetService")

----[[ Constants ]]---------------------------------------------------------------------------- 

local SEED = math.random(math.random(1, 10^8)) 
local DURATION = 2

----[[ Variables ]]----------------------------------------------------------------------------

local editableImage
local imageBuffer
local noiseBuffer
local imageSize

local finished = false

----[[ Functions ]]----------------------------------------------------------------------------



local function createNoiseBuffer(noiseBuffer: buffer)

	for i = 0, imageSize.X * imageSize.Y - 1 do


		x = i % imageSize.X
		y = math.floor(i / imageSize.X)


		local noise = math.clamp(math.noise(x / 50, y / 50, SEED) , -1, 1)
		noise += 1
		noise = noise * 127
		noise = math.floor(noise)


		buffer.writeu8(noiseBuffer, i ,noise )
	end

end


local function frame(frameIndex, imageBuffer: buffer, pixelsCount, noiseBuffer: buffer)

	frameIndex = frameIndex * 254
	for i = 0, pixelsCount - 1 do
		local noiseValue = buffer.readu8(noiseBuffer, i)

		if noiseValue > frameIndex then continue end

		local pixelIndex = (i) * 4
		
		-- You can also write a custom image here instead of setting the pixel color by using an other image buffer and taking its pixel color at index i 
		buffer.writeu8(imageBuffer, pixelIndex, 0)
		--buffer.writeu8(imageBuffer, pixelIndex+1, 0)
		--buffer.writeu8(imageBuffer, pixelIndex+2, 0)
		buffer.writeu8(imageBuffer, pixelIndex+3, 255)

		buffer.writeu8(noiseBuffer ,i, 255) -- this marks the pixel as already done so it doesn't recalculate it every frame
	end

	editableImage:WritePixelsBuffer(Vector2.zero, editableImage.Size, imageBuffer)

end

local function init()

	editableImage = AssetService:CreateEditableImage({Size = Vector2.new(1024, 1024)}) -- You can use a custom image here using CreateEditableImageAsync

	imageBuffer = editableImage:ReadPixelsBuffer(Vector2.new(0, 0), editableImage.Size)
	noiseBuffer = buffer.create(editableImage.Size.X * editableImage.Size.Y)
	script.Parent.ImageLabel.ImageContent = Content.fromObject(editableImage)

	imageSize = editableImage.Size

	createNoiseBuffer(noiseBuffer)

	local startTime = os.clock()

	while os.clock() - startTime < DURATION  do

		wait()

		local progress = (os.clock() - startTime) / DURATION
		frame(progress, imageBuffer, imageSize.X * imageSize.Y, noiseBuffer)

	end

end

init()
9 Likes

Hi,
Can you provide a model or .rbxl of an example with a public editable image… / example

Also is this a script or localscript… ?

Where are you pointing referencing the part / Editable image… I looked through the code twice and do not see it… maybe my coffee has not kicked in yet…

ps the effect looks pretty cool!

Thanks

1 Like

It’s a server script so It was easy for me to test but you can put it in a local script if you reference everything well.
The script is put in a part surface Gui where I have an image label.

Screenshot 2025-02-11 at 9.33.56 PM

here I reference the image

thank you a lot for the feedback!

1 Like

Cool effect! What FPS do you get with this transition? Does the FPS get worse with the increased resolution of the image?

1 Like

Thanks! I get 30fps for a 1024pixel image and 60 for a 512p image.