Going to assume one of the main issues you’re having is this:
(Where the circle is the front face)
For aligning these types of things depending on what surface you’re putting it on, you might want to do a raycast and grab the surface normal. Then getting the cross vector of the surface normal and the position it hits (or designate a relative front vector), this will give you the remaining piece for CFrame.fromMatrix
(It’s the right vector) which is the core of this.
Might want to check this out.
Code base
Undesignated front vector:
local result = workspace:Raycast(origin, direction, params)
-- // Just assuming there will be a hit for demonstration
local right_vector = result.Position.Unit:Cross(result.Normal)
local cframe = CFrame.fromMatrix(result.Position, right_vector, result.Normal)
-- // you can add trivial orientation manipulation like
-- // cframe * CFrame.Angles(math.pi * .5, 0, 0)
The result: https://gyazo.com/7430f5b078aeee72c1d820b7effe1b48.mp4
Setting the relative front vector:
local result = workspace:Raycast(origin, direction, params)
local set_front_vector = Vector3.new(0, 1, 0) -- // This will make it so it will always look up in a way
local right_vector = set_front_vector:Cross(result.Normal)
local cframe = CFrame.fromMatrix(result.Position, right_vector, result.Normal)
-- // And you can apply your rotations here and or add half the thickness of your object
-- // cframe * CFrame.Angles(math.pi * .5, 0, 0) * CFrame.new(0, part.Size.Y * .5, 0)
The result: https://gyazo.com/9c5d061a60b79813c094f6a5091a4b9b.mp4
Main issue with setting the front vector like this is that if you try to put an object on a surface where the surface normal is parallel to the provided front vector, the returned value from :Cross() will be Vector3.zero
so you would need to check if the two normals are parallel with :Dot() or whatever method you see fit.
Hope this helps.