AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Blender Rig

skill-max-786-claude-3d-harness-blender-rig · by MAX-786

>

— No reviews yet
0 installs
0 views
— view→install

Install

$ agentstack add skill-max-786-claude-3d-harness-blender-rig

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ✓ Network access No
  • ✓ Filesystem access No
  • ✓ Shell / process execution No
  • ✓ Environment & secrets No
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-max-786-claude-3d-harness-blender-rig)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 4d ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Blender Rig? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Skill: Blender Procedural Rigging

Sei un esperto di rigging anatomico e procedurale in Blender. Costruisci scheletri corretti, deformazioni biomeccaniche e animazioni da codice.


Connessione — MCP (predefinito)

mcp__Blender__execute_blender_code(code="""
import bpy, bmesh, math
from mathutils import Vector, Matrix, Quaternion
# ... codice ...
result = {"ok": True}
""")

mcp__Blender__get_screenshot_of_window_as_image()
mcp__Blender__render_viewport_to_path(output_path="/rig_preview.png")

IL PRINCIPIO FONDAMENTALE — Bone Roll e Frame Locali

Ogni osso in Blender ha un frame locale (assi X, Y, Z):

  • Y locale: direzione testa→coda (sempre, non modificabile)
  • X locale: determinato dal Bone Roll
  • Z locale: B = Y × X

Bone Roll = 0 significa che l'asse X locale è allineato al mondo. Questo è fondamentale per catene articolate: garantisce che ruotando sull'asse X (flessione) le falangi/vertebre si chiudano senza torsioni strane.

Roll sbagliato → l'osso ruota su un asse obliquo → movimenti strani
Roll = 0       → flessione sull'asse X = chiusura anatomica corretta

Come verificare:

# In Edit Mode — controlla il roll di ogni osso
for bone in arm.data.edit_bones:
    print(f"{bone.name}: roll = {math.degrees(bone.roll):.2f}°")
# Se non è 0° (o 90° per assi specifici), correggilo

ARMATURE — Creazione e Convenzioni

import bpy, math
from mathutils import Vector

def create_armature(name="Rig"):
    """
    Crea un'armatura vuota pronta per ricevere ossa.
    Ritorna (arm_obj, armature).
    """
    bpy.ops.object.armature_add(enter_editmode=True,
                                 align='WORLD', location=(0,0,0))
    arm_obj  = bpy.context.active_object
    arm_obj.name = name
    armature = arm_obj.data
    armature.name = name + "_Armature"
    # Rimuovi l'osso di default
    armature.edit_bones.remove(armature.edit_bones[0])
    return arm_obj, armature

def add_bone(armature, name, head, tail, parent=None,
             connected=False, roll=0.0, layer=0):
    """
    Aggiunge un osso all'armatura (deve essere in Edit Mode).
    
    head, tail  : tuple (x,y,z) in world space
    parent      : nome dell'osso padre (stringa) o None
    connected   : se True, la testa si attacca alla coda del padre
    roll        : rotazione dell'asse X locale in radianti (0 = allineato al mondo)
    
    NOMENCLATURA CONSIGLIATA:
      - Lato: _L (sinistra), _R (destra)
      - Segmento: Palm, Proximal, Intermediate, Distal
      - Root: osso radice (non deforma, ancora il rig)
      - DEF_: ossa che deformano la mesh (Deform bones)
      - CTRL_: ossa di controllo (non deformano)
      - MCH_: ossa meccanismo (intermedie, non visibili)
    """
    bone = armature.edit_bones.new(name)
    bone.head  = Vector(head)
    bone.tail  = Vector(tail)
    bone.roll  = roll
    bone.use_deform = True
    if parent:
        bone.parent = armature.edit_bones[parent]
        bone.use_connect = connected
    return bone

# ── Esempio: dito indice ──────────────────────────────────────────────
def create_finger(armature, name, base_y, segments=None):
    """
    Crea una catena di ossa per un dito.
    
    segments: lista di (nome_suffisso, y_start, y_end)
    Se None, usa proporzioni standard (Proximal 40%, Intermediate 30%, Distal 30%).
    """
    if segments is None:
        segments = [
            ("Palm",         0.0,  -2.0),
            ("Proximal",    -2.0,  -4.0),
            ("Intermediate",-4.0,  -5.5),
            ("Distal",      -5.5,  -6.5),
        ]
    
    prev = None
    for i, (seg, y0, y1) in enumerate(segments):
        bname = f"{name}_{seg}"
        bone  = add_bone(armature, bname,
                          head=(0, y0 + base_y, 0),
                          tail=(0, y1 + base_y, 0),
                          parent=prev, connected=(i > 0),
                          roll=0.0)  # ← ROLL = 0: asse X orizzontale
        prev = bname

FK / IK — DUALITÀ

FK (Forward Kinematics): ruota ogni osso manualmente dalla radice alla punta. Preciso, prevedibile, ma lento per animazioni complesse.

IK (Inverse Kinematics): sposti la punta, Blender calcola gli angoli delle giunzioni. Rapido per posare, ma meno preciso. Richiede un Pole Target per evitare flipping del ginocchio/gomito.

def setup_ik(arm_obj, tip_bone_name, chain_count=3,
              pole_target=None, pole_bone=None, pole_angle=0):
    """
    Aggiunge un vincolo IK all'osso 'tip_bone_name'.
    Deve essere chiamato in POSE mode.
    
    chain_count : numero di ossa nella catena IK (2=gomito, 3=dito, 4=gamba)
    pole_target : oggetto Empty usato come Pole Target (evita il flip del gomito)
    pole_angle  : angolo di offset del pole in gradi (tipico: 0° o 90°)
    
    Esempio — gamba con knee target:
        # 1. Crea Empty per il knee
        bpy.ops.object.empty_add(location=(0, -2, 0.5))
        knee = bpy.context.active_object
        knee.name = "Knee_Target"
        # 2. Attiva pose mode sull'armatura
        bpy.context.view_layer.objects.active = arm_obj
        bpy.ops.object.mode_set(mode='POSE')
        # 3. Applica IK
        setup_ik(arm_obj, "Shin", chain_count=2,
                 pole_target=knee, pole_angle=0)
    """
    bpy.context.view_layer.objects.active = arm_obj
    
    if bpy.context.mode != 'POSE':
        bpy.ops.object.mode_set(mode='POSE')
    
    pbone = arm_obj.pose.bones[tip_bone_name]
    ik    = pbone.constraints.new('IK')
    ik.chain_count = chain_count
    
    if pole_target:
        ik.pole_target      = pole_target
        ik.pole_subtarget   = pole_bone or ""
        ik.pole_angle       = math.radians(pole_angle)
    
    return ik

def setup_ik_target(arm_obj, tip_bone_name, target_obj=None, chain_count=3):
    """
    Alternativa: usa un Empty come target IK (la punta segue l'Empty).
    Crea automaticamente l'Empty se target_obj è None.
    """
    if target_obj is None:
        tip_world = arm_obj.pose.bones[tip_bone_name].tail
        bpy.ops.object.empty_add(location=arm_obj.matrix_world @ tip_world)
        target_obj = bpy.context.active_object
        target_obj.name = f"IK_{tip_bone_name}_Target"
    
    bpy.context.view_layer.objects.active = arm_obj
    bpy.ops.object.mode_set(mode='POSE')
    pbone = arm_obj.pose.bones[tip_bone_name]
    ik    = pbone.constraints.new('IK')
    ik.target      = target_obj
    ik.chain_count = chain_count
    return ik, target_obj

def toggle_ik_fk(arm_obj, bone_names, use_ik=True):
    """
    Commuta tra IK e FK per un gruppo di ossa.
    IK: abilita vincolo IK, disabilita mute su FK
    FK: disabilita vincolo IK (mute=True)
    
    Utile per switch IK/FK durante l'animazione.
    """
    bpy.context.view_layer.objects.active = arm_obj
    bpy.ops.object.mode_set(mode='POSE')
    for bn in bone_names:
        for c in arm_obj.pose.bones[bn].constraints:
            if c.type == 'IK':
                c.mute = not use_ik

WEIGHT PAINTING ALGORITMICO

Il weight painting procedurale assegna pesi ai vertex group in base alla distanza da punti di controllo. Più preciso del painting manuale, 100% riproducibile, zero artefatti di painting.

Smoothstep interpolator

def smoothstep(x):
    """Interpolazione cubica [0,1] → [0,1]. Derivata zero agli estremi."""
    x = max(0.0, min(1.0, x))
    return x * x * (3 - 2 * x)

def smootherstep(x):
    """Quintica — transizione ancora più morbida. Per blend tra giunzioni."""
    x = max(0.0, min(1.0, x))
    return x * x * x * (x * (x * 6 - 15) + 10)

Weight painting per coordinata (catene lineari)

def weight_paint_by_coord(mesh_obj, bone_ranges, coord_axis='Y',
                           blend_zone=0.3):
    """
    Assegna pesi ai vertex group in base alla coordinata di ogni vertice.
    Ideale per catene lineari (dito, colonna, arto).
    
    bone_ranges : dict {nome_vg: (coord_min, coord_max)}
                  la coordinata è in LOCAL SPACE del mesh_obj
    coord_axis  : 'X', 'Y', o 'Z'
    blend_zone  : frazione del range usata per il blend tra ossa adiacenti [0-0.5]
    
    Esempio (dito lungo Y, da 0 a -6.5):
        weight_paint_by_coord(skin, {
            "Palm":         ( 0.0, -2.0),
            "Proximal":    (-2.0, -4.0),
            "Intermediate":(-4.0, -5.5),
            "Distal":      (-5.5, -6.5),
        }, coord_axis='Y', blend_zone=0.3)
    """
    axis_idx = {'X': 0, 'Y': 1, 'Z': 2}[coord_axis]
    
    # Crea vertex group se non esistono
    vgs = {}
    for name in bone_ranges:
        vg = mesh_obj.vertex_groups.get(name)
        if vg is None:
            vg = mesh_obj.vertex_groups.new(name=name)
        vg.add(list(range(len(mesh_obj.data.vertices))), 0.0, 'REPLACE')
        vgs[name] = vg
    
    names   = list(bone_ranges.keys())
    ranges  = list(bone_ranges.values())
    
    for v in mesh_obj.data.vertices:
        coord = v.co[axis_idx]
        for i, (name, (cmin, cmax)) in enumerate(zip(names, ranges)):
            span  = cmax - cmin if cmax != cmin else 1e-6
            blend = abs(span) * blend_zone
            
            if min(cmin, cmax)  0 and abs(blend) > 1e-8:
                    fade_in  = abs((coord - cmin) / blend)
                    if fade_in  1e-8:
                    fade_out = abs((cmax - coord) / blend)
                    if fade_out  0:
                    vgs[name].add([v.index], w, 'ADD')

### Weight painting per distanza da punto 3D
def weight_paint_by_distance(mesh_obj, vg_name, center_local,
                               max_dist, falloff='SMOOTH'):
    """
    Assegna pesi in base alla distanza da un punto 3D in spazio locale.
    Ideale per aree di influenza circolari (nocca, spalla, muscolatura).
    
    center_local : Vector in coordinate locali del mesh
    max_dist     : distanza oltre cui il peso è 0
    falloff      : 'LINEAR', 'SMOOTH' (smoothstep), 'SHARP' (quadratica)
    
    Esempio (palpebra — bordo dell'apertura):
        eye_center = Vector((0, -0.5, 0.35))
        weight_paint_by_distance(eyelid, "UpperLid", eye_center,
                                  max_dist=0.9, falloff='SMOOTH')
    """
    vg = mesh_obj.vertex_groups.get(vg_name)
    if vg is None:
        vg = mesh_obj.vertex_groups.new(name=vg_name)
    
    center = Vector(center_local)
    for v in mesh_obj.data.vertices:
        dist = (v.co - center).length
        t    = max(0.0, 1.0 - dist / max_dist)
        if falloff == 'SMOOTH':
            w = smoothstep(t)
        elif falloff == 'SHARP':
            w = t * t
        else:  # LINEAR
            w = t
        if w > 0.001:
            vg.add([v.index], w, 'REPLACE')

SHAPE KEYS + DRIVER — Biomeccanica Procedurale

I Shape Key + Driver creano deformazioni reattive: la nocca si solleva quando il dito si piega, l'occhio si gonfia quando si chiude, il muscolo si contrae quando l'osso ruota.

def add_shape_key_with_driver(mesh_obj, key_name, driver_bone,
                               arm_obj, transform='ROT_X',
                               expression="abs(rot) / 1.5",
                               var_name="rot"):
    """
    Crea uno Shape Key con Driver collegato alla rotazione di un osso.
    
    key_name      : nome della shape key (es: "Knuckle_Bend")
    driver_bone   : nome dell'osso che guida la deformazione
    arm_obj       : l'oggetto armatura
    transform     : 'ROT_X' | 'ROT_Y' | 'ROT_Z' | 'LOC_X' | 'SCALE_X' ecc.
    expression    : espressione Python del driver (var_name è la variabile)
    
    Ritorna: la shape key (aggiungi vertici spostati dopo questa chiamata)
    
    Esempio completo (nocca che si solleva quando il dito si piega):
        sk = add_shape_key_with_driver(skin, "Knuckle_Bend", "Proximal",
                                        arm_obj, 'ROT_X',
                                        "abs(rot) / 1.5")
        # Poi sposta i vertici della nocca nella sk.data:
        for i, v in enumerate(skin.data.vertices):
            if is_near_knuckle(v.co):
                influence = knuckle_weight(v.co)
                sk.data[i].co.z += 0.3 * influence
    """
    # Assicurati che esista la Basis key
    if not mesh_obj.data.shape_keys:
        mesh_obj.shape_key_add(name="Basis", from_mix=False)
    
    sk = mesh_obj.shape_key_add(name=key_name, from_mix=False)
    sk.value = 0.0
    
    # Aggiunge il Driver
    fc     = sk.driver_add("value")
    driver = fc.driver
    driver.type = 'SCRIPTED'
    
    var            = driver.variables.new()
    var.name       = var_name
    var.type       = 'TRANSFORMS'
    t              = var.targets[0]
    t.id           = arm_obj
    t.bone_target  = driver_bone
    t.transform_type  = transform
    t.transform_space = 'LOCAL_SPACE'
    
    driver.expression = expression
    return sk

def deform_knuckle(mesh_obj, joint_y, influence_radius=0.8,
                   lift_z=0.3, compress_z=0.4):
    """
    Applica la deformazione della nocca a una shape key già creata.
    Chiama questa DOPO add_shape_key_with_driver.
    
    joint_y         : coordinata Y del giunto (in local space)
    influence_radius: raggio di influenza della nocca
    lift_z          : quanto si solleva la nocca superiore
    compress_z      : quanto si comprime l'interno del giunto
    
    Il metodo identifica automaticamente:
      - vertici sopra il giunto (nocca) → si sollevano (+z)
      - vertici sotto il giunto (palmo) → si comprimono (verso +z)
    """
    sk = mesh_obj.data.shape_keys.key_blocks[-1]  # l'ultima shape key
    
    for i, v in enumerate(mesh_obj.data.vertices):
        dist = abs(v.co.y - joint_y)
        if dist  0:   # parte superiore → nocca
                sk.data[i].co.z += lift_z * influence
                sk.data[i].co.y += 0.2 * influence
            else:             # parte inferiore → compressione
                sk.data[i].co.z += compress_z * influence

SOCKET SYSTEM — Collegare Oggetti a Ossa

Il Socket System usa il vincolo CHILD_OF per ancorare oggetti a ossa. Permette di attaccare armi, attrezzi, oggetti a una mano/braccio.

def socket_attach(mesh_obj, arm_obj, bone_name,
                  local_offset=(0,0,0), local_rotation=(0,0,0)):
    """
    Attacca mesh_obj all'osso bone_name tramite vincolo CHILD_OF.
    
    local_offset   : posizione dell'oggetto in coordinate LOCALI dell'osso
    local_rotation : rotazione in gradi (Euler XYZ)
    
    MATEMATICA DEL VINCOLO:
      M_world_child = M_world_bone × M_offset
      Il CHILD_OF sincronizza automaticamente questa equazione.
    
    Esempio (spada ancorata al palmo):
        socket_attach(sword, hand_rig, "Palm",
                      local_offset=(0, -3.5, -0.6),
                      local_rotation=(0, 0, 0))
    
    Esempio (scudo ancorato al braccio sinistro):
        socket_attach(shield, body_rig, "Forearm_L",
                      local_offset=(0, -1.0, 0.1),
                      local_rotation=(0, 90, 0))
    """
    c = mesh_obj.constraints.new('CHILD_OF')
    c.target     = arm_obj
    c.subtarget  = bone_name
    
    # Offset locale rispetto all'osso
    mesh_obj.location = Vector(local_offset)
    mesh_obj.rotation_euler = tuple(math.radians(r) for r in local_rotation)
    
    # Calcola l'inverse matrix per il vincolo
    bpy.context.view_layer.objects.active = mesh_obj
    bpy.ops.constraint.childof_set_inverse(
        constraint=c.name, owner='OBJECT')
    
    return c

def socket_detach(mesh_obj, bone_name=None):
    """Rimuove tutti i vincoli CHILD_OF (o solo quello verso bone_name)."""
    for c in list(mesh_obj.constraints):
        if c.type == 'CHILD_OF':
            if bone_name is None or c.subtarget == bone_name:
                mesh_obj.constraints.remove(c)

PELLE BIOMECCANICA — Shrinkwrap + Solidify

Tecnica per creare pelle che avvolge uno scheletro curvo:

  1. Crea una mesh di partenza dalla forma generale (sfera, cili

…

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.