CFrame API Suggestions

First I’ll suggest an optional overload for cframe:components(), with a behavior similar to unpack:

Current behavior for unpack:

local t = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"}
print(unpack(t, 4, 9))

 > d e f g h i

Suggested behavior for cframe:components(p0, p1):

local m00, m01, m02, m10, m11, m12, m20, m21, m22 = cframe:components(4, 12)

Since the vectors are stored vertically, this feature would be pretty useful too:

local cframe = workspace.CurrentCamera.CFrame
local m02, m12, m22 = cframe:components(6, 6, 9, 9, 12, 12)
assert(, -m12, -m22) == cframe.lookVector)

The overhead from using cframe:components() corresponds with how many Lua variables are being set, so this could help out with intense cframe math. Testing for extra arguments in the c++ would have its own overhead, but hopefully that’s insignificant.

An overload for CFrame.fromEulerAnglesXYZ/CFrame.Angles that sets the position would be very helpful as well:
What we’re doing:

local cframe =, 2, 3) * CFrame.fromEulerAnglesXYZ(2, 3, 4)

What we could be doing:

local cframe = CFrame.fromEulerAnglesXYZ(1, 2, 3, 2, 3, 4)

Also extra methods like CFrame.fromEulerAnglesYXZ and CFrame.fromEulerAnglesZXY would be cool too.


CFrame.fromEulerAnglesYXZ(1, 2, 3)
would be the same as
CFrame.fromEulerAnglesXYZ(0, 1, 0) * CFrame.Angles(2, 0, 3)

I kinda feel like this would lead to very poor readability and inconvenient typos.


I’d really love some methods or properties that simply return the 1st/2nd/3rd column from the rotation matrix, having to use the components method results in loads of unneeded return values and less readability.


Yeah, I agree with that.

I agree with this part.

Definitely agree with the first proposition, ‘meh’ on the second suggestion though.

I don’t really care for the idea of swizzling or a subselect from components(). I would prefer access to the component vectors, and that’s all it really needs.

1 Like

Along with the Quaternion type that has been suggested (see the suggestions Trello) I think that a way to convert between CFrames and Quaternions would be nice. Something like CFrame:AsQuaternion() would be good.

Could we have a toAngles equivallent of toEulerAnglesXYZ?

I’m actually surprised anyone is using that for serious work. What do you use it for?

Personally I would rather have the following than an unpack behavior:

ComponentVector Enum with the following states:

  1. PositionVector
  2. XVector
  3. YVector
  4. ZVector

You put it into Components and out pops a Vector3.

local X = CFrame:Components(Enum.ComponentVector.XVector)

--equivalent to:

local _,_,_,xx,_,_,xy,_,_,xz,_,_ = CFrame:Components()
local X =,xy,xz)
1 Like

That sounds clunky from an API perspective. Why not some readonly properties? Maybe just expanding on lookVector, like rightVector and upVector.


What about a backVector? lookVector is the negative of the axis and it’s kinda weird to have to remember that it’s the odd one out.

It’s probably more useful to keep lookVector, since you can always just do -lookVector.

Couldn’t one use select?

local m00, m01, m02, m10, m11, m12, m20, m21, m22 = select(4, cframe:components())

Yeah if you don’t care about efficiency.


@0xBAADF00D Can you guys possibly fix the Gimbal lock problem that occurs when you multiply the Camera’s CFrame around the point where the Camera is trying to look up/down 90 degrees? I have a feeling its not as simple as it looks to fix, considering that Unity has the same problem, but perhaps a Quaternion safe-guard could solve it?

Its hard to exactly describe this bug, but if you’ve seen it, you know exactly what I’m talking about. If you change the MIN_Y / MAX_Y values in the CameraScript to something higher than +/- 89, it glitches out.

Are you talking about how it uses a “look-at” transformation to calculate it? If the camera is staying upright at all times (until then), then it definitely is.

It’s because the camera’s transform is constructed each frame using essentially a single vector and a position. The direction that “up” is in is always 0,1,0. That means that if you try to rotate your look vector past 89 degrees, it’s no longer the same horizontal direction relative to the up vector. That is, math.atan2(look.Z, look.X) would vary wildly.

Lol, okay, I made a thing for you. A crappy slow and untested version of,v3)

local tolerance=1e-6
local function CameraLook(position,target)
	local zvec=(position-target).unit
	local xvec=up:Cross(zvec)
	local xmag=xvec.magnitude
	if xmag<tolerance then
		local yvec=zvex:Cross(xvec)

Pretty sure it works.

Ah, yes- silly me, efficiency is kind of an important thing. Thanks for pointing that out!