Automatically Colour Rhino Curves by Degree

Automatically Colour Rhino Curves by Degree
Quick look Lines become black, arcs blue, cubic curves red… all without pressing a button. This guide shows you how to drop a tiny Python script into Rhino so every new curve auto‑colours itself based on its degree (1–11).
Why bother?
- Instant visual feedback – spot stray lines or high‑degree NURBS at a glance.
- Fewer manual steps – no more Select → Run Script → … every time you draw.
- Custom palette – tweak colours to match your studio standard or print style.
Prerequisites
You needVersionRhino for WindowsormacOS6,7 or8 (tested)Basic familiarity with running a RhinoPython script–
Note for Mac users: Rhino 8 ships with CPython 3.x. The script below works in both IronPython 2.7 (Win/macOS ≤7) and CPython 3.x (Rhino 8) with no edits.
Step 1 — Copy the script
Open Rhino. In the command bar write EditPythonScript and paste in the code block below. Save the file as AutoCurveColours.py and press Play.
The only part you’ll ever edit is the colour palette at the top.
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Auto Curve‑Colourer for Rhino 6/7/8 (toggle + revert)
# -----------------------------------------------------------------------------
# • Colours EVERY curve (existing + newly‑created) by its degree (1‑11).
# • One alias = ON / OFF. When OFF, all curves return to their original colour.
# • Works in IronPython 2.7 (Rhino ≤7) and CPython 3.x (Rhino 8).
# -----------------------------------------------------------------------------
# Part of the Rhino Masterclass at Cademy.xyz – 2025
# -----------------------------------------------------------------------------
import Rhino
import scriptcontext as sc
import System.Drawing as sd
# ────────────────────────────────────────────────────────────
# USER PALETTE – edit the swatches to your preference
# ────────────────────────────────────────────────────────────
COLOR_MAP = {
1: sd.Color.Black, # lines (deg‑1)
2: sd.Color.Blue, # arcs (deg‑2)
3: sd.Color.Red, # cubic NURBS (deg‑3)
4: sd.Color.Orange,
5: sd.Color.LimeGreen,
6: sd.Color.Turquoise,
7: sd.Color.Cyan,
8: sd.Color.RoyalBlue,
9: sd.Color.Indigo,
10: sd.Color.Violet,
11: sd.Color.Brown,
}
DEFAULT_COLOR = sd.Color.LightGray # degree > 11
# ────────────────────────────────────────────────────────────
# ---------------------------------------------------------------------------
# INTERNAL KEY NAMES (all stored in scriptcontext.sticky)
# ---------------------------------------------------------------------------
_handlers_key = "cademy_curve_colour_handlers" # {doc_id: handler}
_enabled_key = "cademy_curve_colour_enabled" # {doc_id: bool}
_state_key = "cademy_curve_colour_state" # {doc_id: {guid: (src,col)}}
# ---------------------------------------------------------------------------
# ===========================================================================
# CORE COLOUR + RESTORE FUNCTIONS
# ===========================================================================
def _colour_curve(rh_obj):
"""Apply the degree‑based colour to a single curve object."""
geo = rh_obj.Geometry
if not isinstance(geo, Rhino.Geometry.Curve):
return False
deg = geo.Degree
col = COLOR_MAP.get(deg, DEFAULT_COLOR)
attr = rh_obj.Attributes
attr.ColorSource = Rhino.DocObjects.ObjectColorSource.ColorFromObject
attr.ObjectColor = col
rh_obj.CommitChanges()
return True
def _record_and_colour_all(doc, state_dict):
"""Store current colours for *every* curve then recolour them."""
for rh_obj in doc.Objects:
geo = rh_obj.Geometry
if not isinstance(geo, Rhino.Geometry.Curve):
continue
attr = rh_obj.Attributes
# Save original colour once (idempotent)
state_dict[rh_obj.Id] = (attr.ColorSource, attr.ObjectColor)
_colour_curve(rh_obj)
def _restore_all(doc, state_dict):
"""Revert curves to their saved colour source & colour."""
for guid, (src, col) in state_dict.items():
rh_obj = doc.Objects.FindId(guid)
if not rh_obj: # object was deleted
continue
attr = rh_obj.Attributes
attr.ColorSource = src
attr.ObjectColor = col
rh_obj.CommitChanges()
# ===========================================================================
# MAIN TOGGLE (alias runs this file once to flip state per document)
# ===========================================================================
def toggle_auto_colour():
"""Enable or disable auto‑colouring for the ACTIVE Rhino document."""
doc = Rhino.RhinoDoc.ActiveDoc
doc_id = doc.RuntimeSerialNumber
# Retrieve or create our three per‑session dictionaries.
handlers = sc.sticky.get(_handlers_key, {})
enabled = sc.sticky.get(_enabled_key, {})
all_state = sc.sticky.get(_state_key, {}) # {doc_id: state_dict}
state = all_state.get(doc_id, {}) # per‑doc colour cache
# -------- DISABLE ------------------------------------------------------
if enabled.get(doc_id, False):
enabled[doc_id] = False
_restore_all(doc, state)
print("Auto curve‑colouring DISABLED – Cademy.xyz")
sc.sticky[_enabled_key] = enabled
sc.sticky[_state_key] = all_state
return
# -------- ENABLE -------------------------------------------------------
# 1. Create handler once per document, if not already present
if doc_id not in handlers:
def _handler(sender, e, this_doc_id=doc_id):
if not sc.sticky.get(_enabled_key, {}).get(this_doc_id, False):
return # feature is OFF
# Save original colour if we never saw this curve before
state_dict = sc.sticky.get(_state_key, {}).get(this_doc_id, {})
rh_obj = e.TheObject
if rh_obj and rh_obj.Id not in state_dict:
attr = rh_obj.Attributes
state_dict[rh_obj.Id] = (attr.ColorSource, attr.ObjectColor)
sc.sticky[_state_key][this_doc_id] = state_dict
_colour_curve(rh_obj)
doc.AddRhinoObject += _handler
handlers[doc_id] = _handler
sc.sticky[_handlers_key] = handlers
# 2. Mark as enabled
enabled[doc_id] = True
sc.sticky[_enabled_key] = enabled
# 3. Colour every existing curve & cache originals
if doc_id not in all_state:
all_state[doc_id] = {}
_record_and_colour_all(doc, all_state[doc_id])
sc.sticky[_state_key] = all_state
print("🟢 Auto curve‑colouring ENABLED — Cademy.xyz (run again to disable)")
# ---------------------------------------------------------------------------
if __name__ == "__main__":
toggle_auto_colour()Re-Run the script to disable
We tag the handler with the document’s runtime serial number. When you open a second Rhino file, it gets its own independent watcher. And because we keep the exact same function instance in sc.sticky, removing it with -= always succeeds—even after the script has been re‑run.
How the magic works
on_add_objectis registered toRhinoDoc.AddRhinoObject— Rhino calls it for every new object.- The handler filters out anything that isn’t a curve.
- For curves, it looks up the degree in
COLOR_MAPand switches the object’s colour source to By Object. - The sticky dictionary (
sc.sticky) remembers the handler between runs so the same script acts as both ON and OFF toggle.
Step 2 — Add a Rhino alias (one‑click toggle)
- Rhino > Options > Aliases (Preferences > Aliases on macOS)
- Click New, give it a short name like
AutoColours. - Command field:
_-RunPythonScript "AutoCurveColours.py"- OK. Done!
Now type AutoColours in the command line once to turn the watcher on. Type it again to turn it off.
Step 3 — Test drive
- Enable the alias.
- Draw a Line → should turn black instantly.
- Draw an Arc → blue.
- Draw a free Curve (default degree 3) → red.
(Sketch a few higher‑degree curves with the ChangeDegree command if you want to see the rest of the rainbow.)
Don’t miss out, enroll today.

