Nuke Scripting

Nuke scripting is done in pyhton which is an interpreted dynamically typed language. So it will be translated on runtime no need for compiling to run. Besides that it looks at blank space so watch out. nuke python documentation python documentation

=Using the Script Editor= For scripting go click the button on the top left of the nuke pane. Go to windows-> Script Editor. In the script editor you can write and execute scripts.

Loading and Saving Scripts
On the tool bar are buttons for saving, importing and importing combined with executing. The scripts are saved as .py files in the custom scripts folder. Don't forget the extention! .pyc is another extentions that means python compiled. Despite python doesn't need compiling it can be done and compiled scripts are faster.

toolbar
At the top bar of the script editor are buttons for saving and importing (or importing and executing) scripts.

Put latest executed script in script editor
control + [ The brackets with control work like a undo redo options so you can go back and forth through executed scripts.

executing a script
control + [

clear output window
control + backspace

echo python commands
Preferences --> Script Editor --> echo python commands to output window Checking this will output the code of all the operations you do in nuke to the output window. This is useful for figuring out the python command for certain operations.

=Creating Windows=

Message
nuke.message('hello world') This will create a window that sais hello world with an ok button and an info icon.

nuke.getInput
This command workst similar to the input pyhton command. Which doesn't work in nuke. This command will prompt a dialog box with the message that is declared between the brackets and a type field. The command return the user input. Example: var = nuke.getInput("werkt dit?") print(var) ja Here the user input was "ja"
 * 1) Result:

yes or no
There is a nuke function to create a window to get a boolean yes or no answer. nuke.ask Example if nuke.ask('Do you want to create a blur?'): nuke.createNode('Blur') else: pass This will ask the user Do you want to create a blur? if the yes button is clicked the if statement evaluates to True so a Blur node is created. If no is clicked the if statement evaluates to False so the else block will be executed which in this case sais pass so nothing will happen.

Get frames and views
This nuke function asks the user to specify a frame range and a view (if there are multiple when using a stereo viewer). This will result in a list of strings starting with the frame range and then the specified viewer. Example: r = nuke.getFramesAndViews('name of the panel','1-100') range = r[0] views = r[1] Here the first argument is the name of the panel and the second is the default frame range. The result of the user input here is stored in the two variables range and views

Panel
This nuke function let you use all sorts of elements to populate your panel. Example: p = nuke.Panel('my panel') p.addEnumerationPulldown('choose','A B C') p.show print p.value('choose') Working with panels is similar to working with nodes when adding user knobs and getting values.
 * The nuke.Panel function doesn't do much on its own. It creates the panel with the name specified in the argument, but it doesn't show up of have any elements.
 * In the second line a pulldown menu is added to the panel where the first argument is the name of the menu and the second argument are the options divided by spaces.
 * The show function makes the panel actually pop up.
 * The last line prints the outcome of the user input. When cancel is pressed the outcome of the whole panel is None

Create a custom Panel tab
A panel tab is a tab like the poperties window or the script editor. They can define the interface and be stored in interface presets. Example:
 * 1) MY PANEL TAB

import nukescripts import nuke
 * 1) import any modules you are going to use

k = nuke.String_Knob('knobName', 'label')
 * 1) define the variables for the knobs you want to add to the panel

class myPanelTabFunction(nukescripts.PythonPanel):
 * 1) create the panel

#define any customisations def __init__(self): #register the panel nukescripts.PythonPanel.__init__(self, 'my panel', 'com.myRegister.myModalPanel') #set any default values for the knobs you are going to add k.setValue('default value') #add the knobs (the ones you stored in variables above) self.addKnob(k) import nuke
 * This script has to be saved as myPanelTabScript.py in an accessible folder.
 * This will make a panel with the name my panel and a text knob.


 * 1) MY PANEL TAB

import myPanelTabScript
 * 1) import the script

def addMyPanelTab:
 * 1) define the function to call your panel

#define "myPanelTab" as a global variable global myPanelTab #define "myPanelTab" variable as the call for the function inside "myPanelTabScript" to create the panel myPanelTab = myPanelTabScript.myPanelTabFunction #add the panel to the GUI return myPanelTab.addToPane

paneMenu = nuke.menu('Pane')
 * 1) access the "Pane" menu (GUI tabs)

paneMenu.addCommand('my panel tab', addMyPanelTab )
 * 1) add "my panel tab" to the "Pane" menu

nukescripts.registerPanel('com.myRegister.myModalPanel', addMyPanelTab)
 * 1) register the panel to be able to store its layout in the GUI
 * This script needs to be added to the menu.py to add the paneltab to the nuke environment.

=Copying Nodes=== To copy a specific node you can use the copy python model. import copy copy.copy(nuke.selectedNode)

=Duplicate selected nodes= nukescripts.node_copypaste Where nukescripts is the model node_copypaste the function and the brackets indicate that it's a function.

=Selection=

Selects all nodes
nuke.allNodes nuke.allNodes(recurseGroups=True)
 * Include nodes in groups and subgroups:

Store selected Node
variable = nuke.selectedNode

Store selected Nodes in a list
variable = nuke.selectedNodes The first element of your selection will be the last element in the list and the last element in the selection will be the first element in the list.

Getting a value of a knob object from a selected node
nuke.selectedNode.knob.('knobName'.value) or nuke.selectedNode.knob.('knobName'.getValue)

Getting the Node object by its name
nuke.toNode('nodeName')

Getting a list containing all nodes in the node graph
nuke.allNodes

This Node
Nodes can have bottons to execute scripts too. To refer to the node where the script is stored you can use the thisNode function. nuke.thisNode

=Node Classes= To display the node class as well as the knob names and other information select a node and press i

get selected nodes limited to class
This command will give you a list of the selected nodes that are within the specified class. nuke.selectedNodes('nodeClass') or readnodes = nuke.allNodes('Read')

=Creating Nodes= After a node is created it's always selected. So when creating multiple nodes there always connected and aligned vertically by default.

Create node in a variable
When creating a node in a variable you give yourself the opportunity to call the node later in the script to do other operations on it. namevariable = nuke.createNode('classofthenode') Example frameholdcam = nuke.createNode('FrameHold')

Create node with a set value
If you just want to change one value on creation this is a quick way of doing that. If you want to change more values you can store the node in a variable on creation and then use setValue. nuke.createNode('nodeClass').knob('knobName').setValue('desiredValue')

Create node without changing the properties window
When you don't want the properties of the node to show up after creating it (which is the default behaviour) You can put a second argument that controls that. Example: n = nuke.createNode('Blur',inpanel=False)

=Node Connection=

setInput
This function will set the input of a node. a.setInput(b,c) a = is the node name or node. This can be a hard coded node name or a variable storing a node name or node. b = the input number, for example when a node only has one input this has to be 0. Or when you want to connect to the mask input for a grade for example this had to be 1. The way to determine what index you need is to count. You start at the top from right to left then you go to the right side for a mask input for example then you go to the left side for the infinite a inputs of a merge for example. You start counting at 0 c = Where to connect the node to. If it shouldn't connect to anything you can put None in this field. Example Project3D1.setInput(0,FrameHold3)

=Node Position=

get the value of a node position
n = nuke.selectedNode print n['xpos'].value print n['ypos'].value This will first print the x-coördinate of the node position in the node graph and then the y-coördinate. print n.xpos print n.ypos
 * Alternative:

set the value of a node position
n = nuke.selectedNode n['xpos'].setValue(0) n['ypos'].setValue(0) This will set the selected node's position the the center of the script. n.setXpos(0) n.setYpos(0)
 * Alternative:

To set both coördinates with one command you can use the following function: setXYpos(x,y) Where the first command is the x-coördinate and the second the y-coördinate. Example: n = nuke.selectedNode n.setXYpos(0,0) This will set the selected node's position the the center of the script.
 * Set both coördinates with one command:

=Node Size= You can get the size of a node. This can be helpful when working with the layout of the graph editor. You can't change the width of a node, the height can change to make space for the contents of the label. n = nuke.selectedNode print n.screenWidth print n.screenHeight This will print the width and heigth of the selected node.

=Deleting Nodes=

Delete Node
Syntax: nuke.delete(node) With this nuke function you can delete nodes. Note that it expects a node as an argument not a node name! nuke.delete(nuke.toNode('nodeName'))
 * Delete node by name:

Delete Selected Nodes
Syntax: nukescripts.node_delete This function will delete all selected nodes.

=Groups=

create group
nuke.createNode('Group') This will create an empty nuke group, usually you store this in a variable for later use.

collapse selected nodes to a group
nuke.collapseToGroup If there are multiple options for the output or input it will give a pop-up window to specify.

create nodes in a group
To create nodes in a group you need to specify first that you want to work in the group environment. groupNode.begin Where groupNode is usually the stored variable of your group. groupNode.end Example: g = nuke.createNode('Group') g.begin nuke.createNode('Input') nuke.createNode('Output') g.end This will create a group with an input and output. To change the Input name you have to change the name of the input node by replacing the default 1. So with the name InputmyInput the input name that will be displayed outside the group is myInput.
 * Focus Inside a Group
 * Focus Back to the Root Level

=Comment= Piece of script that doesn't do anything and is just for clarification of the code. A comment can be made by starting the line with a # symbol.

=Changing Knobs=

Get the name of a knob
Hover your mouse over the knob you want to know the name of.

Set Value on a Knob
a.knob('b').setValue(c) a is the node name. This can be a hard coded node name or a variable storing a node name. b is the name of the knob you want to target. c is the value that the knob has to take. When it's a knob with a drop-down list it will pick according to the list number so 0 will be the first thing in the list and 1 the second etcetera. Example: FrameHold1.knob('first_frame').setValue(10)

Sometimes knobs take an array of multiple values like a 2d position knob. To set different values for x and y you should set the value to an array. Example: n = nuke.selectedNode n.knob('translate').setValue([1,2]) Here the translate knob is an array of two float values so in the setValue command an array is inputted as argument.

for in loop
This is a python script to loop trough a piece of code until it's executed for everything within the loop. This can be used to change a knob on a lot of nodes at once: for i in nuke.selectedNodes: i.knob('Choose a knob here').setValue(Choose a value here) To change all the bounding boxes of multiple merges to B for example: for i in nuke.selectedNodes: i.knob('bbox').setValue(3)

Set expression on a knob
a.knob('b').setExpression(c) a is the node name. This can be a hard coded node name or a variable storing a node name. b is the name of the knob you want to target. c is the Expression that the knob has to take. Example frameholdcam.knob('first_frame').setExpression(frameholdimg.knob('name').value+'.knob.first_frame') frameholdimg.knob('name').value is the way of targetting a soft coded node from within the expression editor.

Change the color of a node
NodeName.knob('tile_color').setValue(colorcode) for the color of the locator use NodeName.knob('gl_color').setValue(colorcode)

Get the colorcode of a node
You can use the get value function to print the color code print nuke.selectedNode.knob('nameOfTheKnob').getValue Example print nuke.selectedNode.knob('tile_color').getValue

Get a default color
In preferences-->Node Colors you can find all the default colors. Then you can just drag and drop the color from the top left corner of the color panel to a node you want to change the color of.

Change the label of a node
nodeName.knob('label').setValue('label text')

User Knobs
User knobs are created seperately from the node itself. Example: n = nuke.createNode('NoOp') k = nuke.Array_Knob('knobName','knobLabel') n.addKnob(k) k.setTooltip('this is my tooltip') This will make a NoOp and attach an Integer User Knob to it.
 * knobName here is the name of the knob. Note: this has to be unique!
 * knobLabel here is the knob label. This can't contain any reserved words or symbols!
 * 'this is my tooltip' This string will be the tooltip for the knob. The tooltip is assigned to the knob seperately.

=Timeline=

Current Frame
To call the current frame: nuke.frame

=Callbacks= A callback is a function that is being called when a certain event happens. All nuke python callbacks can be found in the manual. Syntax: nuke.addCallback(callable, args=,kwargs=,nodeClass='*') Some callbacks can be created within nodes. For example the write node and the project settings have a python tab. There you can put scripts to execute on a certain event.
 * Where CallBack is the type of callback like on node creation for example.
 * callable is a python function.
 * args= This is where you put the arguments of the function you want to call so not after the function itself!
 * kwargs key word arguments. So this is where the key word arguments of the function have to be placed if there are any.
 * The last argument of the addCallBack defines the node class. This will be the node class where the callback takes effect. For example when this is 'Blur' and the callback is on creation the callback will occur only when a blur node is created. The star means that it will be occur when any node is created.

On Create
Example: nuke.addOnCreate(nuke.message, args=('Ok, you have created a Write node'), nodeClass='Write') After executing this a message will appear every time you create a write node. Note that the callback function doesn't use positional arguments only keyword arguments. Since the callable function doesn't take keyword arguments in this example we can just skip it since position of arguments in the callback itself doesn't matter.

The knobChanged knob
Example with using the nuke interface: This will print hello whenever anything changes to the node like it's position or label. Example using the script editor: n = nuke.createNode('NoOp') n.knob('knobChanged').setValue("print 'hello'") This will do the same thing. Note that the command is within quotes as the argument of the setValue function. When using quotes in your script you need to put it within more quotes. Like here hello is in single quotes so the argument has to be between double quotes. Example activate a floating point slider based on a checkbox: nuke.thisNode.knob('knobChanged').setValue(c = nuke.thisNode.knob('c').value p = nuke.thisNode.knob('f') if c == True:   p.setEnabled(True) else:    p.setEnabled(False) ) Now the slider will only be available when the checkbox is ticked. This will be checked everytime anything changes in the node. Note that this wouldn't work with getValue because that function returns 1.0 or 0.0 for boolean variables!
 * 1) Create No-Op
 * 2) Right click in the properties and select manage user knobs.
 * 3) add a python custom
 * 4) give it any name or label.
 * 5) In the script tab put: nuke.thisNode.knob('knobChanged').setValue(print "hello")
 * 1) Create a No-Op and give it a floating point slider and a checkbox. (here called f and c)
 * 2) Create a python custom in the No-Op

Example using a pulldown choice to make presets: low high max custom nuke.thisNode.knob('knobChanged').setValue(  f = nuke.thisNode.knob('f') p = nuke.thisNode.knob('p').getValue k = nuke.thisKnob if p == 0:   f.setValue(0.1) elif p == 1:    f.setValue(0.9) elif p == 2:    f.setValue(1) else:    pass if k.name=='f':    nuke.thisNode.knob('p').setValue(3) else:    pass  ) So here we use getValue in the p variable which returns the index of the list items. value would return the names. The thisKnob function returns the knob that is being changed here. So in the make slider changeble part this is used to check if the user is trying to change the slider if yes it will set the preset to custom which is the pass after the else so the value can be freely adjusted.
 * 1) make a pulldownchoice called p with the following in the menu items:
 * 1) make a floating point slider called f
 * 2) make a custom python.
 * 3) Add the following custom python script:
 * 1) define variables
 * 1) make presets
 * 1) make slider changeable after setting preset

Write Node Callbacks
In the python tab of the write node you can put scripts for a callback. import nuke def finish: nuke.message('your render has finished') import renders nuke.knobDefault('Write.afterRender', 'renders.finish') So the knob is called afterRender the second argument is what to change the knob to (see change default knobs). So you first load the module we just made and then use it. This will make sure that whenever you open nuke the write node will have this callback. This is a very useful concept for automating the pipeline.
 * Example make a script to call back and put it as a default:
 * 1) Create a renders.py file in the .nuke folder containing:
 * 1) Add the following to the menu.py:

=Working with files=

get the directory
w = nuke.toNode('Write1').knob('file').getValue print w This will print the current path where a write node is writing to.

get the directory without the file itself
Now you need to use the os module. import os w = nuke.toNode('Write1').knob('file').getValue print os.path.dirname(w)

get just the file
import os w = nuke.toNode('Write1').knob('file').getValue print os.path.basename(w)

Make folders
Using the os module: os.mkdir(dir) Where the argument should be the path with the new folder described. This function can only create one folder. If you want to create multiple folders you can use this: os.makedirs(dir) If you try to create a folder that already exists you will get an OSError.

check if a folder already exists
try: os.stat(dir) except: os.mkdir(dir) This will first try to check the stats on the folder. If this gives an error (because the folder doesn't exist) it will create the folder. If it doesn't give an error it won't.

Rename Folders
Example: os.rename(dir, dir+"2") This will add 2 to the folder name. So the first argument of the function is the directory of the folder and the second is the same but the folder should have the new name.

Print folder contents
print os.listdir(dir) Here dir is the folder you want to see the contents of. This will print the contents of a folder as a list.

Delete Folders
Syntax: os.rmdir(dir) Where dir is the directory of the folder you want to remove. Note that this function can only remove empty folders otherwise it will give you an error. When there are contents that were in the folder in the trash the folder is still not considered empty!

=Modules= Modules are packages of functions, in nuke you can import python modules and nuke modules. You can also work with modules you made yourself and put in an accesible folder. You can look for all the python modules in the python documentation. You can get info about every python module or functions of the module with the following command: print help(module or function name)

Most Relevant Build-In Python Modules
All of these need to be imported first to take effect.

sys
print sys.platform This will show you the type of platform you are working on according to python.

platform
This module can get information about the machine you are working on.

time
This model is useful for getting time information about the system like the date. print time.localtime This will print a dictionary containing time information.

colorsys
This module is helpful when converting rgb to hsv for example.

copy
This is useful when you want to copy files in the OS. For example you can copy a render over to all the desired places without the need of re-rendering to different write nodes.

email
This module can sent e-mails. So it can be useful if you want to notify people if a render is finished for example.

fraction
This can help round numbers down. It's useful when you are dealing with too long floating point number.

os
Operative System related functions. It can create folders and delete them for example. The os.path sub-module is very important too.

re
regular expressions This has useful functions for handling complex units of information. import re myVar = 'hello world I am here!' print re.split(' ',myVar) This function can split a string into list items. Where the first argument in the symbol to split on and the second the string to split. *re.match import re for node in nuke.allNodes('Group'): if re.match(, node.name): node['disable'].setValue(True) This function can check things.
 * re.split
 * 1) Result: ['hello', 'world', 'I', 'am', 'here!']

random
Can create pseudo random numbers. import random print random.random This will print a random number between 0 and 1. To get different kind of numbers it can be combined with mathematical operations.

strings
This module can manipulate strings in all sorts of ways.

stringsIO
This can write or read information on the harddrive.

zipfile
This can compress files to zip from python.

shutil
Another tool for handling files in directories.

=Gizmos=

Convert Gizmo to a group
Gizmos can only be used when installed. So other computers that open your script can't use then. When working in larger facilities it can be better to convert gizmos to a group since groups can be opened without the need of an installed gizmo. Note: This only works when a gizmo is installed.
 * To convert gizmos to a group : right-click the node Edit-->Node-->Group-->Copy Gizmo to Group
 * In the gizmo file you can change the word Gizmo at the top to Group. This way you can import the gizmo and open it as a group.

Version Warning
Within the gizmo file everything before the word gizmo isn't necessary to make the gizmo work. The first line will make sure you get a warning if the version of nuke is different from the version the gizmo was created with. If you don't want this behaviour you can simply remove the first line from your gizmo file.

=Customise Graphic Interface=

Setup Files
Windows 10 default: C:\Users\admin\.nuke In order to change the interface you need a menu.py file and an init.py file the init file will be executed before nuke starts so this is where the paths to the folders need to be specified. This is just the Victor Perez setup you need the two .py files, but you can have another folder structure.
 * 1) Go to the .nuke folder. The location will vary from OS.
 * 1) When in the .nuke folder create a folder for python scrips called python
 * 2) Create a folder for icons called icons
 * 3) Create a folder for gizmos called gizmos
 * 4) If there are none create a init.py file and a menu.py file.

Adding Path to the .nuke Folder Structure
nuke.pluginAddPath('./myPath') Where myPath can be a folder or path to folder from within the .nuke folder. This is reletive to the .nuke folder because we are using ./ This will make a folder accesable to nuke. For example to setup the files described above: nuke.pluginAddPath('./icons') nuke.pluginAddPath('./python') nuke.pluginAddPath('./gizmos')

Customising the menu.py script
Changes in the menu.py script will only take in effect after restarting nuke.

Import Modules
On top in the menu.py you want to import the modules you are going to use like nuke, nukescripts, math. You can also import custom modules from your python folder (or other accesible folder) now. For example the Victor_Toolset. Remember that a module is a combination of functions so you can write a module yourself in a .py file defining functions that can be called in nuke when you import it in the menu.py. Example: import nuke import Victor_Toolset

Add Format Resolution Preset
You can add a custom format that then will always be accesible in nodes like the reformat. nuke.addFormat('1 2 3 4 5 6 7.0 presetName') Note that there are very strict naming conventions. You have six interger numbers then a float number then a string name all divided by spaces. The first two numbers are the width and the height of the format. The next four numbers specify the size of the format. Usually you want that the be the same, then you put 0 0 width height The last number (the float) will specify the aspect ratio so 1.0 usually, but 2.0 for anamorphic. Example: nuke.addFormat ('1920 797 0 0 1920 797 1.0 FullHD_Widescreen')

add LUT to the root
Syntax: nuke.root.knob('luts').addCurve('nameOfTheLUT', 'formula') Example sLOG formula: '{pow(10.0, ((t - 0.616596 - 0.03) /0.432699)) - 0.037584}'

customise menu items from Nodes toolbar
nuke.menu('Nodes').addCommand('Channel/Shuffle', 'nuke.createNode("Shuffle")', 'ctrl+shift+alt+j', icon='Shuffle.png') This will set a hotkey for the Shuffle node to ctrl+shift+alt+j With this method you can also change the command that is executed when making a shuffle node and the icon for the node. With this command we navigate to the toolbar which is referred to as Nodes then to the sub-menu Channel and then to the desired node. nuke.menu('Nodes').findItem('Channel').findItem('Shuffle').setShortcut('j') nuke.knobDefault('nodeClass.knob','value') Where the nodeClass is the node class like Blur or Merge2 knob is the knob you want to change the default value of and value the new default value. Note that both arguments are strings!
 * If you just want to change the shortcut:
 * If you want to change a node default:

Add an Item to a Sub-Menu in the Top Menu
nuke.menu('Nuke').findItem('Edit/Node').addCommand('myMenuElement', 'myPythonScript.myFunction', 'myHotkey') You can also create a new menu by putting the new menu name before the new item name with a foward slash. Example: nuke.menu('Nuke').addCommand('V!ctor/Preset Backdrop', 'Victor_Toolset.presetBackdrop', 'alt + ctrl + b') Or use the addMenu function: menubar = nuke.menu("Nuke") tbmenu = menubar.addMenu("&Thinkbox") tbmenu.addCommand("Submit Nuke To Deadline", DeadlineNukeClient.main, "") When using the addMenu function it's easier to add multiple things because you can store the new menu in a variable.
 * Here the nuke.menu function has 'Nuke' as an argument this means it's targeting the top menu bar if you want the toolbar you use 'Nodes' as your argument.
 * The findItem function takes the argument 'Edit/Node' here which means it is navigating to the Edit sub-menu and then the Node sub-menu within that.
 * The addCommand takes 3 arguments (all strings):
 * 'myMenuElement' here refers to the name of the new item. This will be the thing to select in your menu.
 * 'myPythonScript.myFunction' This can refer to a custom python script and a function that is defined within that script. It's basically the python code that has to be executed when clicking on the new menu-item in nuke.
 * 'myHotkey' Here you specify the hotkey to launch your script.

Adding a Gizmo
The .gizmo file should be in a place that can be found by nuke like a gizmos folder that is added in the init.py file, just like the icon file in an icons folder. Example: toolbar = nuke.menu('Nodes') myMenu = toolbar.addMenu('V!ctor', icon='V_EdgeMatte.png') myMenu.addCommand('V_EdgeMatte','nuke.createNode("V_EdgeMatte")','r', icon='V_EdgeMatte.png')
 * Note: We're using a few variables here this is a bit of a nices way and with this method you can easily acces created menus to add more items. Watch out you don't overwrite variables that are needed later in the menu.py script!
 * Note: We are tagetting the toolbar here because we are using 'Nodes' as the argument for the nuke.menu function. So 'Nodes' for the toolbar and 'Nuke' for the top menu bar.
 * Note: You don't need to put .gizmo in the argument for the nuke.createNode command! Unless you're gizmo has the same name as a default node then you'll need to add .gizmo to force nuke to take the gizmo and not the native command!!!

Debugging
When there is an error in the menu.py or the init.py nuke won't be able to boot. It will give you a pop-up to tell you there is an error. When you then click show details it will show you the python error. To avoid errors it's good practice to add things one by one and check if nuke boots in between.

=Scripts=

Change all bounding-boxes to B
for i in nuke.selectedNodes: try: i.knob('bbox').setValue('B') except: pass

Turn read file off for all write nodes
for i in nuke.allNodes: if i.Class == "Write": i.knob('reading').setValue(0)