Migrating ZScript¶
Explains how to port ZScript code to the Python API.
The ZBrush Python SDK ports at its core the ZScript API to Python and with that also allows for porting existing ZScripts to Python. There are, however, some differences between the APIs that are listed in this manual.
Change |
Details |
|---|---|
Function Names |
Many functions have been renamed to follow Python naming conventions, e.g., the ZScript function |
Function Signatures |
Some functions have changed signatures to better fit Python’s capabilities. |
Removed System Functions |
All ZSScript control flow commands ( |
Removed ZScript Tutorial Functions |
Functions in the ‘Display in the ZScript Tutorial Window’ of the current ZScript documentation are not available in Python. |
Example Migration¶
The following code is a very literal port of the ZScript Coffee Maker example to Python. For a more Pythonic implementation, see Example gui_notes.
"""Provides an example for a very literal port of a ZScript script to Python.
This directory contains three examples for notes interfaces. All three implement the same
coffee maker interface, where the user can select a coffee type and then serve it. The examples are:
- ex_gui_notes.py : A modern Pythonic implementation of a notes interface.
- ex_gui_zscript_port.py : A literal port of a ZScript notes interface to Python.
- ex_gui_zscript_orginal.txt : The original ZScript notes example for reference.
It is recommended to use the ex_gui_notes.py example as a reference for building modern notes code,
and this example only as a reference for porting ZScript code to Python.
"""
__author__ = "Javier Edo"
__date__ = "21/08/2025"
__copyright__ = "Maxon Computer"
import os
import zbrush.commands as zbc
message = ""
def note_interface():
hSize = 20
vSize = 18
vPos = 87
hPos = 23
space = 12
choice = [True, False, False, False, False]
choiceImage = [
"images/expresso.jpg",
"images/cappuccino.jpg",
"images/latte.jpg",
"images/mocha.jpg",
"images/flat white.jpg"]
choiceText = ["X", "", "", "", ""]
cupPic = choiceImage[0]
global message
while True:
zbc.add_note_button("", "images/ZCoffeeBack.jpg", 0, 1, 1, 305, 320, 0, 0, 0, 1, 1)
for x in range(5):
zbc.add_note_button(
choiceText[x], "", choice[x], False, hPos, vPos+((vSize+space)*x), hSize, vSize,
-1, 0xffa000, 1.0, 1.0, 1.0)
zbc.add_note_button(
"", cupPic, False, True, 149, 135, 0.0, 0.0, -1, -1, 1.0, 1.0, 1.0)
zbc.add_note_button(
"Cancel", "", False, False, 170, 260, 100, 25, -1, -1, 1.0, 1.0, 1.0)
zbc.add_note_button(
"Serve Now", "", False, False, 30, 260, 100, 25, -1, 0xffa000, 1.0, 1.0, 1.0)
result = zbc.show_note("")
if result >= 2 and result <= 6:
if choice[result - 2]:
choice[result - 2] = False
choiceText[result - 2] = ""
cupPic = "images/ZCoffeeEmpty.jpg"
message = "\Cffa000\n What, no coffee?!\n"
else:
for i in range(5):
if choice[i]:
choice[i] = False
choiceText[i] = ""
choice[result - 2] = True
choiceText[result - 2] = "X"
cupPic = choiceImage[result - 2]
elif result == 8: # Cancel button
message = "\Cffa000\n What, no coffee?!\n"
return
if result < 2 or result > 8: # Serve Now button or press Spacebar
if (choice[0] == 0 and choice[1] == 0 and choice[2] == 0 and choice[3] == 0 and
choice[4] == 0):
# all choices are unchecked, so no coffee selected
zbc.show_note("\Cc0c0c0\n Sorry, we do not serve empty cups.\n Please make a "
"choice or press \Cffa000Cancel\Cc0c0c0.\n", "",3,4737096,0,320)
else:
message = os.path.splitext(os.path.basename(cupPic))[0]
message = "\Cc0c0c0Enjoy your \Cffa000" + message + "\Cc0c0c0 !\n"
return
def open_note():
zbc.freeze(note_interface)
zbc.show_note(message, "",2,4737096,0,220)
if __name__ == "__main__":
open_note()
The original ZScript Coffee Maker example for reference.
//ZScript Note interface example
//***********************************************************************************************
//[IConfig,3.1]//uncomment this for ZBrush 3.1 and above
//[IConfig,2]//uncomment this for ZBrush 2.0 and above
//*********************************
//Variables definition
//*********************************
[VarDef,result,0]
[VarDef,hSize,20]
[VarDef,vSize,18]
[VarDef,vPos,87]
[VarDef,hPos,23]
[VarDef,space,12]
[VarDef,choice(5),0]
[VarDef,choiceImage(5),""]
[VarDef,choiceText(5),""]
[VarDef,cupPic,""]
[VarDef,message,""]
[VarDef,init,1]
//********Routines*********
[RoutineDef,Initialize,//initialization
[VarSet,init,0]
[VarSet,cupPic,"ZCoffeeData\expresso.jpg"]
[VarSet,message,"\Cc0c0c0Enjoy your \Cffa000expresso\Cc0c0c0 !"]
[VarSet,choiceImage(0),"ZCoffeeData\expresso.jpg"]
[VarSet,choiceImage(1),"ZCoffeeData\cappuccino.jpg"]
[VarSet,choiceImage(2),"ZCoffeeData\latte.jpg"]
[VarSet,choiceImage(3),"ZCoffeeData\mocha.jpg"]
[VarSet,choiceImage(4),"ZCoffeeData\flat white.jpg"]
[VarSet,choice(0),1]
[VarSet,choiceText(0),"X"]
]//end routine
[RoutineDef,NoteInterface,//main interface
[IFreeze,//makes operation smooth
[Loop,1000,//loop for selections, until Serve Now or Cancel choice ends loop
//draw the interface
//background image - the other buttons are positioned relative to this
[NoteIButton,/*text*/ , "ZCoffeeData\ZCoffeeBack.jpg" /*image*/ , /*pressed?*/ ,1 /*disabled?*/,1 /*HPos*/, 1 /*VPos*/ , 305 /*HSize*/ , 320 /*VSize*/ , /*color*/ , /*text color*/ , 0 /*opacity*/, /*text opacity*/ ,1 /*image opacity*/ ]
[Loop,5,//draw the selection buttons
[NoteIButton,choiceText(x) /*text*/ , /*image*/ ,choice(x) /*pressed?*/ , /*disabled?*/,hPos /*HPos*/,vPos+((vSize+space)*x) /*VPos*/ , hSize /*HSize*/ , vSize /*VSize*/ , /*color*/ ,0xffa000 /*text color*/, /*opacity*/, /*text opacity*/ , /*image opacity*/ ]
,x]
[NoteIButton,/*text*/ ,cupPic /*image*/ , /*pressed?*/ ,1 /*disabled?*/,149 /*HPos*/,135 /*VPos*/ , /*HSize*/ , /*VSize*/ , /*color*/ , /*text color*/ , /*opacity*/, /*text opacity*/ ,1 /*image opacity*/ ]
[NoteIButton,"Cancel" /*text*/,/*image*/ , /*pressed?*/ ,/*disabled?*/,170 /*HPos*/,260 /*VPos*/ ,100 /*HSize*/ ,25 /*VSize*/ , /*color*/ , /*text color*/ , /*opacity*/, /*text opacity*/ , /*image opacity*/ ]
[NoteIButton,"Serve Now" /*text*/,/*image*/ , /*pressed?*/ ,/*disabled?*/,30 /*HPos*/,260 /*VPos*/ ,100 /*HSize*/ ,25 /*VSize*/ , /*color*/ ,0xffa000 /*text color*/ , /*opacity*/, /*text opacity*/ , /*image opacity*/ ]
[VarSet,result,[Note,""]]//get result
//process result
[If, (result>=2)&&(result<=6),//choice results
[If,choice(result-2),//uncheck if same selection
[VarSet,choice(result-2),0]
[VarSet,choiceText(result-2),""]
[VarSet,cupPic,"ZCoffeeData\ZCoffeeEmpty.jpg"]//set image
[VarSet,message,"\Cffa000\n What, no coffee?!\n"]
[VarSet,init,1]
,//else check selection, uncheck the rest
[Loop,5,//uncheck all first
[VarSet,choice(n),0]
[VarSet,choiceText(n),""]
,n]
[VarSet,choice(result-2),1]//then check selection
[VarSet,choiceText(result-2),"X"]
[VarSet,cupPic,[Var,choiceImage(result-2)]]//set image
]//end if
]//end choice results
[If,result=8,//Cancel button
[VarSet,message,"\Cffa000\n What, no coffee?!\n"]
[LoopExit]//exits loop and interface
]// end Cancel result
[If,(result<2)||(result>8),//Serve Now button or press Spacebar
[If,(choice(0)=0)&&(choice(1)=0)&&(choice(2)=0)&&(choice(3)=0)&&(choice(4)=0),
//all choices are unchecked, so no coffee selected
[Note,"\Cc0c0c0\n Sorry, we do not serve empty cups.\n Please make a choice or
press \Cffa000Cancel\Cc0c0c0.\n",,3,4737096,,320]
[RoutineCall,Initialize]//resets interface
,//else process coffee choice
[VarSet,message,[FileNameExtract,[FileNameResolvePath,[Var,cupPic]],2]]
[VarSet,message,[StrMerge,"\Cc0c0c0\n Enjoy your \Cffa000",message,"\Cc0c0c0 !\n"]]
[LoopExit]//exits loop and interface
]//end if
]//end Serve Now result
]//end loop
]//end freeze
]//end routine
//*****end of routines********
//Button for launching interface
[IButton,"Launch Note Interface",,
[If,init, //initialize if necessary
[RoutineCall,Initialize]
]//end if
[RoutineCall,NoteInterface]//call interface
[Note,#message,,2,4737096,,220]//end message is displayed
]//end button
API Comparison¶
Find below a full list of the ZScript commands and their Python equivalents, as well as the porting notes.
ZScript Cmd |
Python Cmd |
Notes |
|---|---|---|
Assert |
n/a |
Python has a built-in assert() although its a ‘real’ assert unlike the ZScript one |
BackColorSet |
n/a |
ZScript Window commands not ported |
ButtonFind |
n/a |
Unlike ZScript python integration does not distinguish between top/other level commands |
ButtonPress |
n/a |
Unlike ZScript python integration does not distinguish between top/other level commands… use press |
ButtonSet |
n/a |
Unlike ZScript python integration does not distinguish between top/other level commands… use set |
ButtonUnPress |
n/a |
Unlike ZScript python integration does not distinguish between top/other level commands… use un_press |
CanvasClick |
canvas_click |
|
CanvasGyroHide |
hide_canvas_extras |
|
CanvasGyroShow |
show_canvas_extras |
|
CanvasPanGetH |
get_canvas_pan |
returns a tuple… equivalent is index 0 |
CanvasPanGetV |
get_canvas_pan |
returns a tuple… equivalent is index 1 |
CanvasPanSet |
set_canvas_pan |
|
CanvasStroke |
canvas_stroke |
|
CanvasStrokes |
canvas_strokes |
|
CanvasZoomGet |
get_canvas_zoom |
|
CanvasZoomSet |
set_canvas_zoom |
|
Caption |
n/a |
ZScript Window commands not ported |
CreateDirectory |
n/a |
use python built-ins for example: os.makedirs()… resolve paths using resolve_path |
CurveAddPoint |
add_curve_point |
|
CurvesCreateMesh |
create_mesh_from_curves |
|
CurvesDelete |
delete_curves |
|
CurvesNewCurve |
add_new_curve |
|
CurvesNew |
new_curves |
|
CurvesToUI |
curves_to_ui |
|
Delay |
n/a |
use time.sleep |
DispMapCreate |
create_displacement_map |
|
Exit |
n/a |
the original behavior aborting execution of ZScript can be done in python in multiple ways… to exit ZBrush… use sys.exit() |
FileDelete |
n/a |
use python built-ins for example: os.remove() resolve paths using resolve_path |
FileExecute |
n/a |
use python’s built-in ctypes.CDLL or cffi modules to achieve this |
FileGetInfo |
n/a |
use python’s built-in stat module |
FileNameAdvance |
increment_filename |
this is easily reimplementable in python but was left here as it’s commonly used |
FileNameAsk |
ask_filename |
|
FileNameExtract |
n/a |
use python’s string slicing instead |
FileNameGetLastTyped |
get_last_typed_filename |
|
FileNameGetLastUsed |
get_last_used_filename |
|
FileNameGetNext |
get_next_filename |
|
FileNameHasNext |
has_next_filename |
|
FileNameMake |
make_filename |
|
FileNameResolvePath |
resolve_path |
|
FileNameSetNext |
set_next_filename |
|
FileTemplateGetNext |
get_next_template_filename |
|
FontSetColor |
n/a |
ZScript Window commands not ported |
FontSetOpacity |
n/a |
ZScript Window commands not ported |
FontSetSize |
n/a |
ZScript Window commands not ported |
FontSetSizeLarge |
n/a |
ZScript Window commands not ported |
FontSetSizeMedium |
n/a |
ZScript Window commands not ported |
FontSetSizeSmall |
n/a |
ZScript Window commands not ported |
FontColorSet |
n/a |
ZScript Window commands not ported |
GetActiveToolPath |
get_active_tool_path |
|
GetMainToolPath |
get_main_tool_path |
|
GetPolyMesh3DArea |
get_polymesh3d_area |
|
GetPolyMesh3DVolume |
get_polymesh3d_volume |
|
HotKeyText |
n/a |
ZScript Window commands not ported |
IButton |
add_button |
command group argument replaced by function call… expected function signature fn(str) -> None |
IClick |
click |
|
IClose |
close |
|
IColorSet |
set_color |
|
IConfig |
config |
|
IDisable |
disable |
|
IEnable |
enable |
|
IExists |
exists |
|
IFadeIn |
fade_in |
|
IFadeOut |
fade_out |
|
IFreeze |
freeze |
command group argument replaced by function call… expected function signature fn() -> None |
IGet |
get |
|
IGetFlags |
get_flags |
|
IGetHotkey |
get_hotkey |
|
IGetID |
get_id |
|
IGetInfo |
get_info |
|
IGetMax |
get_max |
|
IGetMin |
get_min |
|
IGetSecondary |
get_secondary |
|
IGetStatus |
get_status |
|
IGetTitle |
get_title |
|
IHeight |
get_height |
|
IHide |
hide |
|
IHPos |
get_pos |
returns a tuple… equivalent is index 0 |
IKeyPress |
press_key |
command group argument replaced by function call… expected function signature fn() -> None |
ILock |
lock |
|
Image |
n/a |
ZScript Window commands not ported |
IMaximize |
maximize |
|
IMinimize |
minimize |
|
IModGet |
get_mod |
|
IModify |
modify |
|
IModSet |
set_mod |
|
Interpolate |
interpolate |
|
IPalette |
add_palette |
|
IPress |
press |
|
IReset |
reset |
|
IsDisabled |
is_disabled |
|
IsEnabled |
is_enabled |
|
ISet |
set |
|
ISetHotkey |
set_hotkey |
|
ISetMax |
set_max |
|
ISetMin |
set_min |
|
ISetStatus |
set_status |
|
IShowActions |
show_actions |
|
IShow |
show |
|
ISlider |
add_slider |
command group argument replaced by function call… expected function signature fn(str float) -> None |
IsLocked |
is_locked |
|
IsPolyMesh3DSolid |
is_polymesh3d_solid |
|
IStroke |
stroke |
|
ISubPalette |
add_subpalette |
|
IsUnlocked |
is_unlocked |
|
ISwitch |
add_switch |
command group argument replaced by function call… expected function signature fn(str bool) -> None |
IToggle |
toggle |
|
IUnlock |
unlock |
|
IUnPress |
un_press |
|
IUpdate |
update |
|
IVPos |
get_pos |
returns a tuple… equivalent is index 1 |
IWidth |
get_width |
|
MemCopy |
n/a |
use python built-ins for exchange with dynamic libs |
MemCreate |
n/a |
use python built-ins for exchange with dynamic libs |
MemCreateFromFile |
n/a |
use python built-ins for exchange with dynamic libs |
MemDelete |
n/a |
use python built-ins for exchange with dynamic libs |
MemGetSize |
n/a |
use python built-ins for exchange with dynamic libs |
MemMove |
n/a |
use python built-ins for exchange with dynamic libs |
MemMultiWrite |
n/a |
use python built-ins for exchange with dynamic libs |
MemRead |
n/a |
use python built-ins for exchange with dynamic libs |
MemReadString |
n/a |
use python built-ins for exchange with dynamic libs |
MemResize |
n/a |
use python built-ins for exchange with dynamic libs |
MemSaveToFile |
n/a |
use python built-ins for exchange with dynamic libs |
MemWrite |
n/a |
use python built-ins for exchange with dynamic libs |
MemWriteString |
n/a |
use python built-ins for exchange with dynamic libs |
MergeUndo |
merge_undo |
|
Mesh3DGet |
query_mesh3d |
signature changed! query_mesh3d(int property Opt<int> index) -> list[float] |
MessageOK |
message_ok |
|
MessageOKCancel |
message_ok_cancel |
|
MessageYesNo |
message_yes_no |
|
MessageYesNoCancel |
message_yes_no_cancel |
|
MouseHPos |
get_mouse_pos |
returns a tuple… equivalent is index 0 |
MouseLButton |
get_left_mouse_button_state |
|
MouseVPos |
get_mouse_pos |
returns a tuple… equivalent is index 1 |
MTransformGet |
n/a |
python has built-in memory block handling |
MTransformSet |
n/a |
python has built-in memory block handling |
MVarDef |
n/a |
python has built-in memory block handling |
MVarGet |
n/a |
python has built-in memory block handling |
MVarSet |
n/a |
python has built-in memory block handling |
NormalMapCreate |
create_normal_map |
|
Note |
show_note |
|
NoteBar |
set_notebar_text |
|
NoteIButton |
add_note_button |
|
NoteIGet |
get_from_note |
|
NoteISwitch |
add_note_switch |
|
PageSetWidth |
n/a |
ZScript Window commands not ported |
PaintBackground |
n/a |
ZScript Window commands not ported |
PaintBackSliver |
n/a |
ZScript Window commands not ported |
PaintPageBreak |
n/a |
ZScript Window commands not ported |
PaintRect |
n/a |
ZScript Window commands not ported |
PaintTextRect |
n/a |
ZScript Window commands not ported |
PD |
n/a |
ZScript Window commands not ported |
PenMoveCenter |
n/a |
ZScript Window commands not ported |
PenMoveDown |
n/a |
ZScript Window commands not ported |
PenMoveLeft |
n/a |
ZScript Window commands not ported |
PenMoveRight |
n/a |
ZScript Window commands not ported |
PenMove |
n/a |
ZScript Window commands not ported |
PenSetColor |
n/a |
ZScript Window commands not ported |
PixolPick |
pixol_pick |
|
PropertySet |
n/a |
ZScript Window commands not ported |
RAND |
rand |
python’s random module is preferrable… left here for compatibility purposes |
IRAND |
rand_int |
python’s random module is preferrable… left here for compatibility purposes |
Randomize |
randomize |
kept here for compatibility reasons… prefer using python’s random module |
RGB |
rgb |
|
SectionBegin |
n/a |
ZScript Window commands not ported |
SectionEnd |
n/a |
ZScript Window commands not ported |
ShellExecute |
n/a |
use python’s built-in subprocess module instead |
Sleep |
n/a |
not ported for now… can affect overall ZB performance |
SleepAgain |
n/a |
not ported for now… can affect overall ZB performance |
StrAsk |
ask_string |
|
StrExtract |
n/a |
use python’s string slicing |
StrFind |
n/a |
built-in to python cast |
StrFromAsc |
n/a |
use python’s built-in |
StrLength |
n/a |
use len() |
StrLower |
n/a |
use lower() |
StrMerge |
n/a |
use python’s formatting |
StrokeGetInfo |
get_stroke_info |
|
StrokeGetLast |
get_last_stroke |
|
StrokeLoad |
load_stroke |
|
StrokesLoad |
load_strokes |
|
StrToAsc |
n/a |
|
StrUpper |
n/a |
use upper() |
SubTitle |
n/a |
ZScript Window commands not ported |
SubToolGetActiveIndex |
get_active_subtool_index |
|
SubToolGetCount |
get_subtool_count |
|
SubToolGetFolderIndex |
get_subtool_folder_index |
|
SubToolGetFolderName |
get_subtool_folder_name |
|
SubToolGetID |
get_subtool_id |
|
SubToolGetStatus |
get_subtool_status |
|
SubToolLocate |
locate_subtool |
|
SubToolLocateByName |
locate_subtool_by_name |
|
SubToolSelect |
select_subtool |
|
SubToolSetStatus |
set_subtool_status |
|
SystemInfo |
system_info |
|
TextCalcWidth |
n/a |
ZScript Window commands not ported |
Title |
n/a |
ZScript Window commands not ported |
TLDeleteKeyFrame |
delete_keyframe |
|
TLGetActiveTrackIndex |
get_active_track_index |
|
TLGetKeyFramesCount |
get_keyframes_count |
|
TLGetKeyFrameTime |
get_keyframe_time |
|
TLGetTime |
get_timeline_time |
|
TLGotoKeyFrameTime |
set_timeline_to_keyframe_time |
|
TLGotoTime |
set_timeline_time |
|
TLNewKeyFrame |
new_keyframe |
|
TLSetActiveTrackIndex |
set_active_track_index |
|
TLSetKeyFrameTime |
set_keyframe_time |
|
ToolGetActiveIndex |
get_active_tool_index |
|
ToolGetCount |
get_tool_count |
|
ToolGetPath |
get_tool_path |
|
ToolGetSubToolID |
get_subtool_id |
|
ToolGetSubToolsCount |
get_subtool_count |
|
ToolLocateSubTool |
locate_subtool |
|
ToolLocateSubToolByName |
locate_subtool_by_name |
|
ToolSelect |
select_tool |
|
ToolSetPath |
set_tool_path |
|
TransformGet |
get_transform |
|
TransformSet |
set_transform |
|
TransposeGet |
get_transpose |
|
TransposeIsShown |
is_transpose_shown |
|
TransposeSet |
set_transpose |
|
Val |
n/a |
variables are built-in to python |
VarAdd |
n/a |
variables are built-in to python |
VarDec |
n/a |
variables are built-in to python |
VarDef |
n/a |
variables are built-in to python |
VarDiv |
n/a |
variables are built-in to python |
VarInc |
n/a |
variables are built-in to python |
VarListCopy |
n/a |
variables are built-in to python |
VarLoad |
n/a |
variables are built-in to python |
VarMul |
n/a |
variables are built-in to python |
VarSave |
n/a |
variables are built-in to python |
VarSet |
n/a |
variables are built-in to python |
VarSize |
n/a |
variables are built-in to python |
VarSub |
n/a |
variables are built-in to python |
Var |
n/a |
variables are built-in to python |
ZBrushInfo |
zbrush_info |
|
ZBrushPriorityGet |
n/a |
this existed but was not implemented |
ZBrushPrioritySet |
n/a |
this existed but was not implemented |
ZSphereAdd |
add_zsphere |
|
ZSphereDel |
delete_zsphere |
|
ZSphereEdit |
edit_zsphere |
|
ZSphereGet |
get_zsphere |
|
ZSphereSet |
set_zsphere |
See also¶
Quickstart
Take your first steps with Python scripting in ZBrush.
API Overview
Explains the conventions and capabilities of the ZBrush API.