This is taking longer than expected.

Try againBrowse the library
AI Blocks

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.

Download all files

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.

This skill

Rhino modeling script writer

Open builder

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

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:

  1. 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.
  2. 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.
  3. 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 .py Rhino 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 _-RunPythonScript or _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
  1. Disable redraw: rs.EnableRedraw(False).
  2. Wrap mutations in a single undo record: undo = doc.BeginUndoRecord("My Op") … doc.EndUndoRecord(undo).
  3. Use RhinoCommon directly inside the loop (skip rhinoscriptsyntax overhead).
  4. Re-enable redraw and call doc.Views.Redraw() in a try/finally so a crash never leaves the viewport frozen.
Distribute a script to a teammate
  1. Save the .py / .rvb somewhere on disk.
  2. Add the folder to Options → Files → Search paths so Rhino can find it by name.
  3. Create a toolbar button or alias whose macro is:
    • Python: ! _-RunPythonScript "MyScript.py"
    • RhinoScript: ! _-LoadScript "MyScript.rvb" _-RunScript MySubName
  4. The leading ! cancels any running command; - runs the command in script (no-dialog) mode.
Run code at Rhino startup
  1. Place a .rvb/.py in a search path.
  2. Tools → Options → RhinoScript (or Python) → add to Startup list. The file executes once per session.
Gotchas
  • rhinoscriptsyntax returns GUIDs, RhinoCommon returns objects. Mixing them is fine, but doc.Objects.Find(guid) is the bridge from a rs.* id to a RhinoObject.
  • Coordinates differ by surface. Python uses (x, y, z) tuples or Rhino.Geometry.Point3d; VBScript uses 3-element Array(x, y, z). Never pass a Python list to a VBScript helper through COM.
  • Option Explicit is off by default in VBScript. Typos silently create new variables. Always add Option Explicit at the top of .rvb files.
  • VBScript has no block scope. All Dims inside a Sub are hoisted to the top of the procedure. Loop counters leak.
  • Nothing, Empty, and Null are different in VBScript. Use IsNull for Rhino.GetObject failure, IsEmpty for uninitialized Variant, Is Nothing for object refs.
  • Parentheses change calling semantics in VBScript. Call Foo(a, b) and Foo a, b are valid; Foo(a, b) (no Call, with parens) is not a call to a Sub — it’s a syntax error for multi-arg subs and a forced ByVal for single-arg.
  • Tolerance is per-document. Always read doc.ModelAbsoluteTolerance rather than hardcoding 0.001; users work in mm, m, inches, etc.
  • Long loops should poll Rhino.RhinoApp.EscapeKeyPressed so the user can cancel. Otherwise Rhino appears frozen.
  • GUID strings vs System.Guid. rhinoscriptsyntax accepts either; RhinoCommon wants System.Guid. Convert with System.Guid(str_id) if needed.
  • Don’t call doc.Views.Redraw() inside a tight loop. Toggle redraw once outside the loop.
  • .rvb is just .vbs renamed with a Rhino-specific extension so Rhino’s LoadScript recognizes it. Same VBScript engine.
  • Rhino.RhinoApp.IsHeadless may not exist on older Rhino 8 builds. Use getattr(Rhino.RhinoApp, "IsHeadless", None) and check for None before using. Fall back to a heuristic (e.g. sc.doc.Views.Count == 0) or assume GUI present.
  • RhinoMath is at Rhino.RhinoMath, not Rhino.DocObjects.RhinoMath. Accessing Rhino.DocObjects.RhinoMath raises AttributeError.
  • doc.Objects.AddBrep() returns System.Guid.Empty on failure. In Rhino 8 CPython the System namespace may not be directly importable; check the return value as a string: str(obj_id) == "00000000-0000-0000-0000-000000000000".
  • rhinoscriptsyntax has no type stubs. Static analysers (Pylance/Pyright) flag import rhinoscriptsyntax as rs as unresolvable. Suppress with # type: ignore on 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 any import random inside the stdlib (e.g. tempfile imports random internally) will find your file instead and fail with Cannot 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 script uses CPython 3 (UTF-8 by default) so the same file works there, making the failure non-obvious. IronPython 2.7 raises SyntaxError: 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 becomes x.
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
Upstream docs