In-Experience Build-a-Texture: EditableImage Support for SurfaceAppearance

[Update] January 26, 2026


Hi Creators!

We’re happy to announce that EditableImage support for SurfaceAppearance is now available in Studio! You can now use the EditableImage API to create your own custom Color, Metalness, Roughness, and/or Normal maps to create a SurfaceAppearance using the new runtime AssetService.CreateSurfaceAppearanceAsync method.

image3

EditableImage being used to modify the various maps that SurfaceAppearance supports, allowing a player to paint with a glossy yellow color.

To try out this new functionality, go to File > Beta Features > and enable “EditableImage support for SurfaceAppearance maps”

Getting Started

After enabling the Studio Beta, you can use the new AssetService.CreateSurfaceAppearanceAsync method by providing a table of EditableImage Content objects as input.

Here’s an example demonstrating how to create and apply a custom SurfaceAppearance to a MeshPart:

Click here to expand
game.Lighting.EnvironmentSpecularScale = 1 -- make sure we allow reflective surfaces

local InsertService = game:GetService("InsertService")
local meshPart = InsertService:CreateMeshPartAsync("rbxassetid://16799342206", Enum.CollisionFidelity.Box, Enum.RenderFidelity.Automatic)
meshPart.TextureID = "rbxassetid://16799393274"
meshPart.Size = Vector3.new(10,10,10)
meshPart.Parent = workspace

wait(5) -- make a dramatic pause

local AssetService = game:GetService("AssetService")
local ei1 = AssetService:CreateEditableImage({Size=Vector2.new(256, 256)})
local ei3 = AssetService:CreateEditableImage({Size=Vector2.new(4, 4)})
local ei4 = AssetService:CreateEditableImage({Size=Vector2.new(8, 8)})

-- purple albedo
ei1:DrawRectangle(Vector2.zero, ei1.Size, Color3.new(0.82, 0, 0.82), 0, Enum.ImageCombineType.Overwrite)

-- full metal
ei3:DrawRectangle(Vector2.zero, ei3.Size, Color3.new(1, 1, 1), 0, Enum.ImageCombineType.Overwrite)

-- 0 roughness
ei4:DrawRectangle(Vector2.zero, ei4.Size, Color3.new(0, 0, 0), 0, Enum.ImageCombineType.Overwrite)

local sa = AssetService:CreateSurfaceAppearanceAsync({
	ColorMap = Content.fromObject(ei1),
	-- NormalMap is not specified
	NormalMap = nil,
	MetalnessMap = Content.fromObject(ei3),
	RoughnessMap = Content.fromObject(ei4)
})

sa.Parent = workspace.MeshPart

Purple ColorMap + full metalness + zero roughness creates a very shiny object that reflects the environment. Note the Fresnel reflection on the side face.

The script provided above should be placed in a LocalScript parented to StarterPlayerScripts to ensure it runs correctly.

Keep in mind that if you leave a map as nil or do not provide an input for it, the SurfaceAppearance will be created without that map, using a default value instead (see code example + resulting texture above). This means you do not need to provide inputs for all four maps (ColorMap, NormalMap, MetalnessMap, RoughnessMap) if they are not needed.

Known Issues and Limitations

  • Only EditableImage Content can be used: The API currently only supports EditableImage Content as input. We are working on adding support to mix EditableImage Content with Content from Asset URIs, but for now, you can use published image assets with this new SurfaceAppearance method by converting them into an EditableImage first:

local myEditableImage = AssetService:CreateEditableImageAsync(Content.fromUri("rbxassetid://ASSET_ID"))

  • No Mipmaps are generated: This runtime, async capability is meant for in-experience creation and is not intended to replace the asset system. When a SurfaceAppearance is created with this API, it will not have mipmaps. If you choose to publish this SurfaceAppearance later, it will go through the full asset upload process, which includes mipmap generation.

  • No new compression: The images are not compressed using this new API. While this won’t add additional memory pressure compared to just using EditableImage objects, it’s something to be aware of.

Things to Keep in Mind

  • Note that the CreateSurfaceAppearanceAsync method is asynchronous. Although it may return almost immediately at the moment, this could change in the future.

  • SurfaceAppearance instances created with this API will have a higher memory footprint compared to Studio-created ones. They are heavier on GPU memory (up to 12x) and use more GPU memory bandwidth because their constituent textures are not compressed or optimally packed for efficiency. Please adjust your use accordingly.

  • The SurfaceAppearance instance is driven by its underlying EditableImage objects. Please keep in mind the existing best practices for working with EditableImage objects, especially regarding memory management, permissions, and Trust & Safety.

What’s Next

Our plan is to enable this for live experiences once we’ve gotten some initial feedback from you and feel confident about the API. We’re eager to hear your thoughts and suggestions on this new feature. Your feedback is what helps us improve!

Best,
Roblox Rendering Team

131 Likes

This topic was automatically opened after 10 minutes.

ok now add pixelation / aliasing options

68 Likes

Add Emission map, so parts of PBR’s can have neon/glowing effect

72 Likes

What is the ETA on allowing editble* APIs to work on existing in-game meshes, such as player avatars or map geometry?

A big usecase I have for editable surfaceappearances is making things like clothing & map objects look wet when it’s raining for example. This is physically impossible to do at the moment because the restrictions are so high, the feature isn’t really useful.

16 Likes

add .dds support for images please

18 Likes

Will this work in game for players to customize assets and save them ?

4 Likes

Ok, does that mean we can swap non-editable surfaceappearances in-game easily now?

2 Likes

That’s awesome! I can’t wait to see what it is used for.

2 Likes

Wow. This is good. They can do this in experience.

2 Likes

8 Likes

Will be interesting to see if we can create “live” foliage with this now without having to rely on interesting techniques that make it look 2d

2 Likes

WHOA thats a cool feature, a very welcome one

gives me an idea for a custom character painter, would be quite easy now

2 Likes

This will revolutionize high quality games as we know them. If this gets performant enough to use widely, it opens an entire rabbithole of dynamic textures, which will make Roblox even more realistic, and adds a lot of new unique ways to create assets.

This update is awesome. Absolute cinema

1 Like

This is pretty promising so far, I’ve been really wanting a way to create SurfaceAppearances at runtime.

Could it be made so that, when support for regular Content URIs is added, that we can get Mipmapping and texture packing supported, since the visuals of the SurfaceAppearance wouldn’t need to update based on an EditableImage?

It makes sense to leave these out for cases where someone would be, say, using EditableImage to paint onto a mesh. But for my case, I would want to be able to color any accessory that a player is wearing, but MeshPart accessories lack SurfaceAppearances, so in order to do this I would have to generate that SurfaceAppearance and set the TintColor accordingly. As such, I don’t need to dynamically change any of the maps, and there’d be a lot of them, so I’d rather have improved performance over fast generation.

A more ideal solution would be to allow Color3 on MeshPart textures, but that’s been requested for a very long time so I’m not holding my breath.

2 Likes

Whats the current progress on the asset service APIs intended for uploading these to Roblox from Studio?

It looks like they got a bit left in the dark and are still restricted to the local plugin realm.

1 Like

So many cool things are going to be possible with EditableImage! Please, I beg you, add support for pressure sensitivity on tablet pens and touch devices (in studio too). :pleading_face:

2 Likes

oh wow so that mean we can make real washing game inside roblox , how do isave object i edited withsurface editableimage ;-; it gona be hard or complex

1 Like

Alot of people saying “add this” “add that”, but i just wanna say thanks, ive been waiting for this feature for a while, it’l defenitely enhance my ocean rendering quality :heart:

2 Likes

Thank you for making me aware of this, looking forward to it in the future!

1 Like