AI Blocks › Design things people love
Rhino modeling script writer
Share your Rhino version, task and source script. Choose the right API and guard each change. Get code and steps to check it.
Share your Rhino task, version and model details. Get a script with steps to check it.
Free · No account · MIT licence · Made by github · Tested · Updated 28 Oct 2026
What you get
What goes in
- Your Rhino version
- What you want the script to do
- Your document units and the geometry it works on
- Your existing script, if you have one (optional)
Before you start
- Rhino 7 or later, with Rhino 8 best. The skill is written for Rhino 8 (one Script Editor for Python 3, VB and C#). On Rhino 7, use the older Python and VBScript editors and expect some features to differ.
- Rhino's Script Editor to run the result
What comes out
- Script choice: Which type fits your task: Python, VBScript, C# or a command macro, and why.
- Script code: The full script, with checks on picked objects and your document's tolerance.
- Redraw and undo handling: Code that pauses redraw, groups changes into one undo step, and restores the view if something fails.
- How to run it: Steps to open the Script Editor or run the file by name, or set up a toolbar button.
- Checks to perform: What to look for in Rhino to confirm the script did the right thing.
- Verification limits: A plain note that the script was not run in Rhino, and what that leaves unchecked.
Is it for you?
Use it when
- You want a new Rhino script for a modeling task, such as editing many objects at once.
- A script you have fails, freezes Rhino, or undoes only one object at a time.
- You need to share a script with a teammate or run it when Rhino starts.
Skip it when
- You only need a fixed run of commands with no variables or loops: use a Rhino command macro instead.
- You work in other CAD software, not Rhino: use that program's own scripting help.
- You need proof the script runs in Rhino: run it yourself, because your AI cannot test it for you.
Fill it in
Add what this task works from, then copy the request.
- The Rhino version, modeling task, document units, input geometry and any existing script.
Run it
Download the complete instructions and supporting files. Add them to Claude, ChatGPT or Gemini once, then ask for it by name in any chat. Pasting the instructions into a chat works too.
Before and after this skill
Choose the steps you need. Bring your own material when you have it.
Before
Bring the material listed under Fill it in.
After
- Small usability test planner
Design it
Details
From github. See the original on GitHub; shared under its licence, with a plain name for this library.
What it does
Share your Rhino version, task and source script. Choose the right API and guard each change. Get code and steps to check it.
What goes in and out
You give it
- The Rhino version, modeling task, document units, input geometry and any existing script.
You get
- A script file in the language that fits your task, ready to paste into Rhino's Script Editor.
- The exact way to run it, by Script Editor steps or a run command.
- A short list of checks to do in Rhino to confirm it worked.
- A plain note on what was not tested, since your AI cannot run Rhino.
Use it when
- You want a new Rhino script for a modeling task, such as editing many objects at once.
- A script you have fails, freezes Rhino, or undoes only one object at a time.
- You need to share a script with a teammate or run it when Rhino starts.
- Not for a fixed list of commands with no variables (use a command macro) or for non-Rhino CAD work.
More for Design things people love
- Brand identity system planner
- Everyday usability reviewer
- Mobile app designer
- Template layout alternatives planner
Every design things people love skill
How the task works
- Choose the scripting surface. Match task complexity and the installed Rhino runtime to Python, legacy VBScript, C# or a macro.
- Handle document behavior. Use document tolerances, validate selections and group changes with redraw and undo cleanup.
- Explain running and testing. Provide loading instructions and expected checks without claiming a Rhino runtime was exercised.
Full instructions
- Open Claude, ChatGPT or Gemini and paste in the skill text.
- Tell your AI your Rhino version, your task, your document units and what geometry the script touches.
- Paste your current script if you have one.
- Save a copy of your Rhino file first, since the script changes objects in it. Then copy the code into Rhino's Script Editor and run it with the steps your AI gives you.
- Do the listed checks in Rhino, then send any error text back to your AI to fix.
- Next, once it runs, save the script in a folder listed under Options, Files, Search paths. Then add a toolbar button or alias with the macro ! _-RunPythonScript "MyScript.py" (Python), or add the file to the Startup list under Tools, Options to load it every session.
Full instruction file
Rhino 3D Scripting Skill
Write production-quality scripts for Rhinoceros 3D. Covers the three scripting surfaces (RhinoScript/VBScript, RhinoPython, direct RhinoCommon .NET) and the Rhino 8+ Script Editor.
Before you start
Use the material below to do this job. If facts or tool access are missing, explain what you can finish and what must wait.
What you need (use your own material or the linked skill):
- Your question (yours): the decision or problem, and what a good outcome looks like.
- A codebase (yours): a project's code, in a folder or repo the AI can open.
How to start:
- Look first. Use what they've already attached, pasted or put in their about-me note. In a coding assistant with file access, look in the project too for these by name.
- Check what's missing. Look for your question, a codebase. They can attach files, paste the details, or share a file path your assistant can read. Ask only for missing facts that change the result. If they ask you to start with what they have, complete the parts you can and mark the gaps.
- Do the job. Follow the skill below with the facts and tools you have. Mark each gap with
MISSING:where it belongs and never invent a fact to fill it.
When to Use This Skill
- User asks to write, edit, or debug a
.rvb,.vbs, or.pyRhino script - User wants a Rhino command macro or wants to automate a sequence of Rhino commands
- User wants to manipulate geometry, layers, blocks, materials, viewports, or annotations from code
- User mentions
rhinoscriptsyntax,scriptcontext,RhinoCommon,Rhino.Geometry,RhinoDoc, or the Script Editor - User wants to pick objects, prompt for input, or build a small UI inside Rhino
- User asks how to load, run, or distribute a script (startup scripts, aliases, toolbar buttons)
Choosing a Scripting Surface
Pick the surface based on the task, not preference. Recommend Python by default for new work.
| Surface | When to choose | File ext |
|---|---|---|
RhinoPython (rhinoscriptsyntax + RhinoCommon) |
Default for new scripts. Best ecosystem, readable, full RhinoCommon access. | .py |
| RhinoScript (VBScript) | Maintaining legacy .rvb/.vbs files; integrating with VBA/COM. |
.rvb, .vbs |
| RhinoCommon (C#/.NET) via Script Editor | Performance-critical loops, complex geometry, leveraging .NET libraries. | .cs |
| Command macro | Pure sequence of existing Rhino commands; no logic. | toolbar/alias |
A macro is not a script — it is a string of command-line input (e.g. ! _-Line 0,0,0 10,0,0 _Enter). Use a script the moment you need a variable, loop, or conditional.
Prerequisites
- Rhino 7 or later (Rhino 8 strongly recommended — unified Script Editor supports Python 3, VB, and C# in one window).
- Script Editor: type
_ScriptEditor(Rhino 8) or_EditPythonScript/_EditScript(older). - Run a saved file from the command line with
_-RunPythonScriptor_LoadScript+_RunScript.
Core Patterns
Python: minimal scaffold
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
def main():
obj_id = rs.GetObject("Select a curve", filter=rs.filter.curve, preselect=True)
if not obj_id:
return
length = rs.CurveLength(obj_id)
print("Length: {0:.4f}".format(length))
if __name__ == "__main__":
main()
Python: working with RhinoCommon directly
import Rhino
import scriptcontext as sc
doc = sc.doc # Rhino.RhinoDoc.ActiveDoc
tol = doc.ModelAbsoluteTolerance
circle = Rhino.Geometry.Circle(Rhino.Geometry.Point3d(0, 0, 0), 5.0)
curve_id = doc.Objects.AddCircle(circle)
doc.Views.Redraw()
VBScript: minimal scaffold
Option Explicit
Call Main()
Sub Main()
Dim strObject
strObject = Rhino.GetObject("Select a curve", 4) ' 4 = curve filter
If IsNull(strObject) Then Exit Sub
Rhino.Print "Length: " & Rhino.CurveLength(strObject)
End Sub
Picking objects with a custom filter (Python, RhinoCommon)
import Rhino
import scriptcontext as sc
go = Rhino.Input.Custom.GetObject()
go.SetCommandPrompt("Select breps")
go.GeometryFilter = Rhino.DocObjects.ObjectType.Brep
go.SubObjectSelect = False
go.GetMultiple(1, 0)
if go.CommandResult() != Rhino.Commands.Result.Success:
pass
else:
ids = [go.Object(i).ObjectId for i in range(go.ObjectCount)]
Step-by-Step Workflows
Bulk-modify many objects fast
- Disable redraw:
rs.EnableRedraw(False). - Wrap mutations in a single undo record:
undo = doc.BeginUndoRecord("My Op")…doc.EndUndoRecord(undo). - Use RhinoCommon directly inside the loop (skip
rhinoscriptsyntaxoverhead). - Re-enable redraw and call
doc.Views.Redraw()in atry/finallyso a crash never leaves the viewport frozen.
Distribute a script to a teammate
- Save the
.py/.rvbsomewhere on disk. - Add the folder to
Options → Files → Search pathsso Rhino can find it by name. - Create a toolbar button or alias whose macro is:
- Python:
! _-RunPythonScript "MyScript.py" - RhinoScript:
! _-LoadScript "MyScript.rvb" _-RunScript MySubName
- Python:
- The leading
!cancels any running command;-runs the command in script (no-dialog) mode.
Run code at Rhino startup
- Place a
.rvb/.pyin a search path. Tools → Options → RhinoScript(orPython) → add to Startup list. The file executes once per session.
Gotchas
rhinoscriptsyntaxreturns GUIDs, RhinoCommon returns objects. Mixing them is fine, butdoc.Objects.Find(guid)is the bridge from ars.*id to aRhinoObject.- Coordinates differ by surface. Python uses
(x, y, z)tuples orRhino.Geometry.Point3d; VBScript uses 3-elementArray(x, y, z). Never pass a Python list to a VBScript helper through COM. Option Explicitis off by default in VBScript. Typos silently create new variables. Always addOption Explicitat the top of.rvbfiles.- VBScript has no block scope. All
Dims inside aSubare hoisted to the top of the procedure. Loop counters leak. Nothing,Empty, andNullare different in VBScript. UseIsNullforRhino.GetObjectfailure,IsEmptyfor uninitializedVariant,Is Nothingfor object refs.- Parentheses change calling semantics in VBScript.
Call Foo(a, b)andFoo a, bare valid;Foo(a, b)(noCall, with parens) is not a call to a Sub — it’s a syntax error for multi-arg subs and a forcedByValfor single-arg. - Tolerance is per-document. Always read
doc.ModelAbsoluteTolerancerather than hardcoding0.001; users work in mm, m, inches, etc. - Long loops should poll
Rhino.RhinoApp.EscapeKeyPressedso the user can cancel. Otherwise Rhino appears frozen. - GUID strings vs
System.Guid.rhinoscriptsyntaxaccepts either; RhinoCommon wantsSystem.Guid. Convert withSystem.Guid(str_id)if needed. - Don’t call
doc.Views.Redraw()inside a tight loop. Toggle redraw once outside the loop. .rvbis just.vbsrenamed with a Rhino-specific extension so Rhino’sLoadScriptrecognizes it. Same VBScript engine.Rhino.RhinoApp.IsHeadlessmay not exist on older Rhino 8 builds. Usegetattr(Rhino.RhinoApp, "IsHeadless", None)and check forNonebefore using. Fall back to a heuristic (e.g.sc.doc.Views.Count == 0) or assume GUI present.RhinoMathis atRhino.RhinoMath, notRhino.DocObjects.RhinoMath. AccessingRhino.DocObjects.RhinoMathraisesAttributeError.doc.Objects.AddBrep()returnsSystem.Guid.Emptyon failure. In Rhino 8 CPython theSystemnamespace may not be directly importable; check the return value as a string:str(obj_id) == "00000000-0000-0000-0000-000000000000".rhinoscriptsyntaxhas no type stubs. Static analysers (Pylance/Pyright) flagimport rhinoscriptsyntax as rsas unresolvable. Suppress with# type: ignoreon the import line; the module is always available at Rhino runtime.- Never name a script after a Python standard-library module (e.g.
random.py,math.py,os.py). IronPython 2.7 (_-RunPythonScript) resolves the script directory before stdlib, so anyimport randominside the stdlib (e.g.tempfileimportsrandominternally) will find your file instead and fail withCannot import name <X>. CPython 3 (rhinocode) is unaffected because it resolves stdlib first. Rename the script or avoid importing modules that pull in the shadowed name. - Em dashes and other non-ASCII characters silently break
_-RunPythonScript(IronPython 2.7).rhinocode scriptuses CPython 3 (UTF-8 by default) so the same file works there, making the failure non-obvious. IronPython 2.7 raisesSyntaxError: Non-ASCII character '\xe2'at the first offending byte. The most common culprit is the em dash (the long dash, U+2014), which many editors type in place of two hyphens. Add# -*- coding: utf-8 -*-as line 1 of every script that must run under both runtimes, and replace typographic characters with ASCII equivalents: em dash (U+2014) becomes two hyphens--, arrow becomes->, multiplication sign becomesx.
Troubleshooting
| Symptom | Fix |
|---|---|
rs.GetObject returns None immediately |
The user pressed Escape, or your filter excludes everything. Re-check rs.filter.* flags. |
| “Unable to find script” when running by name | The folder isn’t in Options → Files → Search paths. |
VBScript Type mismatch on coordinates |
You passed a 2-element array. Rhino requires 3-element Array(x, y, z). |
Python ImportError: No module named Rhino |
You’re running CPython outside Rhino. RhinoCommon is only available in Rhino’s embedded Python (or via rhino3dm for read-only file work). |
| Created geometry doesn’t appear | You forgot doc.Views.Redraw(), or rs.EnableRedraw(False) was never re-enabled. |
| Undo undoes only the last object of a batch | Wrap the batch in BeginUndoRecord / EndUndoRecord. |
| Script works alone but fails as a startup script | Startup runs before any document is open — return early or skip document-dependent work when sc.doc is None. |
rs.Command("...") returns False |
The macro string is malformed. Prefix with ! and -, end every prompt with _Enter or a value. |
AttributeError: type object 'RhinoApp' has no attribute 'IsHeadless' |
Property added in a later Rhino 8 build. Use getattr(Rhino.RhinoApp, "IsHeadless", None) and guard against None. |
rhinocode script ignores arguments after the script path |
rhinocode concatenates extra tokens onto the file URI. Pass data via a temp file or a Rhino dialog instead. See references/macros-and-loading.md. |
Cannot import name <X> inside stdlib (e.g. tempfile, os) when using _-RunPythonScript |
Script filename shadows a stdlib module (e.g. random.py shadows random). IronPython 2.7 searches the script directory before stdlib. Rename the script, or remove the import that pulls in the shadowed module and replace it with a direct alternative (e.g. read %TEMP% via os.environ instead of import tempfile). |
SyntaxError: Non-ASCII character '\xe2' ... but no encoding declared |
IronPython 2.7 (_-RunPythonScript) hit an em dash or similar character. Add # -*- coding: utf-8 -*- as line 1, or replace the character: em dash (U+2014) becomes two hyphens --, arrow becomes ->. The same file runs fine under rhinocode (CPython 3), which hides the problem. |
After this
When you've handed it back, suggest what they could do next in one short question. It's a suggestion: if they're done, that's fine. Offer these, and say they can type their own:
- The Small usability test planner. If they pick one and that skill is added here, carry straight on with what you just made. If not, give the link and say what to bring.
References
- references/rhinoscriptsyntax-cheatsheet.md — most-used
rs.*functions by category. - references/rhinocommon-map.md — which namespace to import for which task.
- references/macros-and-loading.md — command-line macro syntax,
LoadScript/RunScript, search paths. - references/vbscript-quirks.md — VBScript-only traps relevant to RhinoScript.
Upstream docs
- RhinoScript landing: https://docs.mcneel.com/rhino/8/help/en-us/information/rhinoscripting.htm
- Developer hub: https://developer.rhino3d.com/
- RhinoCommon API index: https://mcneel.github.io/rhinocommon-api-docs/api/RhinoCommon/html/R_Project_RhinoCommon.htm
- Example scripts repo: https://github.com/mcneel/rhino-developer-samples/tree/8/rhinoscript