Atm, I’ve got movement working while keeping the model to stay where the bottom surface is always facing down. But I want to have it rotate along walls/roof/other surfaces.

This how it currently looks

And this is how I want it to work (from Adopt Me)

I am using raycast, so I should be able to get the normal by doing NewRay.Normal but I’m not sure how to include it, without it ruining the current the movement

local RaycastFilter = RaycastParams.new()
RaycastFilter.FilterType = Enum.RaycastFilterType.Blacklist
RaycastFilter.FilterDescendantsInstances = {Model, Player.Character, workspace.Plots.Interiors[Player.Name].Build.Door}
local UnitRay = Camera:ScreenPointToRay(Mouse.X, Mouse.Y, 1)
local NewRay = workspace:Raycast(UnitRay.Origin, UnitRay.Direction * 1000, RaycastFilter)
if not NewRay.Instance then return end -- Make sure instance exists
-- Snap to 0.5 grid
local PosX = math.floor((NewRay.Position.X / 0.5) + 0.5) * 0.5
local PosY = math.floor((NewRay.Position.Y / 0.5) + 0.5) * 0.5
local PosZ = math.floor((NewRay.Position.Z / 0.5) + 0.5) * 0.5
local NewPos = Vector3.new(PosX, PosY, PosZ)
local Pos = (Model.PrimaryPart.CFrame - Model.PrimaryPart.Position) + NewPos
Model:SetPrimaryPartCFrame(
Pos * -- Set position
CFrame.new(0, Model.PrimaryPart.Size.Y / 2, 0) -- Offset the model so its not halfway through the floor
)

You can use the Mouse.Target. This is what I would do.
1.) Set the floor part, maybe name it floor, and if the mouse.Target.Name is floor, then the orientation is always (0, Specified Angle, 0)
2.) Set wall parts, maybe name it wall, and if the mouse.Target.Name is wall then the orientation is (Orientation that you want, Angle that player specified, 0)
3.) To get the orientation that you want, use the position and then use math to detect which side of the wall it is on.

I suggest using raycasting and using after that RaycastResult, you can determine with RaycastResult.Normal how you should rotate the object you’re moving.
By making the direction of the normal the top side.

Note, you’ve to edit to rotate the CFrame offset of the model as well with this.

Yes, if you read my code you’d see I am using raycasting, and I am aware of how to get the normal. My question tho is how can I implement that into what I currently have

You would need to do some vector math using the cross product. Yes, you will have to use raycasting for this and use the surface normal of the part the ray has hit:

local axis = Vector3.new(0, 1, 0):Cross(normal)
local angle = math.asin(axis.Magnitude)
if cross.Magnitude == 0 then
axis = Vector3.new(1, 0, 0)
end
Model:SetPrimaryPartCFrame(CFrame.new(pos + normal * Model.PrimaryPart.Size.Y / 2) * CFrame.fromAxisAngle(axis, angle))

local axis = Vector3.new(0, 1, 0):Cross(normal)
local angle = math.asin(axis.Magnitude)
axis = axis.Magnitude == 0 and Vector3.new(1, 0, 0) or axis
if axis.Magnitude == 0 then
if normal.y < 0 then
angle = math.pi
end
axis = Vector3.new(1, 0, 0)
end
Model:SetPrimaryPartCFrame(CFrame.new(pos + normal * Model.PrimaryPart.Size.Y / 2) * CFrame.fromAxisAngle(axis, angle))

yOffset: model.PrimaryPart.Size.Y/2
surfacePos: position from the raycastresult snapped to grid

local function calculateCf(oldCf, yOffset, surfacePos, normal)
local oldUpVec = oldCf.UpVector
local oldRot = oldCf-oldCf.Position
local newPos = surfacePos+normal*yOffset
local dot = oldUpVec:Dot(normal)
if dot > 1-1e-5 then
return oldRot+newPos
end
if dot < -1+1e-5 then
return CFrame.Angles(math.pi, 0, 0)*oldRot+newPos
end
local scalarAngle = math.acos(dot)
local rotationAxis = oldUpVec:Cross(normal).Unit
return CFrame.fromAxisAngle(rotationAxis, scalarAngle)*oldRot+newPos
end