Hi, I am not sure if I fully understand what you want to achieve, but anyway….
“Curve.HorizontalFrameAtParameter” is giving you the coordinate system you want, because:

The X Axis is going to be horizontal and contained in the vertical plane that included the normal direction ( that means that in a plan view the X Axis will be apparently tangent to the curve )

the Y Axis is going to be horizontal and perpendicular to the curve

Being X and Y horizontal , Z is obviously always vertical
Maybe you can have the issue of no consistent orientation of the X and Y Axis, that imply that the objects you align may flip the orientation.
I think that this is a little bug that will be solved at some moment. In the meantime you can avoid this problem, making directly the vectors and the coordinate systems, instead of using “Curve.HorizontalFrameAtParameter”
This is the code
vecNormal=cu.TangentAtParameter(par);
vecYAxis=vecNormal.Cross(Vector.ZAxis());
vecXAxis=vecYAxis.Cross(Vector.ZAxis());
CoordinateSystem.ByOriginVectors(
cu.PointAtParameter(par),
vecXAxis,vecYAxis);
Well, you have now your coordinate systems to align the objects. So …how to do this exactly?..depends if you are talking about populate dynamo geometry or revit family instances.
The first option is really straightforward. Just build the object related to a coordinate system convenient to work with (normally the default one), thinking the origin and default X and Y will be the equivalent ones in the curve. And later transform the object from this coordinate system to the ones in the curve.
The second option is a bit more tricky, because the family instance are thought (normally) to be hosted in a level with an offset with just an insertion point. As far as I know there is not a direct way to populate conventional family instances controlling the 3d orientation. This is the way a manage to do it (probably other dynamo users are finding other ways):
The object I want to populate is a normal family, for example a generic model
I create and adaptive component with just three points that will be the origin and the orientation of X and Y axis
The conventional family is nested in the adaptive component, inserted in a way that will follow the orientation drived by the three points
In Dynamo I use the coordinate systems in the curve for making groups of three points (for example by Cartesian coordinates 0,0,0 ….1,0,0…and …0,1,0)
In Dynamo I create adaptive components by points. So the result is that you will have the family instances populated following the desired 3d orientation .
This “intermediate” adaptive component with three points will be always the same, so the next time you need to make something similar you will jut reload the nested family for another one.
Anyway, this kind of workflows in Dynamo makes sense when you need to orientate the family instance with precise NO VERTICAL orientation. If you want just vertical orientation maybe you can find your way using directly “divide” and “repeat” in Revit without using Dynamo at all.