I’ve created a script to interpolate a part’s angles revolving fully around a circle in a loop (counter clockwise), however I don’t know how/why the CFrame angles are moving the position as well. It’s probably to do with how I’m handling the calculation of standard position, as I haven’t found a way to retrieve that successfully as tuple of 3 values.

```
local part = script.Parent
local TweenService = game:GetService("TweenService")
local function rotationFromCFrame(cframe)
--[[ Returns a tuple containing the angles from any cframe passed. ]]
-- why not `local standardPos = CFrame:ToEulerAnglesXYZ (CFrame.Angles(part.CFrame))`? Argument 3 missing or nil for some reason appears even if (0,0,0)
local components = { cframe:components() } -- put into array
return components[4], components[5], components[6]
end
------- Variables
local standardPos = CFrame.Angles( rotationFromCFrame(part.CFrame) )
print(standardPos)
local rotations = {
math.pi/2,
math.pi,
(3 * math.pi)/4,
}
local function tweenRot(part, cframe, duration)
--[[ Tween wrapper that rotates a part's rotation from passed args. ]]
local goal -- declare. should never be nil
if cframe == 'standardPosition' then
goal = {
CFrame = standardPos
}
else
goal = {
CFrame = part.CFrame * cframe
}
end
local tweenInfo = TweenInfo.new(
duration,
Enum.EasingStyle.Sine,
Enum.EasingDirection.Out,
0,
false,
0
)
local tween = TweenService:Create(part, tweenInfo, goal)
tween:Play()
local debugvars = "goal: "
for i,v in pairs(goal) do
debugvars = debugvars .. tostring(v) .. ', '
end
print(debugvars)
end
------- Main
repeat wait()
for index=1, #rotations do
wait(3)
tweenRot(part, CFrame.Angles(0,rotations[index],0), 1)
print('Index CFrame:\t i=' .. index .. ' | ' .. tostring( rotations[index]) )
print('Part CFrame:\t i=' .. index .. ' | ' .. tostring( rotationFromCFrame(part.CFrame) ) .. '\n')
end
wait(3)
tweenRot(part, 'standardPosition', 1) -- reset to standard pos
until part == nil
```