Compiling python scripts into components in R8s

Hi, I’m new to the forum, so apologies if this question isn’t in the right place.

I was wondering if there are any detailed guides on how to compile Grasshopper Python scripts into Grasshopper components. From what I understand, the old compilation workflow has been deprecated and replaced by the new Script Editor. I’ve found a few forum threads discussing this, but none of them seem to fully explain the process.

I’m particularly interested in learning the most efficient way to convert existing IronPython scripts written for Rhino 7 so they can be compiled and used in Rhino 8. Any insights, documentation, or recommended workflows would be greatly appreciated.

Thanks in advance!

I’ve watched the guide @eirannejad has put together on how to use the script editor works which was really helpful

along with the Mcneel’s guide

1 Like

You’ve got most of it, there are some additional resources here..

Hi thank you for your response. I’m specifically looking for any documentation or recommended workflows for converting code that was previously compiled as a .ghpy component. In particular, I want to understand how to migrate code that overrides original component methods (for example, to customize component appearance or add UI elements) so that it can be compiled using the new Script Editor method.

There was an older thread I also attached where someone tried to modify a component to add a button, but it wasn’t fully answered — I’m hoping to get a clearer idea of what the current best practices are for achieving this in Rhino 8 / Grasshopper using the new system.

Any pointers to documentation, examples, or workflows would be really helpful!

After researching a bit the ScriptEditor in Rhino 8 is designed for script-in-a-box components, not deep GH_Component subclassing.

Most likely you’ll want to use the ScriptEditor generated dotnet project solution (.sln and .csproj files) which will allow you to do more with custom right click menus, component appearance and shape, custom serialization and GH_Component subclass with arbitrary method overrides.

I’ve assigned this to Ehsan so that he can provide more insight on how things will progress in future.

1 Like

They (GHPython components, not CPython ones, nor IronPython 2 ones) should still run perfectly well in Rhino 8. Add ghenv.Component.ToggleObsolete(False) to remove the “Old” banner.

If I knew about it, I would’ve used: GitHub - compas-dev/compas-actions.ghpython_components: Trying to make Grasshopper development version-control friendlier since 1337. for packagng plug-ins.

1 Like

@Kent_Maz Script editor projects are designed to pack the scripts into shippable Rhino and Grasshopper plugin binaries (.rhp, and .gha files) to make it easier to share Rhino and GH scripts with others. They scripts are only packed and not Compile-d. Python 3 can not even be compiled to a CLR like you would expect with C# or IronPython. That’s a runtime limitation and not a choice we made.

Thank you for the clarification.

It doesn’t necessarily need to be compiled as a .ghpy file — packaging it as standard Rhino and Grasshopper plugin binaries (.rhp and .gha) works perfectly fine for me, honestly even better.

What I’m really trying to understand is how to migrate my existing IronPython scripts — which I previously compiled into .ghpy components — into this new plugin-based workflow. Many of those scripts subclassed GH_Component directly to override rendering behavior, customize attributes, and modify component (for example, custom graphics, etc.).

So my main question is: when moving to the new plugin packaging approach, is subclassing GH_Component and overriding attributes/graphics still supported? Or are those kinds of UI customizations no longer possible in the newer system?

I’d really appreciate any clarification/steps guide on how this maps to the current Rhino 8 / Grasshopper development workflow.

The structure of my script is really similar to the post I also referenced where it subclassed the GH_Component for adding a button. I’ll copy paste it below for reference. If I had something similar would I be able to use the packaging method to a plugin binaries using the script editor? If so what’s the proper approach?

from ghpythonlib.componentbase import executingcomponent as component
import Grasshopper, GhPython
import System

class Button_UI(Grasshopper.Kernel.Attributes.GH_ComponentAttributes): # inherits all methods of GH_ComponentAttributes
    def __init__(self, owner):
        super(Button_UI, self).__init__(owner)
        self.component = owner
        self.button_down = False
                
    def Layout(self): # override inherited method Layout
        Grasshopper.Kernel.Attributes.GH_ComponentAttributes.Layout(self)
        component_rect = Grasshopper.Kernel.GH_Convert.ToRectangle(self.Bounds) 
        component_rect.Height += 22
        self.button_rect = System.Drawing.Rectangle(component_rect.X, component_rect.Bottom-22, component_rect.Width, 22)
        self.button_rect.Inflate(-2, -2)
        Bounds = component_rect
        self.Bounds=Bounds
        ButtonBounds = self.button_rect
        self.ButtonBounds=ButtonBounds
            
    def Render(self,canvas, graphics, channel): # Override Render method
        Grasshopper.Kernel.Attributes.GH_ComponentAttributes.Render(self, canvas, graphics, channel)
        if channel == Grasshopper.GUI.Canvas.GH_CanvasChannel.Objects:
            color = Grasshopper.GUI.Canvas.GH_Palette.Grey if self.button_down else Grasshopper.GUI.Canvas.GH_Palette.Black
            button = Grasshopper.GUI.Canvas.GH_Capsule.CreateTextCapsule(self.ButtonBounds, self.ButtonBounds, color, "Button", 2, 0)
            button.Render(graphics, self.Selected, self.Owner.Locked, False)
            button.Dispose()
            
    def RespondToMouseDown(self,sender,e):
        if e.Button == System.Windows.Forms.MouseButtons.Left:
            rec = self.button_rect
            pt = System.Drawing.Point.Round(e.CanvasLocation)
            if not self.button_down:
                if pt.X > rec.X and pt.X < rec.X+rec.Width and pt.Y > rec.Y and pt.Y < rec.Y+rec.Height:
                    self.button_down = True
                    self.component.OnDisplayExpired(False)
                    return  Grasshopper.GUI.Canvas.GH_ObjectResponse.Capture
        return super(Button_UI, self).RespondToMouseDown(sender, e)
        
    def RespondToMouseUp(self,sender,e):
        if e.Button == System.Windows.Forms.MouseButtons.Left:
            if self.button_down:
                self.button_down = False
                self.component.OnDisplayExpired(False)
                rec = self.button_rect
                pt = System.Drawing.Point.Round(e.CanvasLocation)
                if pt.X > rec.X and pt.X < rec.X+rec.Width and pt.Y > rec.Y and pt.Y < rec.Y+rec.Height:
                    self.component.click_response()
            return  Grasshopper.GUI.Canvas.GH_ObjectResponse.Release
        return super(Button_UI, self).RespondToMouseUp(sender, e)
        
class MyComponent(component):
    def __init__(self):
        self.click_count = 0
    
    def CreateAttributes(self): # Override inherited method create attributes
        self.m_attributes=Button_UI(self) 
            
    def RunScript(self, x, y):
        return self.click_count
        
    def click_response(self):
        self.click_count += 1
        self.ExpireSolution(True)

@eirannejad Hi Ehsan, I am the one who originally posted the script that @Kent_Maz posted here. I’d love to get a proper answer on this too.

Does this mean the component methods like CreateAttributesand DrawViewportMeshescannot be overridden with python? Do those require that the script be compiled like in the old IronPython workflow, or will they work as the .rhp, and .gha files? I had quite a few tools using these overrides in Ipy that I would love to get working in python3.