# Creating stairs in Dynamo

**URL:** <https://forum.dynamobim.com/t/creating-stairs-in-dynamo/83724>\
**Category:** Revit\
**Tags:** revit, dynamo\
**Created:** [December 3, 2022, 12:46pm UTC](https://forum.dynamobim.com/t/creating-stairs-in-dynamo/83724 "2022-12-03T12:46:18Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![ceskoMU3VA](https://avatars.discourse-cdn.com/v4/letter/c/dbc845/32.png) [@ceskoMU3VA](https://forum.dynamobim.com/u/ceskoMU3VA)\
**Post date:** [December 3, 2022, 12:46pm UTC](https://forum.dynamobim.com/t/creating-stairs-in-dynamo/83724/1 "2022-12-03T12:46:18Z")

</div>

Hello everyone,

I am trying to create stairs in Revit with a help of Dynamo. Just as exercise but it is not so easy how I expected to be. Unfortunatelly there is not specific built In Node just for stairs.Only what I found to creating elements are the Nodes under Family Instance. So there is a Node with Input Family Type and set up the coordinates.

I was trying to figured out how the structure with stairs really works.What here is Family Type, Family name etc.? I tried in other direction, from run Type to stairs. I got a Family name right but now I have a problem with the Type name. How to get that?

 ![Creating the Stairs_R22](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/1/1/11c1a763d85d8d0cec1f6dff008d645943176485.png)

Thank you in advance for your answers 🙂

---

<div class="post-metadata">

**Author:** ![jacob.small](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.dynamobim.com/jacob.small/32/161030_2.png) [@jacob.small](https://forum.dynamobim.com/u/jacob.small)\
**Post date:** [December 3, 2022, 3:26pm UTC](https://forum.dynamobim.com/t/creating-stairs-in-dynamo/83724/2 "2022-12-03T15:26:51Z")

</div>

The elements which defines stairs cannot be built from scratch and have your stair function as you would expect. You need to build them as stairs via the UI or the actionable API method. I am not aware of any node to do so, but there is sample code for creating a new stair available in a few places online, my preferred starting point would be here: [Creating and Editing Stairs](https://help.autodesk.com/cloudhelp/2018/ENU/Revit-API/Revit_API_Developers_Guide/Revit_Geometric_Elements/Stairs_and_Railings/Creating_and_Editing_Stairs.html)

You will need to build your own node for this, which can be done by converting that c# code to Python, or by producing a zero touch node.

---

<div class="post-metadata">

**Author:** ![ceskoMU3VA](https://avatars.discourse-cdn.com/v4/letter/c/dbc845/32.png) [@ceskoMU3VA](https://forum.dynamobim.com/u/ceskoMU3VA)\
**Post date:** [December 3, 2022, 11:14pm UTC](https://forum.dynamobim.com/t/creating-stairs-in-dynamo/83724/3 "2022-12-03T23:14:43Z")

</div>

Thanks Jacob for the link and your answer. Man this is a new world to me.I am not fimilar with Python so maybe I need to start learning it to be able to do what you’re suggesting.I will try it. Thank you…

---

<div class="post-metadata">

**Author:** ![paolo.pozzoli](https://avatars.discourse-cdn.com/v4/letter/p/58956e/32.png) [@paolo.pozzoli](https://forum.dynamobim.com/u/paolo.pozzoli)\
**Post date:** [December 6, 2022, 6:14pm UTC](https://forum.dynamobim.com/t/creating-stairs-in-dynamo/83724/4 "2022-12-06T18:14:24Z")

</div>

Hi Jacob,  
I try to give a shot at converting to Python the c# code of the link you provided.  
I feel I’m close to the target but I’m getting an error when calling the function (see image below)  
 ![immagine](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/9/b/9b1a99fbd343f960e90718edb5d1963d53338b17.png)

The code is below:

```auto
# BOILERPLATE
import clr
import sys
sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')
import System
from System import Array
from System.Collections.Generic import *
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager 
from RevitServices.Transactions import TransactionManager 

clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")

import Autodesk 
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *

#from Autodesk.Revit.DB import XYZ, Line, CurveLoop, StairsEditScope, FailureProcessingResult

# FUNCTIONS
class StairsFailurePreprocessor:
	def PreprocessFailures(self, failuresAccessor):
		#Use default failure processing
		return FailureProcessingResult.Continue
		
	def CreateStairs(document, levelBottom, levelTop):
		newStairsId = None
		
		with StairsEditScope(document, "New Stairs") as newStairsScope:
			newStairsId = newStairsScope.Start(levelBottom.Id, levelTop.Id)
			
			with Transaction(document, "Add Runs and Landings to Stairs") as stairsTrans:
				stairsTrans.Start()

				# create a sketched run for the stairs
				bdryCurves = []
				riserCurves = []
				pathCurves = []
				
				# create points
				pt1 = XYZ(0, 0, 0)
				pt2 = XYZ(15, 0, 0)
				pt3 = XYZ(0, 10, 0)
				pt4 = XYZ(15, 10, 0)
				
				# define boundaries
				bdryCurves.append(Line.CreateBound(pt1, pt2))
				bdryCurves.append(Line.CreateBound(pt3, pt4))
				
				#riser curves
				riserNum = 20
				
				for i in range(0,riserNum+1):
					end0 = (pt1 + pt2) * i / riserNum
					end1 = (pt3 + pt4) * i / riserNum
					end2 = XYZ(end1.X, 10, 0)
					riserCurves.append(Line.CreateBound(end0, end2))
				
				# stairs path curves
				pathEnd0 = (pt1 + pt3) / 2
				pathEnd1 = (pt2 + pt4) / 2
				pathCurves.append(Line.CreateBound(pathEnd0, pathEnd1))
				
				newRun1 = StairsRun.CreateSketchedRun(document, newStairsId, levelBottom.Elevation, bdryCurves, riserCurves, pathCurves)
				
				# add a straight run
				locationLine = Line.CreateBound(XYZ(20, -5, newRun1.TopElevation), XYZ(35, -5, newRun1.TopElevation))
				newRun2 = StairsRun.CreateSketchedRun(document, newStairsId, locationLine, StairsRunJustification.Center)
				newRun2.ActualRunWidth = 10
				
				# add a landing between the runs
				landingLoop = CurveLoop()
				p1 = XYZ(15, 10, 0)
				p2 = XYZ(20, 10, 0)
				p3 = XYZ(20, -10, 0)
				p4 = XYZ(15, -10, 0)
				curve_1 = Line.CreateBound(p1, p2)
				curve_2 = Line.CreateBound(p2, p3)
				curve_3 = Line.CreateBound(p3, p4)
				curve_4 = Line.CreateBound(p4, p1)
				
				# append the curves to the landing loop
				landingLoop.Append(curve_1)
				landingLoop.Append(curve_2)
				landingLoop.Append(curve_3)
				landingLoop.Append(curve_4)
				
				# create the landing
				newLanding = StairsLanding.CreateSketchedLanding(document, newStairsId, landingLoop, newRun1.TopElevation)
				
				stairsTrans.Commit()
				
			# a failure preprocessor is to handle possible failures during the edit mode commitment process.
			
			newStairsScope.Commit(StairsFailurePreprocessor())
		
		return newStairsId

# INPUTS
startLevel = IN[0]
endLevel = IN[1]

# CODE
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication 
app = uiapp.Application 
uidoc = uiapp.ActiveUIDocument
	
sfp = StairsFailurePreprocessor()

# OUTPUTS
OUT = sfp.CreateStairs(doc, startLevel, endLevel)

```

Any help would be appreciated to solve the issue (and provide me and my friend Damir getting a new custom node 😉 )  
Thanks in advance

P

---

<div class="post-metadata">

**Author:** ![ceskoMU3VA](https://avatars.discourse-cdn.com/v4/letter/c/dbc845/32.png) [@ceskoMU3VA](https://forum.dynamobim.com/u/ceskoMU3VA)\
**Post date:** [December 7, 2022, 5:12am UTC](https://forum.dynamobim.com/t/creating-stairs-in-dynamo/83724/5 "2022-12-07T05:12:11Z")

</div>

Oooo there is Paolo, the Master of Python hehe…Thank you Paolo for your effort finding the answer for this script.I appreciate it very much 🙂

---

<div class="post-metadata">

**Author:** ![paolo.pozzoli](https://avatars.discourse-cdn.com/v4/letter/p/58956e/32.png) [@paolo.pozzoli](https://forum.dynamobim.com/u/paolo.pozzoli)\
**Post date:** [December 7, 2022, 7:06am UTC](https://forum.dynamobim.com/t/creating-stairs-in-dynamo/83724/6 "2022-12-07T07:06:01Z")

</div>

Ahah, if I was a true master I wouldn’t be asking for help as I’m stuck 😅  
Glad to help you in this quest. 😉

Bye  
Paolo

---

<div class="post-metadata">

**Author:** ![paolo.pozzoli](https://avatars.discourse-cdn.com/v4/letter/p/58956e/32.png) [@paolo.pozzoli](https://forum.dynamobim.com/u/paolo.pozzoli)\
**Post date:** [December 7, 2022, 5:22pm UTC](https://forum.dynamobim.com/t/creating-stairs-in-dynamo/83724/7 "2022-12-07T17:22:21Z")

</div>

Hi there,  
got some steps further with the code and debug it.  
I’m at the very end now but I can’t manage to get the FailuresPreprocessor working.  
See my updated code below (i left a few commented lines for other unsuccessful tests I did).

```auto
# BOILERPLATE
import clr
import sys
sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib')
import System
from System import Array
from System.Collections.Generic import *
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager 
from RevitServices.Transactions import TransactionManager 

clr.AddReference("RevitAPI")
clr.AddReference("RevitAPIUI")

import Autodesk 
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *

#from Autodesk.Revit.DB import XYZ, Line, CurveLoop, StairsEditScope, FailureProcessingResult

# FUNCTIONS
class StairsFailurePreprocessor:
	#def PreprocessFailures(self, failuresAccessor):
	def PreprocessFailures(failuresAccessor):
		#Use default failure processing
		return FailureProcessingResult.Continue
		
def CreateStairs(document, levelBottom, levelTop):
	newStairsId = None
	
	with StairsEditScope(document, "New Stairs") as newStairsScope:
		newStairsId = newStairsScope.Start(levelBottom.Id, levelTop.Id)
		
		with Transaction(document, "Add Runs and Landings to Stairs") as stairsTrans:
			stairsTrans.Start()

			# create a sketched run for the stairs
			bdryCurves = []
			riserCurves = []
			pathCurves = []
			
			# create points
			pt1 = XYZ(0, 0, 0)
			pt2 = XYZ(15, 0, 0)
			pt3 = XYZ(0, 10, 0)
			pt4 = XYZ(15, 10, 0)
			
			# define boundaries
			bdryCurves.append(Line.CreateBound(pt1, pt2))
			bdryCurves.append(Line.CreateBound(pt3, pt4))
			
			#riser curves
			riserNum = 20
			
			for i in range(0,riserNum+1):
				end0 = (pt1 + pt2) * i / riserNum
				end1 = (pt3 + pt4) * i / riserNum
				end2 = XYZ(end1.X, 10, 0)
				riserCurves.append(Line.CreateBound(end0, end2))
			
			# stairs path curves
			pathEnd0 = (pt1 + pt3) / 2
			pathEnd1 = (pt2 + pt4) / 2
			pathCurves.append(Line.CreateBound(pathEnd0, pathEnd1))
			
			newRun1 = Autodesk.Revit.DB.Architecture.StairsRun.CreateSketchedRun(document, newStairsId, levelBottom.Elevation, bdryCurves, riserCurves, pathCurves)
			
				# add a straight run
			locationLine = Line.CreateBound(XYZ(20, -5, newRun1.TopElevation), XYZ(35, -5, newRun1.TopElevation))
			newRun2 = Autodesk.Revit.DB.Architecture.StairsRun.CreateStraightRun(document, newStairsId, locationLine, Autodesk.Revit.DB.Architecture.StairsRunJustification.Center)
			newRun2.ActualRunWidth = 10
			
			# add a landing between the runs
			landingLoop = CurveLoop()
			p1 = XYZ(15, 10, 0)
			p2 = XYZ(20, 10, 0)
			p3 = XYZ(20, -10, 0)
			p4 = XYZ(15, -10, 0)
			curve_1 = Line.CreateBound(p1, p2)
			curve_2 = Line.CreateBound(p2, p3)
			curve_3 = Line.CreateBound(p3, p4)
			curve_4 = Line.CreateBound(p4, p1)
			
			# append the curves to the landing loop
			landingLoop.Append(curve_1)
			landingLoop.Append(curve_2)
			landingLoop.Append(curve_3)
			landingLoop.Append(curve_4)
			
			# create the landing
			newLanding = Autodesk.Revit.DB.Architecture.StairsLanding.CreateSketchedLanding(document, newStairsId, landingLoop, newRun1.TopElevation)
			
			stairsTrans.Commit()
			
		# a failure preprocessor is to handle possible failures during the edit mode commitment process.
		
		sfp = StairsFailurePreprocessor()
		newStairsScope.Commit(sfp.PreprocessFailures())
		
		#newStairsScope.Commit(sfp)
		#newStairsScope.Commit(StairsFailurePreprocessor())
	
	return [newStairsId, doc.GetElement(newStairsId)]

# INPUTS
startLevel = UnwrapElement(IN[0])
endLevel = UnwrapElement(IN[1])

# CODE
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application
uidoc = uiapp.ActiveUIDocument

# OUTPUTS
OUT = CreateStairs(doc, startLevel, endLevel)

```

The output is the following:

 ![immagine](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/d/9/d936c71c755b7e4626802f3aad4d78ef8b267ff1.png)

If I remove the line `newStairsScope.Commit(sfp.PreprocessFailures())` the code seems to go fine (I get an ElementId) but no results is showing in Revit and such ElementId is not searchable in Revit either.  
See output below:

 ![immagine](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/9/e/9ea25731891708cbd0b6e485321a6c05ab636d43.png)  
And Revit warning if I try to access the element by its Id:  
 ![immagine](https://us1.discourse-cdn.com/flex022/uploads/dynamobim/original/3X/b/6/b68dc464c138168de113f3f4c79d3a4d90acc249.png)

Thanks again for your help.

Paolo

---

<div class="post-metadata">

**Author:** ![ceskoMU3VA](https://avatars.discourse-cdn.com/v4/letter/c/dbc845/32.png) [@ceskoMU3VA](https://forum.dynamobim.com/u/ceskoMU3VA)\
**Post date:** [December 7, 2022, 6:19pm UTC](https://forum.dynamobim.com/t/creating-stairs-in-dynamo/83724/8 "2022-12-07T18:19:21Z")

</div>

Hehe man in my eyes you’re the master.Thank you again :)…
