Why tik.maya?¶
Maya scripting with maya.cmds is powerful but has pain points that compound in
larger projects. tik.maya addresses these directly while maintaining Maya’s flexibility.
The Problem with maya.cmds¶
String-based node references break easily
# Using maya.cmds
import maya.cmds as cmds
cube = cmds.polyCube(name="myCube")[0]
cmds.setAttr(f"{cube}.translateX", 5)
# If something renames the node...
cmds.rename(cube, "renamedCube")
# Your reference is now broken
cmds.setAttr(f"{cube}.translateX", 10) # Error! "myCube" doesn't exist
Verbose, repetitive code
# Lock and hide attributes requires multiple calls
cmds.setAttr("pCube1.scaleX", lock=True)
cmds.setAttr("pCube1.scaleX", keyable=False)
cmds.setAttr("pCube1.scaleX", channelBox=False)
No type safety
# Typos only discovered at runtime
cmds.setAttr("pCube1.tranlsateX", 5) # Misspelled!
How tik.maya Solves This¶
MObject Tracking with UUID Backup¶
tik.maya tracks nodes using maya.api.OpenMaya.MObject handles for performance,
with UUID as a backup for restoration. References stay valid through renames,
namespacing, and re-parenting.
import tik.maya as tm
cube = tm.resolve("myCube")
cube.translate_x = 5
# Rename works seamlessly
cube.rename("renamedCube")
cube.translate_x = 10 # Still works!
Under the hood, tik.maya uses MObject as the primary handle for speed. If the MObject becomes stale (e.g., after undo/redo), tik.maya reconstructs it from the stored UUID, providing a fast path with a safe fallback.
Flexible Dynamic Wrapping¶
tik.maya’s architecture brings fine-tuning, speed, elegance, and extensibility together through dynamic wrapping:
# Works as a drop-in replacement for maya.cmds
import tik.maya as tm # Instead of: import maya.cmds as cmds
# All cmds functions work automatically
cube = tm.polyCube(name="myCube")[0]
tm.xform(cube, translation=(1, 2, 3))
tm.setAttr(f"{cube}.visibility", 0)
But with key advantages:
Automatic object wrapping: Node-returning commands give you typed objects, not strings
Selective overrides: Performance-critical functions like
createNodeuse optimized OpenMaya APIExtensible design: Add custom behavior without modifying Maya
Zero migration cost: Change your import statement and existing scripts work
# You also get the object-oriented benefits
cube.translate = (5, 6, 7)
cube["visibility"].value = False
cube["visibility"].locked = True
# And mathematical operators for dependency networks
driver = tm.spaceLocator()[0]
(driver["translateX"] * 2.0 + 5) >> cube["translateY"]
This flexible structure means you can migrate gradually — use tm.polyCube() just
like cmds.polyCube() when convenient, or embrace the object-oriented API when it
makes sense. See the snippets/comparisons/08_cylinder_rig/ example to see how an
entire rigging script works with just an import change!
Concise, Readable Code¶
# Lock and hide in one line
cube["scaleX"].locked = True
cube["scaleX"].visible = False
# Or batch operations
for attr in ["scaleX", "scaleY", "scaleZ"]:
cube[attr].locked = True
cube[attr].visible = False
# Connect with operators
driver["translate"] >> cube["translate"]
Pythonic and Type-Safe¶
# Properties for state, methods for actions
cube.visibility = False
cube.freeze(translate=True, rotate=True)
# Automatic type resolution
mesh = tm.resolve("pCubeShape1") # Returns Mesh
joint = tm.resolve("joint1") # Returns Joint
# IDE autocomplete and type hints work
cube. # Shows: translate, rotate, freeze(), snap_to(), etc.
Procedural Math Networks¶
Build dependency graphs using Python operators:
driver = tm.Transform.create(name="driver")
follower = tm.Transform.create(name="follower")
# Arithmetic creates and connects utility nodes automatically
(driver["tx"] * 2.0 + 5) >> follower["ty"]
Side-by-Side Comparison¶
Connecting attributes:
# maya.cmds
cmds.connectAttr("driver.translateX", "driven.translateX", force=True)
cmds.connectAttr("driver.translateY", "driven.translateY", force=True)
cmds.connectAttr("driver.translateZ", "driven.translateZ", force=True)
# tik.maya
driver["translate"] >> driven["translate"]
Creating and positioning:
# maya.cmds
loc = cmds.spaceLocator(name="myLocator")[0]
cmds.setAttr(f"{loc}.translate", 1, 2, 3, type="double3")
# tik.maya
loc = tm.Locator.create(name="myLocator")
loc.transform.translate = (1, 2, 3)
When to Use What¶
Use tik.maya when:
Building tools that manipulate scene objects
Writing rigging scripts needing reliable references
You want maintainable, readable code
Consider raw API when:
Performance-critical inner loops (though tik.maya is fast)
Operations tik.maya doesn’t wrap yet
Note
tik.maya and cmds coexist. Use node.name to pass tik.maya objects
to cmds functions.
Summary¶
Pain Point |
|
|
tik.maya |
|---|---|---|---|
Node references |
Strings — break on rename |
MObject/MDagPath handles — robust |
MObj/UUID-backed — survives renames |
Code verbosity |
Multiple calls per operation |
Verbose boilerplate (fn sets, plugs) |
Concise properties and methods |
Performance |
Moderate |
Fastest (No Undo / Not crash safe) |
Fast (With Undo support and more stable) |
Type safety |
None — errors at runtime |
Stronger typing via API classes |
IDE completion, type hints |
API style |
Procedural, flag-heavy |
Low-level, explicit, handle-based |
Pythonic, object-oriented |
Debugging |
String matching errors |
Object inspection via function sets |
Object inspection, clear errors |
tik.maya combines the simplicity of maya.cmds with the robustness of
maya.api.OpenMaya, wrapped in a Pythonic interface. Write less code,
catch errors earlier, and stop worrying about node names.