There are other ways of doing this that I’m sure involve hinge constraints or offsetting CFrames, however a simple solution I’ve done before is to have an invisible part that is twice the size of the door and centered around the edge of the door, like so:
What we’re trying to do here is rotate the invisible part while having the actual door just follow the invisible part’s movement.
Anchor the transparent door part and unanchor the visible door part. Make the transparent part CanCollide = false. Then add a WeldConstraint with Part0 = transparent door, Part1 = actual door; like this:

Then just have the transparent part rotate like normal, not changing its position at all. I wrote this script to do just that:
local Angle = 120
local Open = false
local Tweening = false
local InvisibleDoor = script.Parent.RotatePart
script.Parent.Door.ClickDetector.MouseClick:Connect(
function()
if Tweening == true then
return
end
Open = not Open
local Turn_Radians = math.rad(Angle * (Open == false and 1 or Open == true and -1))
local Tween = game:GetService("TweenService"):Create(InvisibleDoor, TweenInfo.new(1), {["CFrame"] = InvisibleDoor.CFrame * CFrame.Angles(0, Turn_Radians, 0)})
Tweening = true
Tween:Play()
Tween.Completed:wait()
Tweening = false
end
)
I ended up having to make the transparent part slightly thinner than the door so I could click on the door, but rest assured this does not change where the hinge position is:
In addition to this, you could actually make the brick any size you want. It’s just easier to find the position if you resize it like I said initially. After you have it in the right place you can choose to make it a very tiny brick if you’d like.
And here it is in action:
https://gyazo.com/44401bf73a989f6b84712bd344acbab9
door.rbxl (27.9 KB)