Preventing glitch in between two CFrame tweens

I have created a simple die roll function that flips the die to the random result generated using stored rotations in CFrame values within the die. It works for the most part, but I want to get rid of glitch at the top of the path, you can see it suddenly jerks to some unknown rotation and then returns to where it is supposed to be. I don’t know what causing this as nothing is really happening between the two tweens playing.



local tweener = game:GetService("TweenService")
local rand =
local THROW = 5
local TWEENINFOUP =,Enum.EasingStyle.Quint,Enum.EasingDirection.Out)
local TWEENINFODOWN =,Enum.EasingStyle.Quint,Enum.EasingDirection.In)
function roll(die)
	local result = rand:NextInteger(1,tonumber(die.Name:match("%d+")))
	local dieStart = die.CFrame
	--Get rotation information stored in CFrameValue
	local x,y,z,R00,R01,R02,R10,R11,R12,R20,R21,R22 = die:FindFirstChild(tostring(result)).Value:GetComponents()
	local tweenUP = tweener:Create(die,TWEENINFOUP,{CFrame =,dieStart.Y+THROW,dieStart.Z,-R00,R01,-R02,R10,-R11,R12,-R20,R21,-R22)})
	local tweenDown = tweener:Create(die,TWEENINFODOWN,{CFrame =,dieStart.Y,dieStart.Z,R00,R01,R02,R10,R11,R12,R20,R21,R22)})

workspace.Event.Event:Connect(function() roll(workspace.D6) end)

Your matrix for tweenUp is off.

I can’t exactly fix it without knowing what you want it to be, but one fix could be changing



1 Like

This fixed it, thank you so much. I am curious though why I just needed to change a few signs on those. Is it because what I put in there is not a possible rotation somehow? I only flipped the signs at random on the way up to give it a bit more spin.

(oops I wrote a lot)

tl;dr: Don’t manipulate components directly unless you really need to.

Basically CFrame rotation is made of three vectors:

vector CFrame property equivalent GetComponents() vector
right RightVector, R10, R20)
up UpVector, R11, R21)
back -LookVector, R12, R22)

So the components list really is laid out like this:

local x,  y,  z,
      rx, ux, bx, -- x components for (r)ight, (u)p, and (b)ack vector
      ry, uy, by, -- y components
      rz, uz, bz  -- z components
    = cframe:GetComponents()

These three vectors must be orthogonal (at right angles to each other) and also follow the right-hand rule:


In that photo, X is the right vector, Y is the up vector, and Z is the back vector. So if a part’s CFrame matched that photo, it would look like:


In other words, this must always be true:

RightVector:Cross(UpVector) == -LookVector
-- or, equivalently
UpVector:Cross(-LookVector) == RightVector
-- or...
-LookVector:Cross(RightVector) == UpVector

So now knowing that the CFrame components are actually X, Y, Z components of three vectors, you can see why your random negating might cause problems – you might’ve accidentally flipped one of the vectors entirely and broke the right-hand rule, or you might’ve just negated like RightVector.X but not Y, and ended up with a non-orthogonal setup which behaves in unexpected ways.

We can see what happens if we play around with these:

local cf = script.Parent.CFrame
local right, up, back = cf.RightVector, cf.UpVector, -cf.LookVector

local function BreakRightHandRule()
	-- just flip one of them
	script.Parent.CFrame = CFrame.fromMatrix(cf.Position, -right, up, back)


This does this to our poor part (something similar happened with your d6):


However, if we negate back as well, the right hand rule happens to work out again and the part renders just fine (this is what I did in my response):


This is like if the hand from the first photo was pointing towards you, thumb down, middle finger to the left still.

Also see CFrame Math Operations for even more info :slight_smile:


Wow, thank you for the incredibly detailed response. I’ll definitely be more careful to make sure the right hand rule isn’t broken or just find another solution entirely. Lesson learned