Nodes/LF Nodes/Scale GLB Nodes
ComfyUI Node

Scale GLB Nodes

Fix a rigged model's proportions without re-rigging

By lucafoscili·Created 2 years ago·Updated 22 days ago· 36
Scale GLB Nodes
  • glb
  • targets
  • glb
◄percent100►

Generated 3D assets have a house style: slightly big head, slightly short arms, feet that float a centimetre off the ground. If the model is a static prop, nobody cares. If it's rigged and animated, you have a problem - because "just scale the arm" in Blender means editing a joint in a skeleton whose animation channels all reference that joint's transforms, and if you do it wrong the animation explodes.

LF_ScaleGLBNodes scales selected skin joints and their subtrees while leaving every animation track, sampler and inverse bind matrix in the file untouched. That's a specific, narrow, genuinely useful surgery: adjust proportions on an animated rig without breaking the animation.

How it works

The trick is structural rather than mathematical. For each joint you select, it inserts a static child node that carries the uniform scale factor and an anchor offset, hands the old children over to it, and swaps it into skins.joints in place of the original. Because the joint keeps its own animated translation, rotation and scale, and the new child just holds a constant factor, the existing animation channels still drive the joint exactly as before - with everything below it now scaled around the anchor.

The anchor is expressed in the selected joint's local coordinates, and scaling keeps that point fixed under the joint's animated transform. That's what stops a scaled arm from detaching from a shoulder: anchor at the joint origin and the subtree grows outward from where it attaches.

percent applies uniformly to the group. At exactly 100 the original GLB bytes pass through unchanged - a real passthrough, not a re-encode - which is handy for leaving a node in the graph while you're still tuning.

Same self-contained GLB 2 contract as LF_ApplyTextureToGLB: embedded images, one buffer, no external resources.

The inputs and outputs that matter

  • glb - exactly one FILE_3D_GLB. Chained after a texture swap, a loader, or a 3D generator.
  • targets - the JSON recipe. This is the input that takes five minutes to get right:
{"nodes":[{"nodeIndex":4,"nodeName":"joint","anchorLocal":[0,-0.1,0]}],"minPercent":65,"maxPercent":115}

nodeIndex identifies the joint. nodeName is an optional identity check - if the name doesn't match, it refuses rather than scaling the wrong thing. anchorLocal defaults to [0,0,0]. The minPercent/maxPercent bounds are a guard rail: a recipe can't be asked for a factor outside 1–200, and that's checked even at 100.

  • percent - 1 to 200, default 100. The uniform factor for this group.

Output: glb, one in-memory FILE_3D_GLB, ready for a stock 3D viewer, a saver, or another transform. Chain multiple instances of the node to control independent groups separately - head here, arms there - each with its own recipe.

How to install it

ComfyUI Manager → search LF Nodes → install → restart, or:

cd ComfyUI/custom_nodes
git clone https://github.com/lucafoscili/lf-nodes
python -m pip install -r lf-nodes/requirements.txt

Pip with ComfyUI's interpreter. The GLB codecs in this pack are pure Python + Pillow on the texture side - no compiled 3D dependencies, which is genuinely refreshing given that the heavy 3D packs need CUDA extensions built against your exact torch version. You do have to live with the pack's wider requirements list (154 nodes' worth). And the archived-repo warning stands: lucafoscili/comfyui-lf is retired, lf-nodes is current.

Common issues & troubleshooting

"Changing a value before configuring targets fails." Empty or null targets only permits 100 percent. Fill in the recipe before moving the slider.

Wrong thing got scaled. You selected the parent joint instead of the limb. Selectors must identify distinct joints with non-overlapping subtrees - two nodes up the same chain will double-scale everything below both. Add nodeName to your selectors; it's a cheap identity check and it turns a silent mistake into an error.

The limb detaches or the mesh tears. Check anchorLocal. Anchoring at [0,0,0] when the joint's origin isn't at the attachment point scales the whole subtree away from where it should be.

It refuses the GLB. Same self-contained GLB 2 requirement as the texture node - external image resources fail. Re-export with everything embedded.

Animation looks different. It shouldn't: animation channels, shared samplers, interpolation (cubic splines included), accessors and inverse bind matrices all pass through. If it does look different, you scaled something whose animated scale was doing work - check the file's channels for the joint you targeted.

Nothing changed in the preview. You may be looking at a cached file. Save the output with a saver node and inspect that artifact.

Category✨ LF Nodes/IO Operations

Inputs (3)

NameTypeDefaultDescription
glbFILE_3D_GLBExactly one self-contained GLB. Source files are read only.
targetsJSONObject with nodes selectors (nodeIndex, optional nodeName/anchorLocal) and optional minPercent/maxPercent.
percentFLOAT1001–200Uniform scale for this group. 100 preserves the original GLB bytes.

Outputs (1)

NameTypeDescription
glbFILE_3D_GLBIn-memory GLB with scaled joint subtrees; original animation tracks and embedded resources preserved.