Trying to make a mirror, but it's not working properly

Hey there,

I’m trying to make a working mirror by using a ViewportFrame inside a SurfaceGui adorned to a part. If you test the code, you can see that the mirror somewhat works, except that when you go left, it goes right, and vice-versa. It also cuts you out a bit.

Here is the code:

local cam ="Camera",script.Parent)
cam.FieldOfView = 70
local pos = workspace.Part.CFrame.Position
local lv = workspace.Part.CFrame.LookVector
cam.CFrame =,pos + lv)

script.Parent.ViewportFrame.CurrentCamera = cam

local char ="Model",script.Parent.ViewportFrame)
local realChar = game.Players.LocalPlayer.Character

for i,v in pairs(realChar:GetChildren()) do
	if v:IsA("BasePart") then
		local c = v:Clone()
		c.Parent = char
		if v:IsA("BasePart") then
				c.CFrame = v.CFrame

I do realize that it is not optimized, but I put this together in just a minute.
Thanks to all the bros that help me out on this. :slight_smile:


Try using boatbomber’s ViewportFrame Camera System. It is less laggy and much more stable


Thanks for that, I will use it!

However, this still does not solve my problem. I’m trying to make the character in the mirror go left when player moves left, and vice versa. My problem is that things move the opposite direction in the mirror. Is there a way to inverse the Coordinate Frame of parts in some way to make it replicate the effects of a mirror?

You’ve been pretty helpful so far though, I’m glad you shared this model with me :slight_smile:

You need to get the position of each part in object space of the mirror. Then take that and multiply the axis you want to mirror by -1. Finally convert it from object space back to world space.

If you don’t know how to convert to and from object space CFrame has a method for that.


Do note that even if motion is flipped in my camera model, object shapes and textures will not be.

It won’t actually be mirroring the objects, since meshes and CSGs and images aren’t being flipped.

I don’t know why I thought my original post would work. For reasons brought up by boatbomber, no CFrame solution could ever work.

I’m on mobile and can’t test this, but it’s possible you could get this to work by making the X size of your viewport frame negative. If this doesn’t work then it is highly likely that there is no current solution to your problem.

Your code is kinda confusing lol

Your main issue: Camera CFrame updating is the main cause of your issue, you aren’t “reflecting.” Your system is just a camera. So your right arm is gonna show up on your left instead, etc.
You’ll need to use the handy reflection equation for determining a vectors direction after being, well, reflected…

I made this before, so if you wanna see a model go to:

I will note that I could make it better by using a billboard gui but im too lazy lol.

I can explain my system in more depth if you need, but I think this is enough to help you along without boring you.

1 Like

Please do go in depth! If someone isn’t interested, they can just scroll.

Also, yes. My system is a camera, not a mirror. That is not an issue, that was its purpose. He suggested repurposing my camera to become a mirror.

1 Like

Whoops, I thought you were OP. Pardon me lol

In any case, my mirror system is mainly based on the reflection equation.
It starts of by getting the camera of the viewer (means the scripts have to be client-based) and determining the position. From there, it gets the direction from the player’s camera to the mirror and applies the handy reflection equation.

Basically when a vector/direction is reflected, the reflected vector is always the same angle from the normal (The vector perpendicular to the surface) of the surface as the original vector.
A visual representation (the dotted line being the normal):
Code representation (using right vector because the mirror is on the right surface):

local nDir = dir - 2*(dir:Dot(mirror.CFrame.RightVector))*mirror.CFrame.RightVector

Points to notice:

  • dir is the direction from the mirror to the camera
  • I am doing a dot product on both dir and the rightvector to find the angle (a simplification of the original formula due to both of them being united)
  • I multiply that angle to the normal vector of the surface (right vector in my case) and double it
  • I subtract this doubled version from the original direction to get the new reflected direction (doubled to avoid receiving the normal vector instead of the reflected vector)

So every time the camera of the player moves, the camera of the mirror reflects itself accordingly.
This was poorly explained because I couldn’t locate the reflection equation I got. I swear it’s somewhere.


ViewportFrames generally are not useful for trying to make a mirror. They cannot show the correct perspective, nor can you flip meshes or images on one axis without reversing normals (unwanted inversion of the parts). You can generally make a better looking fake mirror with a room behind a transparent wall than with a ViewportFrame. The lighting will be more consistent with what’s on the real-world side of the mirror, and all part types are supported. There is no solution for arbitrary, asymmetric characters or designs (including shirts with writing) to actually be mirrored, you just need to give up that dream or force players to have characters that you’ve manually created mirrored versions of.


You all have good solutions!
I agree with both @tlr22 and @EmilyBendsSpace!
However, tlr22 will get the solution tag due to me trying to use ViewportFrame .

The reason for that is that they can provide more of the 2d-reflection effect like a real mirror. Using parts behind glass makes it seems too 3D, and simply unrealistic.

@tlr22, I will take your idea with a bit of editing: After multiplying by -1, you have to convert it BACK to world space, in order to see objects in proper position. If I am wrong, pkz correct me :slight_smile:

Anyways, thanks everybody! I am glad you contributed and you gave the community valuable information that anybody could access!

EDIT: @GreekForge had a GREAT idea, but the problem was that things moved the oppisite direction still, which is not what I wanted. Good math tho!