# Blender Procedural

> >

- **Type:** Skill
- **Install:** `agentstack add skill-max-786-claude-3d-harness-blender-procedural`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [MAX-786](https://agentstack.voostack.com/s/max-786)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [MAX-786](https://github.com/MAX-786)
- **Source:** https://github.com/MAX-786/claude-3d-harness/tree/main/library/gaius/blender-procedural

## Install

```sh
agentstack add skill-max-786-claude-3d-harness-blender-procedural
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Skill: Blender Procedural Modeling (Advanced)

Sei un esperto di modellazione procedurale matematica in Blender.
Lavori con frame propagation, loft anatomici, strutture ripetitive parametriche.

---

## Connessione — MCP (predefinito)

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

# Screenshot rapido (no render)
mcp__Blender__get_screenshot_of_window_as_image()

# Render su file e poi Read per analisi visiva
mcp__Blender__render_viewport_to_path(output_path="/preview.png")
```

---

## Visual Loop

```
1. execute_blender_code(build_code)
2. render_viewport_to_path("preview.png") → Read("preview.png") → analisi visiva
3. execute_blender_code(fix_code) → itera fino a soddisfazione
```

---

## IL PRINCIPIO FONDAMENTALE — Frame Propagation

Ogni punto su una curva ha un **frame locale** (sistema di riferimento):
- **T** (Tangent): direzione di avanzamento
- **N** (Normal): "su" del frame
- **B** (Binormal): B = T × N

Il problema del frame naïve (Frenet-Serret): N dipende dalla curvatura → **flipping**
su tratti rettilinei e **drift** su curve complesse.

**Soluzione: Parallel Transport**
```
M_{n+1} = M_n · T · R
dove R = rotazione minima che porta T_n → T_{n+1}
```
Il frame ruota solo quanto necessario — nessun flip, nessun drift.

```python
from mathutils import Vector, Matrix, Quaternion
import math

def parallel_transport(points):
    """
    Calcola un frame ortonormale per ogni punto della curva usando Parallel Transport.
    Elimina il flipping di Frenet-Serret su tratti rettilinei e curvi.
    
    Input : lista di Vector (punti della curva)
    Output: lista di (T, N, B) — tuple di Vector normalizzati
    """
    n = len(points)
    frames = [None] * n
    
    # Frame iniziale — scegli N0 perpendicolare a T0
    T0 = (points[1] - points[0]).normalized()
    # Trova un vettore non parallelo a T0
    up = Vector((0, 0, 1))
    if abs(T0.dot(up)) > 0.99:
        up = Vector((1, 0, 0))
    N0 = T0.cross(up).normalized()
    B0 = T0.cross(N0).normalized()
    frames[0] = (T0, N0, B0)
    
    for i in range(1, n):
        T_prev, N_prev, B_prev = frames[i - 1]
        if i  1e-8:
            axis.normalize()
            cos_a = max(-1.0, min(1.0, T_prev.dot(T_curr)))
            angle  = math.acos(cos_a)
            q = Quaternion(axis, angle)
            N_curr = q @ N_prev
            B_curr = T_curr.cross(N_curr).normalized()
            N_curr = B_curr.cross(T_curr).normalized()
        else:
            N_curr = N_prev.copy()
            B_curr = B_prev.copy()
        
        frames[i] = (T_curr, N_curr, B_curr)
    
    return frames

def reortho(T, N):
    """
    Riortonormalizza N rispetto a T (anti-drift).
    Chiama ogni 10-20 passi per evitare accumulo di errore floating point.
    """
    N = N - T * T.dot(N)
    if N.length  0 and bump_start  0.3:
                poly.material_index = 1
```

---

## CRESCITA DIFFERENZIALE — superfici organiche

La crescita differenziale crea superfici corrugate/ondulate tipiche di foglie,
cortecce, intestino, cervello. Ogni vertice si sposta in base alla distanza
dai vicini vs. la sua distanza ideale.

```python
def differential_growth_step(obj, growth_rate=0.02, target_edge_len=None,
                              boundary_stiffness=0.8):
    """
    Un passo di crescita differenziale su una mesh.
    Chiama più volte (50-200 iterazioni) per ottenere la forma finale.
    
    growth_rate        : quanto crescono i vertici interni (0.01-0.05)
    target_edge_len    : lunghezza ideale degli edge (None = media attuale)
    boundary_stiffness : quanto i vertici di bordo resistono alla crescita [0-1]
    
    NOTA: richiedere sempre bpy.ops.object.modifier_apply su SubSurf PRIMA
    di applicare la crescita, altrimenti opera sulla mesh base e non su quella
    suddivisa.
    
    Workflow:
        1. Crea mesh di partenza (es: piano suddiviso 20x20)
        2. Seleziona e applica SubSurf livello 2
        3. Itera differential_growth_step 100-200 volte
        4. Il risultato è una superficie corrugata organica
    """
    import bmesh
    
    bm = bmesh.new()
    bm.from_mesh(obj.data)
    bm.verts.ensure_lookup_table()
    bm.edges.ensure_lookup_table()
    
    if target_edge_len is None:
        total_len = sum(e.calc_length() for e in bm.edges)
        target_edge_len = total_len / len(bm.edges) if bm.edges else 0.1
    
    displacements = [Vector((0,0,0))] * len(bm.verts)
    
    for v in bm.verts:
        neighbors = [e.other_vert(v) for e in v.link_edges]
        if not neighbors:
            continue
        
        force = Vector((0, 0, 0))
        for nb in neighbors:
            vec  = nb.co - v.co
            dist = vec.length
            if dist = target?

TRIGGER → passa allo STATO 2

STATO 2 — Rotazione
    → calcola angolo tra Z_locale e nuova_direzione_globale
    → applica rotazione (immediata o distribuita = fillet)
    → reset distanza_accumulata = 0
    → passa allo STATO 1
```

Liste di waypoint: `[(5m, dir_X), (8m, dir_Z), (12m, dir_Y)]` — ad ogni trigger si aggiorna la direzione target.

### La matematica: `rotation_difference()`

```python
from mathutils import Vector, Matrix, Quaternion

def align_to_direction(current_matrix, new_direction_global):
    """
    Calcola e applica la rotazione minima per allineare Z locale a new_direction_global.
    rotation_difference() trova l'arco minimo — stesso principio del Parallel Transport
    ma per un cambio intenzionale (non per prevenire il flipping accidentale).
    """
    # Direzione locale attuale (asse Z della matrice corrente)
    z_locale = (current_matrix.to_3x3() @ Vector((0, 0, 1))).normalized()
    # Direzione target nello spazio globale
    nuova_dir = Vector(new_direction_global).normalized()
    # Quaternione di rotazione minima
    rot_quat = z_locale.rotation_difference(nuova_dir)
    # Applica alla matrice corrente
    return current_matrix @ rot_quat.to_matrix().to_4x4()
```

### Fillet Procedurale — raccordo dello spigolo vivo

Se la rotazione è immediata → angolo netto (tubature industriali).
Se distribuita su N passi → raccordo sferico (bambù, aorta, vertebre):

```python
def fillet_turn(current_matrix, new_direction, step_size, fillet_steps=8):
    """
    Distribuisce la rotazione verso new_direction su fillet_steps passi.
    Il raggio del raccordo è proporzionale a step_size * fillet_steps.
    """
    from mathutils import Vector, Quaternion
    z_loc = (current_matrix.to_3x3() @ Vector((0, 0, 1))).normalized()
    new_dir = Vector(new_direction).normalized()
    q_total = z_loc.rotation_difference(new_dir)
    # Slerp: angolo parziale a ogni passo
    angle_total = q_total.angle
    axis = q_total.axis if q_total.axis.length > 1e-8 else Vector((0, 0, 1))
    q_step = Quaternion(axis, angle_total / fillet_steps)
    matrices = []
    m = current_matrix.copy()
    for _ in range(fillet_steps):
        m = m @ q_step.to_matrix().to_4x4() @ Matrix.Translation((0, 0, step_size))
        matrices.append(m.copy())
    return matrices  # lista di frame intermedi per il loft
```

### Spettro discreto→continuo

```
Spigolo vivo              Raccordo procedurale        Tropismo continuo
(fillet_steps = 1)       (fillet_steps = N)          (W ad ogni passo)
       │                        │                            │
Tubatura industriale      Ramo di bambù              Radice organica
Condotto aerazione        Vertebra→vertebra          Coronaria sinuosa
```

| Struttura | Approccio | Parametri |
|-----------|-----------|-----------|
| Tubatura industriale | State Machine, steps=1 | lista waypoint + direzioni |
| Rami bambù | State Machine, steps=3-5 | lunghezza segmento, angolo nodo |
| Colonna vertebrale | State Machine + Fillet | angoli lordosi/cifosi per segmento |
| Aorta | State Machine + Fillet largo | 1-2 cambi dir., raggio ~30mm |
| Coronarie | Sezione 10 (Noise Field) | scala noise, W=0.2-0.4 |

---

## MODELLAZIONE A GRAFO (Sezione 12)

Paradigma opposto al cinematico: invece di un punto che viaggia, si parte da una **nuvola di punti già posizionati** e si decide *chi collegare a chi*.

| | Cinematico (Sez. 7-11) | A Grafo (Sez. 12) |
|--|--|--|
| Input | Un punto che si muove | Nuvola di punti |
| Output | Curva/tubo continuo | Rete, mesh, tessuto |
| Analogia | Pennello che disegna | Tessitore che annoda fili |

### 1. Plexus Effect — connessione per distanza soglia

```python
def plexus_effect(bm, verts, d_max):
    """
    Collega ogni coppia di vertici se la distanza è < d_max.
    Complessità O(N²) — per N grandi usare KD-tree.
    Applicazioni: reti neurali, molecole, ragnatele, motion graphics.
    """
    for i, va in enumerate(verts):
        for j, vb in enumerate(verts):
            if j <= i: continue
            if (va.co - vb.co).length < d_max:
                try: bm.edges.new((va, vb))
                except ValueError: pass  # arco già esistente
```

### 2. Triangolazione di Delaunay — dalla nuvola alla mesh

Costruisce automaticamente una mesh triangolata massimizzando l'angolo minimo di ogni triangolo. Nessun punto cade dentro la circonferenza circoscritta di nessun triangolo → mesh più regolare possibile.

```python
from scipy.spatial import Delaunay
import numpy as np

def delaunay_mesh(punti_3d, bm):
    """
    punti_3d: lista di Vector
    bm: bmesh già inizializzato
    Proietta su XY per Delaunay 2D, poi usa Z reale per i vertici.
    """
    points_2d = np.array([(v.x, v.y) for v in punti_3d])
    tri = Delaunay(points_2d)
    verts = [bm.verts.new(p) for p in punti_3d]
    for simplex in tri.simplices:
        try:
            bm.faces.new([verts[simplex[0]], verts[simplex[1]], verts[simplex[2]]])
        except ValueError: pass
```

Applicazioni: ricostruzione mesh da scansioni laser, terreni da punti quota, semplificazione mesh dense.

### 3. Diagrammi di Voronoi — l'inverso di Delaunay

Ogni cella contiene tutti i punti più vicini al suo "seme". I bordi delle celle Voronoi sono le mediatrici dei segmenti di Delaunay.

```python
from scipy.spatial import Voronoi
vor = Voronoi(points)
# vor.vertices       = vertici dei poligoni Voronoi
# vor.ridge_vertices = archi (bordi) tra celle
```

Applicazioni biologiche: scaglie di rettile, struttura trabecolare dell'osso, pattern cellulare della cornea, schiuma e bolle.

### 4. Minimum Spanning Tree (MST) — strutture ottimizzate

Algoritmo di Kruskal: trova il sottoinsieme minimo di archi che connette tutti i punti senza cicli, minimizzando la lunghezza totale.

```python
import heapq

def kruskal_mst(verts_list):
    """
    verts_list: lista di Vector
    Ritorna lista di coppie (i, j) degli archi del MST.
    Applicazioni: vene su foglie, ramificazioni fluviali, fulmini,
                 crepe su ceramica, struttura basilare vasi capillari.
    """
    edges = []
    n = len(verts_list)
    for i in range(n):
        for j in range(i + 1, n):
            d = (verts_list[i] - verts_list[j]).length
            heapq.heappush(edges, (d, i, j))
    parent = list(range(n))
    def find(x):
        while parent[x] != x: x = parent[x]
        return x
    mst = []
    while edges and len(mst) < n - 1:
        d, i, j = heapq.heappop(edges)
        ri, rj = find(i), find(j)
        if ri != rj:
            parent[ri] = rj
            mst.append((i, j))
    return mst
```

### Applicazioni nel progetto cardiaco

| Struttura | Algoritmo | Input | Output |
|-----------|-----------|-------|--------|
| Rete capillare miocardio | Plexus su attrattori ASE | Punti nel volume | Rete di capillari |
| Mesh da TAC | Delaunay 3D su contorni | Punti del contorno/slice | Mesh chiusa |
| Pattern trabecolare VD | Voronoi 3D | Semi randomici nel volume RV | Struttura spugnosa |
| Albero coronarico | MST | Attrattori nel miocardio | Vasi ottimizzati |

---

## SISTEMI IBRIDI: GRAFO + CINEMATICA (Sezione 13)

**Il Grafo pensa, la Cinematica costruisce.**

Il Grafo genera topologie perfette ma filiformi (zero spessore, non renderizzabili).
La Cinematica produce geometrie volumetriche ma fatica con topologie ramificate complesse.

### Schema del workflow ibrido

```
[ Dati Globali / Attrattori ]
           ↓
(Modellazione a Grafo — Sez. 12)
    Trova la Topologia (MST / Delaunay / Space Colonization)
           ↓
[ Scheletro Logico: Nodi e Archi ]
           ↓
(Modellazione Cinematica — Sez. 7-11)
    Sweep/Loft lungo gli archi (State Machine + Fillet)
    Parallel Transport per orientare i profili
    Legge di Murray per scalare i raggi alle biforcazioni
           ↓
[ Mesh Volumetrica 3D Finale ]
```

### Applicazione: albero coronarico completo

```python
# Fase 1 (Grafo): scheletro astratto
# 1. Genera attrattori sulla superficie del miocardio (proporzioni ASE)
# 2. Space Colonization → grafo di ramificazione da radice aortica
# 3. MST per determinare albero ottimale

# Fase 2 (Ibrido): trasforma archi in waypoint ordinati
# (ogni arco grafo → lista di punti intermedi per state_machine_path)

# Fase 3 (Cinematica): costruzione volumetrica
# - state_machine_path() inserisce raccordi ai cambi di direzione
# - build_vessel() genera il tubo con Parallel Transport
# - radius_bu diminuisce man mano che ci si allontana dalla radice (Legge di Murray)

# Legge di Murray per vasi sanguigni:
# r_parent^3 = r_child1^3 + r_child2^3
def murray_radius(r_parent, ratio=0.5):
    """Raggio figlio per biforcazione simmetrica."""
    return r_parent * (0.5 ** (1/3))  # ≈ r_parent * 0.794
```

**Sintesi:** il Grafo decide il "Dove" e il "Come è connesso", la Cinematica decide il "Che forma ha" e il "Quanto è spesso".

---

## ANALISI RICHIESTA

| Keyword | Tecnica |
|---------|---------|
| `cuore / vaso / arteria / vena` | build_shell + add_cavity + build_vessel |
| `DNA / elica / collagene` | double_helix / helix_spine + build_vessel |
| `colonna / vertebra / spine` | lumbar_spine + parallel_transport |
| `tubo / pipe / cavo su curva` | build_vessel |
| `sezione personalizzata / manico ovale` | build_vessel_custom_section |
| `crescita / organico / corrugato` | differential_growth_step (iterato) |
| `cavità / camera / vuoto interno` | add_cavity + assign_cavity_material |
| `propagazione matriciale / L-system / vertebra` | propagate_matrix + reortho_matrix (Sez. 7) |
| `tropismo / gravitropismo / fototropismo / vite` | vector_blend_step + influenza_fn (Sez. 10) |
| `rumore organico / sinuoso / corona sinuosa` | get_noise_vector con mathutils.noise (Sez. 10) |
| `space colonization / albero vascolare` | Space Colonization pseudocode (Sez. 10) |
| `state machine / bambù / tubatura / waypoint` | align_to_direction + fillet_turn (Sez. 11) |
| `plexus / rete neurale / ragnatela` | plexus_effect (Sez. 12) |
| `delaunay / mesh da punti / scansione` | delaunay_mesh con scipy (Sez. 12) |
| `voronoi / scaglie / trabecolare / bolle` | scipy.spatial.Voronoi (Sez. 12) |
| `minimum spanning tree / vene foglia / fulmini` | kruskal_mst (Sez. 12) |
| `grafo + loft / albero coronarico completo` | Workflow ibrido Grafo→Cinematica (Sez. 13) |

**Se richiesta ambigua → chiedi: "La forma ha una spine (asse principale)?
Ha profili variabili lungo quell'asse? Ha influenze globali (gravità, attrattori)?
Oppure parte da una nuvola di punti da connettere (grafo)?"**

## Output

- Codice Python completo, nessun placeholder
- Usa sempre parallel_transport per tubi su curva (non Frenet-Serret)
- Dopo esecuzione: render → Read → analisi visiva → itera
- Commenta le misure anatomiche con fonte (ASE, Gray's Anatomy, ecc.)

## Source & license

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

- **Author:** [MAX-786](https://github.com/MAX-786)
- **Source:** [MAX-786/claude-3d-harness](https://github.com/MAX-786/claude-3d-harness)
- **License:** MIT

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

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-max-786-claude-3d-harness-blender-procedural
- Seller: https://agentstack.voostack.com/s/max-786
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
