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:

=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=

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')

=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)

=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)

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

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: ''' 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 nuke.thisNode.knob('knobChanged').setValue(

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.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.

=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