Maya & Python Scripting / Maya / Python
Expanding on the Face Control with Python in Maya
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 reusable control builder becomes useful when it can place several related controls without giving each one a different implementation. This lesson takes the existing single face-control widget and lays out a small facial interface: paired brows, eyes, and nose controls, plus a centered mouth control.
The controls can move individually by the end of the recording, but they do not yet drive facial deformation. The surrounding frame, character label, and blendshape integration are deferred. The exact Maya release is not identified, and the lesson assumes the earlier control-building function and grouping structure already exist.
Separate the widget builder from the face layout
At 00:00–02:01, the instructor introduces a face-controller function whose job is to call the existing widget builder several times. The first call creates a left-brow control. An initial test does nothing until the new layout function is actually called.
This gives the code two responsibilities. The lower-level function creates one consistent control. The layout function decides which controls the face needs and where they should sit. Keeping those decisions separate avoids copying the entire widget construction just to change a name or position.
Test one layout call first. Confirm that it creates the expected named widget before adding all the other facial regions. If the function has only been defined, it has not yet performed any scene operation; the explicit call is part of the workflow.
Place the zero group with X and Y arguments
During 02:01–04:04, the widget builder receives X and Y position arguments. The lesson uses the zero group returned by the existing grouping work and sets that group’s tx and ty values from the arguments.
The important target is the placement group. It locates the widget in the overall interface while allowing its child control to keep the neutral values established by the earlier builder. Offsetting the animator-facing control directly would mix initial layout with later animation input.
The first position is tested with small values, then adjusted to fit the size of the existing widget. The left-brow placement settles at negative 1.5 in X and positive 1.5 in Y. These are interface layout units in the example, not positions on the character’s facial mesh.
Repeated testing exposes a limitation: creating the same named controls on top of an existing layout causes problems. The instructor clears the test controls before rebuilding. The lesson does not implement replacement, duplicate detection, or safe in-place updates for an existing face interface.
Build paired rows with consistent spacing
At 04:04–07:02, the right-brow call mirrors the layout position across the interface, using positive 1.5 in X at the same height. The eye calls are copied from that pair and moved downward through several placement tests.
The final eye row uses Y at negative 1.5, leaving three units between the brow and eye rows. The instructor arrives at this by viewing the result and adjusting the arguments. The useful principle is consistent row spacing that accounts for the actual widget size, rather than assuming an arbitrary position will leave enough room.
Check both the visible spacing and the names after duplication. A correctly positioned right-hand widget with a left-brow name is still an incorrect layout call for later routing code. Conversely, correct names do not prevent widgets from overlapping if their positions were not updated.
The left/right labels in this lesson describe the chosen interface arrangement and naming convention. The recording does not establish a universal rule for whether character-left should appear on screen-left or screen-right.
Add nose controls and a centered mouth row
During 07:02–09:00, the instructor considers a single nose control but chooses left and right nose widgets for the expressions available and possible future targets. Their X positions remain negative and positive 1.5, and the row moves to Y at negative 4.5.
The mouth is centered at X zero and placed at Y negative 7.5. This continues the three-unit vertical spacing. The recorded layout can be summarized as:
| Region | X positions | Y position |
|---|---|---|
| Brows | -1.5 and +1.5 | +1.5 |
| Eyes | -1.5 and +1.5 | -1.5 |
| Nose | -1.5 and +1.5 | -4.5 |
| Mouth | 0 | -7.5 |
These values are an example for the existing widget dimensions. If the widgets change size, review the spacing again. The source does not demonstrate automatic layout measurement or collision detection.
Verify the interface layer before connecting expressions
At 09:00–09:26, the instructor confirms that the controls move individually and explicitly notes that they do not do anything to the face yet. The next proposed steps are a surrounding box, a character-specific label, and integration with the expression setup.
Finish this stage by checking seven distinct controls, their names, their row spacing, and the separation between placement-group values and the child controls’ movement. Test a clean rebuild from the expected starting state as the lesson does.
A working layout is a useful result on its own: later code can route expressions to predictable named controls. It does not yet establish the attributes, driven keys, or deformation connections those controls will eventually use.