AgentStack
SKILL verified MIT Self-run

Scripting Reference

skill-amanbh997-claude-skills-for-computational-designers-scripting-reference · by Amanbh997

Python for Rhino and Grasshopper (RhinoCommon, rhinoscriptsyntax, ghpythonlib), C# for Grasshopper components, Python for Revit (pyRevit, RevitPythonShell), JavaScript for web 3D (Three.js), and code patterns for AEC computational design

No reviews yet
0 installs
16 views
0.0% view→install

Install

$ agentstack add skill-amanbh997-claude-skills-for-computational-designers-scripting-reference

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No 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.

Are you the author of Scripting Reference? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

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 .gh file is a binary blob. A .py file 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_Goo wrappers

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.

Versions

  • v0.1.0 Imported from the upstream source.