Nodes/Avatar Graph/Transform Shape Key
ComfyUI Node

Transform Shape Key

Hand-sculpting a blink or a mouth shape without opening Blender

By avatechai·Created 3 years ago·Updated 2 years ago· 264
Transform Shape Key
  • bpy_objs
  • bpy_objs
shape_key_nameEyeBlinkLeft
target_vertex_groupGroup
scale_x1.00
scale_y1.00
offset_x0.00
offset_y0.00
rotate0.00
origin_offset_x0.00
origin_offset_y0.00
transform_radius1.00
falloff0.00

This is the node that actually gives your Avatar Graph rig an expression. Everything else in avatech.ai's pack - segmentation, mesh cleanup, UV work - is prep; this is where a flat mesh region turns into a named, driveable shape key like a blink or a mouth pose. The README's own node table describes this family as "given shape key name & target vertex_group, modify the vertex / all vertex's transform" - that's exactly what this does, with a full set of transform controls exposed as node parameters instead of Blender's shape-key sculpting tools.

How it works

A shape key in Blender (and in most avatar/VRM rigging conventions) is a named, blendable deformation of a mesh - 0% is the base shape, 100% is the deformed target, and something at runtime (audio level, a blink trigger, a MediaPipe blend-shape value) drives the blend between them. This node builds that target shape by applying a 2D transform - scale, offset, rotation - to a specific vertex group, and saving the result under a shape key name. Instead of manually pushing vertices around in Blender's sculpt mode, you're describing the deformation numerically: "scale this vertex group down on the Y axis and offset it slightly" becomes an eyelid closing.

The inputs that matter

There's a lot here, but three names do most of the work:

  • shape_key_name (default "EyeBlinkLeft") - the name this deformation gets saved under. That default is a strong hint about the pack's intended use: it matches common blend-shape naming conventions used by facial-tracking systems, so a shape key you build here can plug straight into a live tracking pipeline downstream.
  • target_vertex_group (default "Group") - which vertex group this transform applies to. This has to match a group name you've already defined upstream (via a vertex-group-assignment node elsewhere in this pack) - get the name wrong and the transform silently has nothing to act on.
  • scale_x / scale_y, offset_x / offset_y, rotate - the actual deformation, each ranging roughly ±10 (rotate ±360, in degrees) with a 0.01 step for fine control. This is where you dial in "eye closes" or "mouth opens."

Rounding it out: origin_offset_x / origin_offset_y shift the pivot point the transform rotates and scales around (so a squash doesn't happen from the wrong center), and transform_radius with falloff control how far the deformation reaches and how softly it blends at the edge of the vertex group, so you don't get a hard crease where affected vertices meet the rest of the mesh.

Input and output are both BPY_OBJS - plural, unlike most nodes in this pack - meaning this one operates on a list of Blender objects rather than a single one.

Installing it

ComfyUI Manager: search avatar-graph-comfyui. Manual install:

cd ComfyUI/custom_nodes
git clone https://github.com/avatechai/avatar-graph-comfyui
cd avatar-graph-comfyui && python -m pip install -r requirements.txt

This is a bpy-backed node like the rest of the pack's mesh tooling, which means the same hard constraint applies: Python 3.10.x only. Use the README's prebuilt Python 3.10 ComfyUI zip on Windows, or a dedicated conda create --name comfyui python=3.10 environment on Mac/Linux, rather than trying to install this against a newer Python. Restart with --enable-cors-header afterward for the live avatar preview panel.

Troubleshooting

If a transform produces no visible change, check target_vertex_group first - a name that doesn't match an existing group means there's nothing for the transform to affect, and this fails silently rather than erroring. If a blink or mouth shape looks like it has a hard, ugly seam at its edge, that's falloff doing too little (or transform_radius too small) - soften the falloff before increasing scale or offset further. And because rotate here is in degrees while several other rotation fields in this pack (UV randomization, for one) use radians, don't assume the units carry over between nodes - check the range shown on each field.

Categorymesh

Inputs (12)

NameTypeDefaultDescription
bpy_objsBPY_OBJS
shape_key_nameSTRINGEyeBlinkLeft
target_vertex_groupSTRINGGroup
scale_xFLOAT1.00-10–10
scale_yFLOAT1.00-10–10
offset_xFLOAT0.00-10–10
offset_yFLOAT0.00-10–10
rotateFLOAT0.00-360–360
origin_offset_xFLOAT0.00-10–10
origin_offset_yFLOAT0.00-10–10
transform_radiusFLOAT1.000–1
falloffFLOAT0.00-10–10

Outputs (1)

NameTypeDescription
bpy_objsBPY_OBJS