Install
$ agentstack add skill-amanbh997-claude-skills-for-computational-designers-scripting-reference ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Scripting Reference for AEC Computational Design
1. Scripting in AEC Computational Design
Why Code Beyond Visual Programming
Visual programming environments like Grasshopper, Dynamo, and Marionette have democratized computational design for architects and engineers. But they hit hard walls in practice:
- Complexity ceiling: Definitions beyond ~200 nodes become unreadable spaghetti, impossible to maintain or hand off.
- Control flow limitations: Try writing a recursive space-partitioning algorithm in pure Grasshopper. You cannot. Loops require plugins (Anemone, Hoopsnake) that add fragility.
- Performance: Visual node evaluation carries overhead. A Python loop processing 50,000 mesh vertices runs 5-20x faster than equivalent wired-up components.
- Data management: Parsing CSV, calling REST APIs, reading databases, writing Excel reports — all trivial in code, painful or impossible in visual programming.
- Version control: A
.ghfile is a binary blob. A.pyfile is diffable, mergeable, reviewable text. - Reusability: Functions, classes, modules, packages — code is composable at every scale.
- Testing: You can unit-test a Python function. You cannot unit-test a Grasshopper cluster.
The Scripting Spectrum
| Level | Tool | Difficulty | Use Case | |-------|------|------------|----------| | Entry | rhinoscriptsyntax (rs) | Easy | Quick automation, batch ops, simple geometry | | Intermediate | RhinoCommon (Python) | Medium | Complex geometry, intersections, analysis | | Intermediate | GhPython | Medium | Custom GH components, data tree manipulation | | Advanced | C# in GH | Hard | Performance-critical components, custom .gha | | Advanced | pyRevit / Dynamo Python | Medium | Revit automation, BIM scripting | | Advanced | Full .NET (C#/F#) | Hard | Production plugins, commercial tools | | Specialist | Three.js / WebGL | Medium | Web viewers, interactive presentations |
Choosing the Right Language
Python — Use when:
- Rapid prototyping and iteration matter most
- You need quick automation scripts (Rhino or Revit)
- Working with data (CSV, JSON, API calls)
- Algorithmic design exploration in Grasshopper
- Team includes non-programmers who need to read the code
C# — Use when:
- Performance is paramount (10-100x faster than Python for tight loops)
- Building distributable Grasshopper plugins (.gha)
- You need strong typing to catch errors at compile time
- Integrating with .NET ecosystem libraries
- Building production-grade Revit add-ins
JavaScript/TypeScript — Use when:
- Building web-based viewers and dashboards
- Client-facing model presentations
- Collaborative design platforms
- AR/VR experiences via WebXR
- Integration with Speckle, IFC.js, or custom APIs
Python vs. C# for AEC — A Practical Comparison
Feature Python C#
─────────────────────────────────────────────────────────────
Typing Dynamic Static
Speed 1x (baseline) 10-100x
REPL Yes (interactive) No (compile required)
GH Component GhPython node Scripting / Visual Studio
Learning curve Gentle Steeper
Error detection Runtime Compile-time
Deployment .py files .gha / .dll
External libraries pip (huge ecosystem) NuGet (large ecosystem)
Data science Excellent (numpy, pandas) Good (MathNet, ML.NET)
String handling Superior Adequate
Memory management Automatic (GC) Automatic (GC)
Multithreading GIL limitation Full parallel support
2. Python for Rhino (rhinoscriptsyntax)
The rhinoscriptsyntax module (imported as rs) wraps RhinoCommon in friendly, high-level functions. It is the fastest way to automate Rhino.
Module Overview
import rhinoscriptsyntax as rs
Object Creation Patterns
# Points
pt = rs.AddPoint(0, 0, 0)
pt2 = rs.AddPoint([10, 5, 3])
# Lines
line = rs.AddLine([0,0,0], [10,0,0])
line2 = rs.AddLine(rs.GetPoint("Start"), rs.GetPoint("End"))
# Polylines
pts = [[0,0,0],[5,0,0],[5,5,0],[0,5,0],[0,0,0]]
pline = rs.AddPolyline(pts)
# Curves
crv = rs.AddCurve(pts, degree=3) # NURBS curve
interp = rs.AddInterpCurve(pts) # interpolated through points
# Circles and Arcs
circle = rs.AddCircle([0,0,0], 5.0)
arc = rs.AddArc3Pt([0,0,0], [10,0,0], [5,5,0])
ellipse = rs.AddEllipse([0,0,0], 10, 5)
# Rectangles
rect = rs.AddRectangle([0,0,0], 10, 5)
# Surfaces
srf = rs.AddSrfPt([[0,0,0],[10,0,0],[10,10,0],[0,10,0]])
pipe = rs.AddPipe(crv, 0, 1.0)
loft = rs.AddLoftSrf([crv1, crv2])
extrusion = rs.ExtrudeCurveStraight(crv, [0,0,0], [0,0,5])
revolve = rs.AddRevSrf(profile_crv, axis_line)
# Meshes
mesh = rs.AddMesh([[0,0,0],[1,0,0],[1,1,0],[0,1,0]], [[0,1,2,3]])
# Solids
box = rs.AddBox([[0,0,0],[10,0,0],[10,10,0],[0,10,0],
[0,0,5],[10,0,5],[10,10,5],[0,10,5]])
sphere = rs.AddSphere([0,0,0], 5.0)
cylinder = rs.AddCylinder([0,0,0], [0,0,10], 3.0)
cone = rs.AddCone([0,0,0], [0,0,10], 5.0)
# Text and annotations
text = rs.AddText("Building A", [0,0,0], height=2.0)
dot = rs.AddTextDot("Label", [5,5,0])
leader = rs.AddLeader([[0,0,0],[5,5,0],[10,5,0]])
dim = rs.AddLinearDimension([0,0,0], [10,0,0], [5,2,0])
Object Query Patterns
# Selection
objs = rs.GetObjects("Select objects")
obj = rs.GetObject("Select one curve", rs.filter.curve)
pt = rs.GetPoint("Pick a point")
# By layer
layer_objs = rs.ObjectsByLayer("Walls")
# By type
all_curves = rs.ObjectsByType(rs.filter.curve)
all_surfs = rs.ObjectsByType(rs.filter.surface)
all_meshes = rs.ObjectsByType(rs.filter.mesh)
# By group
group_objs = rs.ObjectsByGroup("FloorPlan")
# Properties
obj_type = rs.ObjectType(obj) # integer type code
obj_name = rs.ObjectName(obj) # user-assigned name
obj_layer = rs.ObjectLayer(obj) # layer name
obj_color = rs.ObjectColor(obj) # (R,G,B) tuple
Transformation Methods
# Move
rs.MoveObject(obj, [10, 0, 0])
rs.MoveObjects(objs, [0, 5, 0])
# Rotate (angle in degrees)
rs.RotateObject(obj, [0,0,0], 45)
rs.RotateObject(obj, [0,0,0], 90, axis=[0,0,1])
# Scale
rs.ScaleObject(obj, [0,0,0], [2, 2, 2]) # uniform
rs.ScaleObject(obj, [0,0,0], [1, 1, 3]) # non-uniform
# Mirror
rs.MirrorObject(obj, [0,0,0], [0,1,0])
# Copy
copy = rs.CopyObject(obj, [10, 0, 0])
copies = rs.CopyObjects(objs, [5, 5, 0])
# Orient
rs.OrientObject(obj, [ref1, ref2], [target1, target2])
# Array
rs.ArrayLinear(obj, count=5, offset=[10,0,0])
rs.ArrayPolar(obj, count=6, angle=360, center=[0,0,0])
Layer Management
# Create layers
rs.AddLayer("Architecture")
rs.AddLayer("Walls", color=(200, 50, 50), parent="Architecture")
rs.AddLayer("Columns", color=(50, 50, 200), parent="Architecture")
# Layer properties
rs.CurrentLayer("Walls")
rs.LayerColor("Walls", (255, 0, 0))
rs.LayerVisible("Furniture", False)
rs.LayerLocked("Base Plan", True)
rs.LayerPrintWidth("Walls", 0.5)
# Bulk operations
all_layers = rs.LayerNames()
rs.PurgeLayer("Temp Construction")
# Move objects between layers
for obj in rs.ObjectsByLayer("Old Layer"):
rs.ObjectLayer(obj, "New Layer")
User Interaction
# Input
point = rs.GetPoint("Click a point")
string = rs.GetString("Enter building name", "Default")
number = rs.GetReal("Enter floor height", 3.0, 2.5, 6.0)
integer = rs.GetInteger("Number of floors", 5, 1, 100)
boolean = rs.GetBoolean("Options", ["Visible","Yes","No"], [True])
# Output
rs.MessageBox("Operation complete!")
print("Processed {} objects".format(len(objs)))
# Selection
rs.SelectObject(obj)
rs.SelectObjects(objs)
rs.UnselectAllObjects()
Geometry Analysis
length = rs.CurveLength(crv)
area = rs.SurfaceArea(srf) # returns [area, error]
volume = rs.SurfaceVolume(closed_brep) # returns [volume, error]
centroid = rs.SurfaceAreaCentroid(srf) # returns [point, error]
dist = rs.Distance([0,0,0], [10,10,0])
angle = rs.Angle([0,0,0], [10,10,0])
bbox = rs.BoundingBox(obj) # 8 corner points
is_closed = rs.IsCurveClosed(crv)
is_planar = rs.IsCurvePlanar(crv)
degree = rs.CurveDegree(crv)
domain = rs.CurveDomain(crv)
Common Recipes
# Batch rename objects by layer
for obj in rs.AllObjects():
layer = rs.ObjectLayer(obj)
idx = rs.ObjectsByLayer(layer).index(obj)
rs.ObjectName(obj, "{}_{}".format(layer, idx))
# Export each layer to separate file
for layer in rs.LayerNames():
objs = rs.ObjectsByLayer(layer)
if objs:
rs.SelectObjects(objs)
rs.Command("_-Export \"{}.3dm\" _Enter".format(layer))
rs.UnselectAllObjects()
# Generate grid of points
for x in range(0, 100, 10):
for y in range(0, 80, 10):
rs.AddPoint(x, y, 0)
# Offset all curves on a layer inward
for crv in rs.ObjectsByLayer("Site Boundary"):
offsets = rs.OffsetCurve(crv, rs.CurveAreaCentroid(crv)[0], 3.0)
3. Python for Rhino (RhinoCommon)
RhinoCommon is the full .NET geometry library. It gives precise control over every geometric operation.
Namespace Structure
import Rhino
import Rhino.Geometry as rg
import Rhino.DocObjects as rd
import Rhino.Input as ri
import Rhino.RhinoDoc as doc
# Key classes in Rhino.Geometry:
# Point3d, Vector3d, Plane, Line, Arc, Circle, Polyline,
# NurbsCurve, PolylineCurve, BrepFace, BrepEdge,
# Surface, NurbsSurface, Brep, Mesh, Transform,
# BoundingBox, Interval, Point2d
Point3d and Vector3d Operations
# Creation
p1 = rg.Point3d(0, 0, 0)
p2 = rg.Point3d(10, 5, 3)
v1 = rg.Vector3d(1, 0, 0)
v2 = rg.Vector3d(0, 1, 0)
# Arithmetic
p3 = p1 + v1 # Point + Vector = Point
v3 = p2 - p1 # Point - Point = Vector
v4 = v1 + v2 # Vector + Vector = Vector
v5 = v1 * 5.0 # scalar multiplication
v6 = v1 / 2.0 # scalar division
# Vector operations
dot = v1 * v2 # dot product (0 = perpendicular)
cross = rg.Vector3d.CrossProduct(v1, v2) # cross product
v1.Unitize() # normalize in-place
unit = v1 / v1.Length # manual unitize
length = v1.Length
angle = rg.Vector3d.VectorAngle(v1, v2) # radians
# Distance
dist = p1.DistanceTo(p2)
# Static members
origin = rg.Point3d.Origin # (0,0,0)
xaxis = rg.Vector3d.XAxis # (1,0,0)
yaxis = rg.Vector3d.YAxis # (0,1,0)
zaxis = rg.Vector3d.ZAxis # (0,0,1)
Curve Creation
# Line
ln = rg.Line(p1, p2)
ln_crv = rg.LineCurve(ln)
# Circle
circle = rg.Circle(rg.Plane.WorldXY, 5.0)
circle_crv = circle.ToNurbsCurve()
# Arc
arc = rg.Arc(p1, p2, p3) # through 3 points
arc_crv = arc.ToNurbsCurve()
# Polyline
pline = rg.Polyline([rg.Point3d(x, 0, 0) for x in range(11)])
pline_crv = pline.ToPolylineCurve()
# NurbsCurve by control points
pts = [rg.Point3d(i*10, (i%3)*5, 0) for i in range(6)]
nc = rg.NurbsCurve.Create(False, 3, pts) # open, degree 3
# Interpolated curve
interp = rg.Curve.CreateInterpolatedCurve(pts, 3)
# Fillet / Chamfer
filleted = rg.Curve.CreateFilletCurves(crv1, t1, crv2, t2, radius,
True, True, True, 0.001, 0.001)
# Offset
offsets = crv.Offset(rg.Plane.WorldXY, 5.0, 0.01,
rg.CurveOffsetCornerStyle.Sharp)
# Boolean on closed planar curves
union = rg.Curve.CreateBooleanUnion(curves, 0.001)
diff = rg.Curve.CreateBooleanDifference(crv1, crv2, 0.001)
inter = rg.Curve.CreateBooleanIntersection(crv1, crv2, 0.001)
Surface and Brep Creation
# Planar surface from closed curve
breps = rg.Brep.CreatePlanarBreps(closed_crv, 0.001)
# Extrusion
ext = rg.Extrusion.Create(profile_crv, height, cap=True)
ext_brep = ext.ToBrep()
# Loft
loft = rg.Brep.CreateFromLoft(curves, rg.Point3d.Unset, rg.Point3d.Unset,
rg.LoftType.Normal, False)
# Sweep
sweep1 = rg.Brep.CreateFromSweep(rail, section, closed=False, tol=0.001)
# NurbsSurface from point grid
srf = rg.NurbsSurface.CreateFromPoints(pts_2d_list, u_count, v_count,
u_degree, v_degree)
# Boolean operations
union = rg.Brep.CreateBooleanUnion(breps, 0.001)
diff = rg.Brep.CreateBooleanDifference(brep1, brep2, 0.001)
inter = rg.Brep.CreateBooleanIntersection(brep1, brep2, 0.001)
# Planar surface from corner points
srf = rg.NurbsSurface.CreateFromCorners(p1, p2, p3, p4)
Mesh Creation
mesh = rg.Mesh()
mesh.Vertices.Add(0, 0, 0)
mesh.Vertices.Add(10, 0, 0)
mesh.Vertices.Add(10, 10, 0)
mesh.Vertices.Add(0, 10, 0)
mesh.Faces.AddFace(0, 1, 2, 3) # quad
mesh.Normals.ComputeNormals()
mesh.Compact()
# From Brep
meshes = rg.Mesh.CreateFromBrep(brep, rg.MeshingParameters.Default)
# Mesh operations
mesh.Weld(Math.PI) # weld vertices
mesh.UnifyNormals() # consistent normals
mesh.RebuildNormals()
vol = rg.VolumeMassProperties.Compute(mesh)
area = rg.AreaMassProperties.Compute(mesh)
Intersection Methods
# Curve-Curve
events = rg.Intersect.Intersection.CurveCurve(crv1, crv2, 0.001, 0.001)
for e in events:
pt = e.PointA
param_a = e.ParameterA
param_b = e.ParameterB
is_overlap = e.IsOverlap
# Curve-Surface
events = rg.Intersect.Intersection.CurveSurface(crv, srf, 0.001, 0.001)
for e in events:
pt = e.PointA
# Brep-Brep
result, curves, pts = rg.Intersect.Intersection.BrepBrep(brep1, brep2, 0.001)
# Mesh-Ray
ray = rg.Ray3d(origin_pt, direction_vec)
t = rg.Intersect.Intersection.MeshRay(mesh, ray)
if t >= 0:
hit_pt = ray.PointAt(t)
# Line-Plane
result, t = rg.Intersect.Intersection.LinePlane(line, plane)
if result:
hit = line.PointAt(t)
# Brep-Plane (section)
result, curves, pts = rg.Intersect.Intersection.BrepPlane(brep, plane, 0.001)
Transform Class
# Translation
xform = rg.Transform.Translation(rg.Vector3d(10, 0, 0))
# Rotation (angle in radians)
xform = rg.Transform.Rotation(Math.PI / 4, rg.Vector3d.ZAxis, rg.Point3d.Origin)
# Scale
xform = rg.Transform.Scale(rg.Point3d.Origin, 2.0) # uniform
xform = rg.Transform.Scale(rg.Plane.WorldXY, 2.0, 1.0, 3.0) # non-uniform
# PlaneToPlane
xform = rg.Transform.PlaneToPlane(source_plane, target_plane)
# Mirror
xform = rg.Transform.Mirror(rg.Plane.WorldXY)
# Apply
obj_copy = obj.Duplicate()
obj_copy.Transform(xform)
# Combine transforms
combined = xform1 * xform2 # xform2 applied first
BoundingBox, Plane, Interval
# BoundingBox
bbox = obj.GetBoundingBox(True)
min_pt = bbox.Min
max_pt = bbox.Max
center = bbox.Center
diagonal = bbox.Diagonal
is_valid = bbox.IsValid
# Plane
plane = rg.Plane(origin, normal)
plane = rg.Plane(origin, x_axis, y_axis)
plane = rg.Plane.WorldXY
closest = plane.ClosestPoint(test_pt)
# Interval (parameter domain)
interval = rg.Interval(0.0, 1.0)
mid = interval.Mid
length = interval.Length
t = interval.ParameterAt(0.5) # normalized
4. GhPython (Python in Grasshopper)
Component Setup
In the GhPython component (or Script component in GH2):
- Inputs: Right-click each input to set Access (Item / List / Tree) and Type Hint (Point3d, Curve, float, str, etc.)
- Outputs: Name outputs at the bottom of the component
- Type hints are critical: without them, all inputs arrive as
IGH_Goowrappers
Data Tree Handling
import Grasshopper as gh
from Grasshopper import DataTree
from Grasshopper.Kernel.Data import GH_Path
# Create a data tree
tree = DataTree[object]()
for i in range(5):
path = GH_Path(i)
for j in range(10):
tree.Add(rg.Point3d(i*10, j*10, 0), path)
# Iterate a data tree
for i in range(tree.BranchCount):
path = tree.Path(i)
branch = tree.Branch(i)
for item in branch:
print(item)
# Flatten
flat = tree.AllData()
# Graft (each item in its own branch)
graft
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [Amanbh997](https://github.com/Amanbh997)
- **Source:** [Amanbh997/Claude-skills-for-Computational-Designers](https://github.com/Amanbh997/Claude-skills-for-Computational-Designers)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.