Python Script

Tool - Write Python scripts inside Smode

This tool lets you run Python scripts in Smode.

Code execution

The parameter Launch Mode defines when the script is executed. By default it is set to "Manual".
The options are:
  • Manual : when the Execute trigger is pressed
  • At Preload : at script preload, for instance when the project is loading
  • At Activation : at script activation and reactivation
  • At Parameter Change : when a parameter of the script changes
  • At Every Update : every frame
  • At Deactivation : at script deactivation
  • At Unload : at script unload, for instance when the project is closing

The output Console of Smode is also refreshed by the execution of the code. When in the text editor, type Ctrl+Enter to compile and execute the script.

When you change the code of your script you need to recompile it by typing Ctrl+Enter

Import and Export your Script

To import and export your Script simply drag and drop it from and to your media directory.

Oil and SmodeSDK objects

In addition to regular Python and imported modules, all Oil and SmodeSDK objects can be instanciated.
Oil is a library upon which Smode is based, that re-implements various C++ types so that their variables can be introspected. There are atomics (Integer, Boolean ...), smart pointers, containers and so on. SmodeSDK implements classes relevant to graphics and show, such as Textures for instance. Both are automatically imported in every script. Use the Python built-in print(dir(Oil)) or print(dir(SmodeSDK)) in the script to query all native objects.
For instance, Integer is one of them and you can write myInt = Oil.Integer(4) to construct one with an initial value.
Most types in Oil / SmodeSDK don't have a Python binding yet (and don't need one), but can still be constucted by passing their name to the Oil.createObject method. For instance Oil.createObject("StrictlyPositiveInteger") , which is an Oil type without a Python binding.
Oil types that currently have a useful binding and can be constructed are:
  • Boolean , constructed with an optional bool argument
  • Integer and PositiveInteger , constructed with an optional int argument
  • Real and PositiveReal , Meters and PositiveMeters , Seconds , Percentage and UnboundedPercentage , constructed with an optional float argument
  • String , constructed with an optional string argument
  • Color and ColorWithAlpha , constructed with optional named arguments, such as "red", "green", "blue" and "alpha"
  • Vector , constructed without arguments but can be filled with append and insert methods
  • Pointer types, while having a binding, are better created with the Oil.createObject method
  • Selection
  • NativeFile

Here are a few other useful Oil types, without a binding but that can be constructed with the Oil.createObject mechanism:
  • OwnedPointer "owns" an instance in the script. Oil.createObject("OwnedPointer(Number)") creates a dropdown menu that lets you instanciate one of the numerous classes inheriting from Number: Angle, RelativeTime etc.
  • WeakPointer references to an instance of the provided type or its descendents. If the pointed type is abstract (ex: Oil.createObject("OwnedPointer(Camera)") , or with a Layer), it will create a dropdown menu that lists all concrete instances in the project. If it's concrete, it is possible to drag and drop an element of this class there.
  • Position3d for a position in 3D space
  • EulerAngles for an orientation
  • Size3d(Real) for a scale
To access the pointed Oil object, use the get() method of the pointer.
SmodeSDK types that currently have a useful binding and can be constructed are:
  • SingleTextureRenderer , constructed without arguments
  • TextureLayer and GroupLayer , constructed with optional named arguments

Types with bindings can be accessed and set with the = operator; for the other ones you will need to use the get() and set() to convert properly with Python types. For types whose constructors accept optional named arguments, such as Color, any argument accessible trough print(dir()) can be set this way. Ex: myColor = Oil.Color(red=1., blue=0.5)

Expose Parameters

To expose parameters in the Tool, start the script with your variables declarations as follows (one per line): the name of the variable, followed by a colon, and the constructor of the object. For instance, the following code will display a widget for an Integer and a selector of cameras of the project:
myInt: Oil.Integer()
linkToCamera: Oil.createObject("WeakPointer(Camera)")
(remaining of the script...)
All variables exposed by the script are accessible as children properties of the script object. Following the previous example, the first exposed variable can be accessed by script.myInt . Beware: this is an instance of Oil.Integer, you need to call the get() method to retrieve a Python int.
For any object, you can access a variable by its name( getVariableByName ), or iterate through them with the methods getNumVariables and getVariable (that takes the index as a parameter).

Navigate through elementTree

The root of the tree is accessed by script.rootElement . As usual, print(dir(script.rootElement)) will display all variables. The ones in the plural form are usually an array of Element children: layers , modifiers and tools . They themselves can have children arrays, and it's possible to iterate upon them.
Beware that rootElement is different in different Element trees: if the script is located in the Stage it will be a RootStageElement, in the Show it will be a Scene, and so on.
The script.document will return the file (project or compo) you are currently working in. There are a lot of interesting properties that can be accessed; once again use print(dir()) to list them. For instance you can get the Stage with script.document.content.pipeline.stage .
The following properties can be used to navigate more precisely starting from any Element:
  1. parent returns the object that owns the caller; for instance an array
  2. parentElement same, but the returned object is an Element (for instance, since an array is not an Element, it will probably fallback to be the owner of the array)
  3. parentElementInTree some Elements are hidden in the Element tree (Placements for instance). This returns the first Element that is present in the tree.

Create Layers

In order to create layers, you need the name of its generator class; check the layers Class names list for information.
  1. Instantiate your layer
  2. Define the type
  3. Place it in the Element tree

Example with a simple 2d compo layer
myLayer = SmodeSDK.TextureLayer(generator=SmodeSDK.Compo()) script.rootElement.layers.append(myLayer)

Get and set parameters for a layer

Following the previous example, the newly created layer could be accessed by:
myLayer = script.rootElement.layers[len(script.rootElement.layers) - 1]]
Now using the usual print(dir(myLayer)) method, we can see a few properties of interest:
myLayer.label = "myLayer" # will rename the layer in the element Tree
myLayer.activation.set(False) # will deactivate the layer
The first layer named "myLayer" could also be retrieved with: myLayer = script.rootElement.layers["myLayer"]
It is also possible to drag and drop an Element from the ElementTree directly in the script. The path to this Element will be automatically pasted, but beware that this is a harcoded path. Also, it works if the script is in the same tree. If you want to have a link robust to path changes, you can expose a WeakPointer to a concrete class at the beginning of the script and drag the Element on it. For instance for a Layer: myPointer: Oil.createObject("WeakPointer(TextureLayer)") .


Here is an example of a simple 3d layer with a box and an additional modifier:
box = Oil.createObject("BoxGeometryGenerator")
modifier = Oil.createObject("ColorizeGeometryModifier")
renderer = Oil.createObject("SurfaceGeometryRenderer")
myLayer = Oil.createObject("GeometryLayer")
myLayer.generator = box
myLayer.renderer = renderer


Here is an example of a shape layer drawing a simple circle:
circle = Oil.createObject("CircleShapeGenerator")
renderer = Oil.createObject("DefaultShapeRenderer")
layer = Oil.createObject("ShapeLayer")
layer.generator = circle
layer.renderer = renderer

Install Python modules

It is possible to install and use Python modules locally in Smode. The easiest way is to use pip. First, go to you Smode folder, thent in the python subfolder and try to run python.exe . If you get the error that a .dll is missing, copy here the python37.dll located in the parent Smode folder.
Then open a command line tool at this specific location and run python.exe -E -m pip install + the name of your module. It will be downloaded and installed in the local Smode/python directory, and you can import it in the scripts.


  • Python Script Launch Mode: Defines when the current script is executed
  • Manually execute the script

See Also: