Character FX & Animation / Maya / Python
Adding Attributes to Controls
Written guide

Playing loads YouTube content. YouTube processes data after activation.
Watch on YouTubeIf the player is blocked or unavailable, use Watch on YouTube.
A face rig needs an interface that reflects the expressions available on the character. This lesson builds that interface from the names of imported blendshape targets: mouth shapes become attributes on the mouth control, and sided brow, eye, and nose shapes are routed to their corresponding controls. The result is a set of visible, bounded animation channels. Connecting those channels to deformation is a later step.
The workflow combines the series’ existing face-controller builder and blendshape importer. It assumes their object names and filename convention already agree. The recording does not establish an exact Maya release, and its incremental code edits are not a complete, independently tested rigging package.
Create the control interface once, before processing targets
At 00:00–04:01, the instructor brings the two earlier scripts into one face-rig function. One part imports the expression geometry; another creates the controls on which attributes will live. Their order matters more than simply placing both functions in the same file.
Create the controller layout before entering the loop that handles individual blendshape files. A controller-creation call inside that loop would build a fresh layout for each target. A call after the loop leaves the controls unavailable when the loop tries to add attributes. The intended dependency is therefore: establish the character/control names, build the controls once, then process the targets and extend those existing controls.
The recording tests this assembly in a cleared scene and fixes a missing colon before moving on. Keep this initial test narrow: confirm that importing still works and that only one control layout appears. Attribute routing is harder to diagnose if the scene already contains duplicate controllers or remnants from an earlier run.
Turn a filename into an attribute name and a routing decision
The first parsing experiments begin around 04:02. Splitting a target name on underscores produces a list of tokens. The first token identifies the facial region, such as mouth or nose. Later, around 15:00–17:01, the script retains the whole token list so that its last token can also identify a side.
There are two distinct outputs here. An attribute name needs the meaningful target name without the file extension. Routing needs access to the region and, for sided targets, the side token. Keeping those responsibilities separate prevents a common mistake seen during development: replacing the token list with only its first element, then discovering there is no list left from which to read the side.
The lesson removes the extension by splitting on a dot and taking the first part, then splits the remaining name on underscores. That is a project-specific filename assumption. It does not demonstrate handling names with extra dots, inconsistent separators, namespaces, or absent side tokens. Before processing a library, inspect representative filenames and check that the chosen convention actually describes them.
Capitalization also matters to the demonstrated comparisons. A condition written for Mouth will not match a differently capitalized token. Printing the parsed results before creating attributes makes a mismatch visible at the point where it starts, instead of leaving an apparently empty control later.
Define a useful channel, then verify that it is visible
At 06:01–14:02, the instructor creates an attribute manually, inspects Maya’s command history, and translates that operation into the script. The intended channel is a floating-point value with a default of zero, a minimum of zero, and a maximum of one. This gives each expression a neutral state and a bounded full-strength endpoint.
Several errors establish which parts of the command need attention. The default-value flag is corrected to defaultValue; the target extension must be removed because it introduces invalid characters into the proposed attribute name; and the destination control must be selected before the demonstrated selection-dependent addAttr call. A typo in the attribute-name variable is a separate Python problem, not a naming-rule failure in Maya.
Successful execution alone does not establish that an animator can use the channel. In the recording, the attributes exist but are initially absent from the Channel Box. Adding keyable=True makes the intended channels available there. The accidentally entered maximum of zero is then corrected to one: a channel constrained to the same minimum and maximum cannot provide the intended expression range.
For each representative attribute, check three things independently: it belongs to the intended control, it appears in the Channel Box, and its value can move from zero to one. These checks distinguish node selection, visibility, and numeric-range problems. None of them proves that the value drives a blendshape yet.
Route sided targets using the final name token
Around 14:03–19:00, the lesson extends the mouth case to the brows. Under this naming convention, the side is the final underscore-separated token. Python’s -1 index retrieves that last token without requiring every target name to contain the same number of descriptive words.
The script checks the facial category and then the side, selects the matching right or left brow control, and adds the corresponding attributes there. The instructor first verifies the right-side group, then duplicates and adjusts the logic for the left. Testing one side before copying it makes it easier to separate parsing errors from mistakes introduced during duplication.
Treat “left” and “right” as character naming conventions, rather than inferring them from the controller’s position on screen. The recording raises a possible screen-side arrangement change but does not resolve it in this lesson. Check actual object names and target membership before changing signs, swapping labels, or moving controls to compensate for a perceived reversal.
Extend the routing without losing destination ownership
At 19:00–23:01, cheek attributes are deliberately placed on the mouth control. That is an interface choice for this rig, not a universal anatomical grouping. Eye and nose handling is then adapted from the brow blocks, with the relevant category and destination names changed.
The instructor uses a separate Python tab and search-and-replace to duplicate similar blocks. This is quick, but every copied block still needs a destination check. A category test may be correct while its selection statement still points to the previous region’s control. Inspect the finished control layout and confirm that each imported target produced its channel in the intended location.
A parameterized helper is mentioned as a possible way to reduce repetition, but it is not implemented here. The demonstrated result remains a series of explicit routing cases. Keep that distinction when following the lesson: a suggested refactor is not evidence that a reusable dispatcher or a complete naming validator already exists.
Check the attribute layer before adding motion
The final discussion, 23:01–25:25, explores future mappings between controller movement and expressions. Opposing expressions, brow directions, and missing target shapes will require additional decisions. These are plans for later rig behavior, not completed connections in this recording.
Finish this stage with a neutral interface inspection. Confirm one controller layout, the expected expression channels, correct side and region placement, zero defaults, and usable zero-to-one limits. Repeat the build only in the controlled test setup used for the lesson; the demonstrated script does not establish safe handling of existing attributes or arbitrary previously built rigs.
Moving an attribute without changing the face is expected at this checkpoint. The lesson has created the controls’ vocabulary. A later connection layer must translate those values into blendshape weights or other motion, and that layer needs its own endpoint and neutral-state checks.