Examples
This section provides practical code examples for working with the Hive Rigging system. These examples demonstrate common workflows and patterns used by programmers and character riggers.
Getting Started
Basic Rig Creation
The following example shows how to create a new rig instance and initialize it for use:
from zoo.libs.hive import api
# Create an empty rig instance
character = api.Rig()
# Initialize the rig with a name (creates or finds existing rig in scene)
character.startSession("myCharacter")
# The rig is now ready for component creation and manipulation
Note
The startSession() method will either create a new rig or connect to an existing
rig in the current Maya scene, depending on whether a rig with the specified name already exists.
Working with Components
Component Creation and Management
Components are the building blocks of a Hive rig. Here’s how to create and manage them:
from zoo.libs.hive import api
# Initialize rig
character = api.Rig()
character.startSession("myCharacter")
# Create components (without building guides or rig yet)
godNode = character.createComponent("godnodecomponent", "godnode", "M")
leftArm = character.createComponent("vchaincomponent", "arm", "L")
# Access component registry to see all available component types
registry = character.configuration.componentRegistry()
availableComponents = registry.components # Returns dict of available components
# Get components attached to the current rig
allComponents = character.components() # List all components
specificComponent = character.component("arm", "L") # Get by name and side
# Direct access using dot notation (convenient shortcut)
character.arm_L == leftArm # True
character.godnode_M == godNode # True
Tip
Components are identified by their type (e.g., “vchaincomponent”), name (e.g., “arm”), and side (“L”, “R”, or “M” for left, right, or middle/center).
Working with Templates
Template Loading Methods
Templates provide pre-configured rig setups that can be loaded and customized. There are two ways to work with templates:
Method 1: Create a New Rig from Template
This method creates a completely new rig instance based on a template:
from zoo.libs.hive import api
# Get the template registry
templateRegistry = api.Configuration().templateRegistry()
# Get the template path by name (as displayed in the UI)
templatePath = templateRegistry.templatePath("allosaurus")
# Create a new rig from the template
rig, createdComponents = api.commands.loadTemplate(
templatePath,
name="MyRigName"
)
Note
You can also provide an absolute file path to a template file instead of using the registry. This is useful for loading templates from network shares or custom locations.
Method 2: Load Template into Existing Rig
This method merges template components into an existing rig:
from zoo.libs.hive import api
# Initialize existing rig
character = api.Rig()
character.startSession("myExistingCharacter")
# Get template path
templateRegistry = api.Configuration().templateRegistry()
templatePath = templateRegistry.templatePath("allosaurus")
# Load template components into existing rig
rig, createdComponents = api.commands.loadTemplate(
templatePath,
rig=character
)
Warning
When loading a template into an existing rig, the existing rig’s configuration (build scripts, naming conventions, etc.) takes precedence over the template configuration. Only the components are merged to avoid conflicts.
Component Mirroring
Mirroring Components
Component mirroring creates symmetric components by duplicating and flipping existing ones. Mirroring should be performed on root components of chains (e.g., clavicle rather than arm), as the system will automatically mirror all child components.
from zoo.libs.hive import api
# Initialize rig
rig = api.Rig()
rig.startSession("myCharacter")
# Define which components to mirror (using tokenized names)
rootComponentNames = {"clavical:L"}
componentsToMirror = []
# Find components to mirror
for component in rig.iterComponents():
if component.serializedTokenKey() in rootComponentNames:
componentsToMirror.append({
'side': 'R', # Target side for mirrored component
'translate': ('x',), # Mirror axis for translation
'rotate': 'yz', # Mirror plane for rotation
'duplicate': True, # Create duplicate vs. mirror in place
'component': component
})
# Execute mirroring
api.commands.mirrorComponents(rig, componentsToMirror)
Tip
translate: Specify which axis to mirror (e.g., (‘x’,) for X-axis)
rotate: Specify the mirror plane (e.g., ‘yz’ for YZ-plane)
duplicate: False mirrors in place, True creates a new mirrored component
Building and Querying Rigs
Building Guides and Rigs
Once components are created and configured, you need to build the guides and then the rig:
from zoo.libs.hive import api
# Initialize rig with components
character = api.Rig()
character.startSession("myCharacter")
# Create components (example)
arm = character.createComponent("vchaincomponent", "arm", "L")
# Build the guide layer first (creates visual guides for positioning)
character.buildGuides()
# Build the rig layer (creates actual controls and joints)
character.buildRigs()
Querying Guide Controls
After building guides, you can query and manipulate them:
# Get all guides from a component's guide layer
guideLayer = arm.guideLayer()
allGuides = guideLayer.iterGuides()
# Get a specific guide by ID (IDs are constant and should never change)
wristGuide = guideLayer.guide("end") # Typically the wrist/end guide
# Query guide properties
wristPosition = wristGuide.translation() # Returns api.Vector
wristRotationLocal = wristGuide.rotation(
space=api.kTransformSpace,
asQuaternion=False
) # Returns api.EulerRotation
wristRotationWorld = wristGuide.rotation(
space=api.kWorldSpace,
asQuaternion=True
) # Returns api.Quaternion
# Get guide data as dictionary (useful for serialization)
guideData = wristGuide.serializeFromScene()
# Get guide hierarchy
parentGuide = wristGuide.parent() # Returns Guide instance or None
Querying Rig Controls
After building the rig, you can access the actual animation controls:
# Get rig controls from the rig layer
rigLayer = arm.rigLayer()
endControl = rigLayer.control("endfk")
uprControl = rigLayer.control("uprfk")
# or riglayer.findControls("endfk", "uprfk")
# Query control properties
controlPosition = endControl.translation()
# Access animation attributes (often on separate nodes)
# For example, IK/FK blending on an arm component
ikfkBlend = arm.controlPanel().ikfk # Returns api.Plug instance
# Access settings nodes (hidden from animators)
settingsNodes = rigLayer.settingsNodes() # List of api.SettingsNode
# Create custom settings
customSettings = rigLayer.createSettingsNode("myCustomSettings")
customSettings.addAttribute(
"myHiddenSetting",
value=10,
default=0,
Type=api.kMFnNumericFloat
)
Querying Deformation Joints
Access the deformation layer for skinning joints:
# Get joints from the deformation layer
endJoint = arm.deformLayer().joint("end")
jointPosition = endJoint.translation()
Accessing Meta Information
Each component and rig has associated metadata:
# Get meta nodes for debugging and advanced operations
print(character.meta) # Rig meta node
print(arm.meta) # Component meta node
print(rigLayer) # Rig layer meta node
# Get the root transform of a component
rootTransform = arm.rootTransform()
print(rootTransform)
Advanced Operations
Matching Guide Transforms to Existing Joints
This technique is useful when you need to update guides to match the position of existing joints in a scene:
from zoo.libs.hive import api
from zoo.libs.maya import zapi
# Iterate through all rigs in the scene
for rig in api.iterSceneRigs():
# Iterate through all components in each rig
for component in rig.iterComponents():
# Get ID mapping between guide and deform layers
mapping = component.idMapping()
deformLayer = component.deformLayer()
guideLayer = component.guideLayer()
# Get the mapping for deform layer
deformMap = mapping[api.constants.DEFORM_LAYER_TYPE]
# Find corresponding joints and guides
joints = deformLayer.findJoints(*deformMap.values())
guides = guideLayer.findGuides(*deformMap.keys())
# Match guide transforms to joint transforms
for guide, joint in zip(guides, joints):
transformMatrix = joint.transformationMatrix()
# Preserve guide scale while matching position/rotation
transformMatrix.setScale(
guide.scale(zapi.kTransformSpace),
zapi.kTransformSpace
)
guide.setWorldMatrix(transformMatrix.asMatrix())
Creating Guides Programmatically
You can create guides dynamically with custom properties:
# Define guide data
guideData = {
"name": "godnode",
"translate": [0.0, 10.0, 0.0],
"rotate": [0.0, 0.0, 0.0, 1.0], # Quaternion rotation
"rotationOrder": 0,
"shape": "godnode", # Shape name from library or custom dict
"id": "godnode", # Internal Hive ID
"parent": arm.guideLayer().guide("mid"), # Parent guide instance
"children": [], # List of child guides
}
# Create the guide
newGuide = arm.guideLayer().createGuide(**guideData)
# Parent components together (arm driven by godnode)
arm.setParent(godNode, godNode.guideLayer().guide("godnode"))
Note
The same creation pattern applies to rigLayer, deformLayer, inputLayer, and outputLayer.
Component Settings
Query Guide Settings
To query guide settings, there are 2 ways depending on your needs: 1. Through the component Definition. This acts as an in-memory cache, it’s not live and gets updated at save time/build time. 2. Through the Scene Node. This is a live representation of the settings.
Example for component definition
# retrieve 1 setting at a time.
hasTwists = arm.definition.guideLayer.guideSetting("hasTwists").value
# retrieve multiple settings at a time
settings = arm.definition.guideLayer.guideSettings("hasBendy", "hasStretch")
hasBendy, hasTwists = settings["hasBendy"], settings["hasStretch"].value
Example for Scene Node
# retrieve 1 setting at a time.
guideLayer = arm.guideLayer()
guideSettingNode = guideLayer.guideSettings()
hasTwists = guideSettingNode.attribute("hasTwists").value()
# retrieve multiple settings at a time
settings = arm.definition.guideLayer.guideSettings("hasBendy", "hasStretch")
hasBendy, hasTwists = settings["hasBendy"], settings["hasStretch"].value
Query Anim Settings
To query anim settings, there are 2 ways depending on your needs: 1. Through the component Definition. This acts as an in-memory cache, it’s not live and gets updated at save time/build time. 2. Through the Scene Node. This is a live representation of the settings.
Anim settings can support creating multiple nodes eg. controlPanel and constants. controlPanel is a reserved name used by hive to determine which attributes are exposed to the animator. While constants or any other name is defined by the developer of the component.
Example for component definition
ikfkDefaultState = arm.definition.rigLayer.setting(api.constants.CONTROL_PANEL_TYPE, "ikfk")
ikfkDefaultState.value
Example for Scene Node
settings = arm.rigLayer().controlPanel()
attr = settings.attribute("ik") # type: zapi.Plug
attr.value()
attr.set(1)
Scene Object Integration
Casting Scene Objects to Hive Objects
Convert Maya scene objects to their Hive counterparts for programmatic access:
from zoo.libs.maya import zapi
from zoo.libs.hive import api
# Iterate through selected objects
for sceneObject in zapi.selected():
# Get the attached component (if any)
component = api.componentFromNode(sceneObject)
# Get the attached rig (if any)
rig = api.rigFromNode(sceneObject)
print("Object: {}".format(sceneObject.name()))
print("Component: {}".format(component))
print("Rig: {}".format(rig))
Component Grouping
Organize components into logical groups for better management:
# Create a component group
character.createGroup("myGroup", components=character.components())
# List all group names
groupNames = character.groupNames()
# Get components in a specific group (returns generator)
groupComponents = character.iterComponentsForGroup("myGroup")
# Remove a group
character.removeGroup("myGroup")
Command Line Operations
Batch Rig Upgrading
This example demonstrates how to upgrade Hive rigs using Maya’s batch mode (mayapy), which is useful for automated pipeline workflows:
Command Line Usage
First, set up the environment and run the upgrade script:
# Windows
set MAYA_MODULE_PATH=zootoolspro/install/core/extensions/maya
set ZOO_LOG_LEVEL=DEBUG
mayapy.exe upgrade_hive_rig_cli.py --scene my_rig_scene.ma --outputPath my_rig_scene_upgraded.ma
# Linux/Mac
export MAYA_MODULE_PATH=zootoolspro/install/core/extensions/maya
export ZOO_LOG_LEVEL=DEBUG
mayapy upgrade_hive_rig_cli.py --scene my_rig_scene.ma --outputPath my_rig_scene_upgraded.ma
Upgrade Script
The complete upgrade script is available in the resources directory:
import argparse
import contextlib
def parseArguments():
parser = argparse.ArgumentParser("Hive",
description="Provides a script to upgrade a hive rig which resides within maya "
"scene")
parser.add_argument("--outputPath", type=str, required=True, help="Output path for the upgrade rig file.")
parser.add_argument("--rigName", type=str, required=False, help="The name of the rig in the scene, defaults to "
"finding the first rig in the scene.")
parser.add_argument("--scene", type=str, required=True,
help="The Maya scene path to load")
return parser.parse_args()
def upgradeRig(rig):
"""Does the actual labour of rebuilding the rig, relies on the current scenes cached rig definition.
We always go back to the guides which updates the rig definition merging new updates from the base components
before user modification. Before we delete the control rig(maintaining joints and deformation) then we polish
the rig for final output.
:param rig: The Hive rig instance to upgrade.
:type rig: :class:`api.Rig`
"""
rig.buildGuides()
rig.deleteRigs()
rig.polish()
def findRigInstance(name=None):
"""Find the first occurrence of a hive rig which matches the give rig name.
:param name: The rig name to find in the scene.
:type name: str
:return:
:rtype: :class:`api.Rig`
"""
from zoo.libs.hive import api
if name:
rigInstance = api.rootByRigName(name)
if rigInstance is not None:
r = api.Rig(meta=rigInstance)
r.startSession()
return r
raise api.HiveError("No rig in the scene with name: {}".format(name))
rigs = list(api.iterSceneRigs())
if not rigs:
raise api.HiveError("No rigs in scene")
return rigs[0]
@contextlib.contextmanager
def initializeContext():
from maya import standalone
standalone.initialize(name="python")
try:
yield
finally:
standalone.uninitialize()
if __name__ == "__main__":
args = parseArguments()
rigName = args.rigName
outputPath = args.outputPath
sceneFile = args.scene
with initializeContext():
from maya import cmds
cmds.loadPlugin("zootools.py")
from zoo.libs.maya.utils import files
cmds.file(sceneFile, force=True, options="v=0;", ignoreVersion=True, open=True)
rigInstance = findRigInstance(rigName)
upgradeRig(rigInstance)
files.saveScene(outputPath)
Note
The upgrade process: 1. Rebuilds guides from the current rig definition 2. Deletes the existing control rig (maintaining joints and deformation) 3. Rebuilds the rig with updated component definitions 4. Applies polish for final output