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 createNode use optimized OpenMaya API

  • Extensible 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

maya.cmds

maya.api.OpenMaya

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.