Communitygithub.com

Meshy 3D — Generación + Impresión

Habilidades de agente de IA para la plataforma de generación 3D Meshy AI.

¿Qué es Meshy 3D — Generación + Impresión?

Este skill permite a un agente de IA (como Claude Code, Cursor o Codex) interactuar directamente con la API de Meshy AI para generar, refinar y preparar modelos 3D para impresión. Cubre todo el ciclo de vida: desde la detección y configuración segura de la clave API, pasando por la creación de tareas (texto a 3D, imagen a 3D, retopología, rigging, animación, etc.), el monitoreo con retroceso exponencial, la descarga organizada de archivos en una estructura de proyecto, hasta la preparación para impresión 3D con integración de laminadores. Está diseñado para ahorrar créditos al presentar al usuario un resumen de costos antes de cada operación y para manejar pipelines de múltiples pasos de forma robusta. Es útil para desarrolladores, diseñadores y aficionados a la impresión 3D que deseen automatizar flujos de trabajo de generación de activos 3D directamente desde un agente conversacional.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add meshy-dev/meshy-3d-agent

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace Meshy 3D — Generación + Impresión?

Comunícate directamente con la API de Meshy AI para generar e imprimir activos 3D. Cubre el ciclo de vida completo: configuración de clave API, creación de tareas, sondeo con retroceso exponencial, descarga, pipelines de múltiples pasos y preparación para impresión 3D con integración de laminador.


MANIFIESTO DE SEGURIDAD

Variables de entorno accedidas:

  • MESHY_API_KEY: Token de autenticación de API enviado solo en el encabezado HTTP Authorization: Bearer. Nunca se registra, nunca se escribe en ningún archivo excepto .env en el directorio de trabajo actual cuando el usuario lo solicita explícitamente.

Puntos finales de red externos:

  • https://api.meshy.ai: API de Meshy AI (creación de tareas, sondeo de estado, descarga de modelos/imágenes)

Acceso al sistema de archivos:

  • Lectura: .env en el directorio de trabajo actual solamente (búsqueda de clave API)
  • Escritura: .env en el directorio de trabajo actual solamente (almacenamiento de clave API, solo a petición del usuario)
  • Escritura: ./meshy_output/ en el directorio de trabajo actual (archivos de modelo descargados, metadatos)
  • Lectura: archivos proporcionados explícitamente por el usuario (por ejemplo, imágenes locales para conversión de imagen a 3D), accedidos solo en la ruta exacta que el usuario especifica
  • Sin acceso a directorios de inicio, perfiles de shell ni ninguna ruta fuera de lo anterior

Datos que salen de esta máquina:

  • Las solicitudes de API a api.meshy.ai incluyen la MESHY_API_KEY en el encabezado de Autorización y las indicaciones de texto o URL de imágenes proporcionadas por el usuario. No se transmite ningún otro dato local. Los archivos de modelo descargados se guardan solo localmente.

IMPORTANTE: Aviso de sesión de primer uso

Cuando este skill se active por primera vez en una sesión, informa al usuario:

Todos los archivos generados se guardarán en meshy_output/ en el directorio de trabajo actual. Cada proyecto obtiene su propia carpeta ({YYYYMMDD_HHmmss}_{prompt}_{id}/) con archivos de modelo, texturas, miniaturas y metadatos. El historial se rastrea en meshy_output/history.json.

Esto solo necesita decirse una vez por sesión.


IMPORTANTE: Organización de archivos

Todos los archivos descargados DEBEN ir a un directorio estructurado meshy_output/ en el directorio de trabajo actual. NO disperses archivos al azar.

  • Cada proyecto: meshy_output/{YYYYMMDD_HHmmss}_{prompt_slug}_{task_id_prefix}/
  • Las tareas encadenadas (vista previa → refinar → rigging) reutilizan el mismo project_dir
  • Rastrea las tareas en metadata.json por proyecto, y globalmente en history.json
  • Descarga automáticamente las miniaturas junto con los modelos

IMPORTANTE: Reglas de comandos de shell

Usa solo herramientas POSIX estándar. NO uses rg, fd, bat, exa/eza.


IMPORTANTE: Ejecutar tareas largas correctamente

La generación de Meshy toma de 1 a 5 minutos. Escribe todo el flujo de crear → sondear → descargar como UN script de Python y ejecútalo en una sola llamada de Bash. Usa python3 -u script.py para una salida sin búfer. Las tareas que permanecen al 99% durante 30-120 segundos es una finalización normal: NO interrumpas.


Paso 0: Detección de clave API (SIEMPRE EJECUTAR PRIMERO)

Solo verifica el entorno de la sesión actual y el archivo .env en el directorio de trabajo actual. NO escanees directorios de inicio ni archivos de perfil de shell.

echo "=== Detección de clave API de Meshy ==="

# 1. Verificar variable de entorno actual
if [ -n "$MESHY_API_KEY" ]; then
  echo "ENV_VAR: ENCONTRADA (${MESHY_API_KEY:0:8}...)"
else
  echo "ENV_VAR: NO_ENCONTRADA"
fi

# 2. Verificar .env en el directorio de trabajo actual solamente
if [ -f ".env" ] && grep -q "MESHY_API_KEY" ".env" 2>/dev/null; then
  echo "DOTENV(.env): ENCONTRADA"
  export MESHY_API_KEY=$(grep "^MESHY_API_KEY=" ".env" | head -1 | cut -d'=' -f2- | tr -d '"'"'" )
fi

# 3. Estado final
if [ -n "$MESHY_API_KEY" ]; then
  echo "LISTO: clave=${MESHY_API_KEY:0:8}..."
else
  echo "LISTO: NO_SE_ENCONTRÓ_CLAVE"
fi

# 4. Verificación de requests de Python
python3 -c "import requests; print('PYTHON_REQUESTS: OK')" 2>/dev/null || echo "PYTHON_REQUESTS: FALTANTE (ejecuta: pip install requests)"

echo "=== Detección completa ==="

Decisión después de la detección

  • Clave encontrada → Procede al Paso 1.
  • Clave NO encontrada → Ve al Paso 0a.
  • Faltan requests de Python → Ejecuta pip install requests.

Paso 0a: Configuración de clave API (Solo si no se encuentra clave)

Dile al usuario:

Para usar la API de Meshy, necesitas una clave API:

  1. Ve a https://www.meshy.ai/settings/api
  2. Haz clic en "Create API Key", asígnale un nombre y copia la clave (comienza con msy_)
  3. La clave se muestra solo una vez: guárdala en un lugar seguro

Nota: El acceso a la API requiere un plan Pro o superior. Las cuentas de nivel gratuito no pueden crear claves API.

Una vez que el usuario proporcione la clave, configúrala para la sesión actual y, opcionalmente, persístela en .env:

# Configurar solo para la sesión actual
export MESHY_API_KEY="msy_PEGA_CLAVE_AQUÍ"

# Verificar la clave
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer $MESHY_API_KEY" \
  https://api.meshy.ai/openapi/v1/balance)

if [ "$STATUS" = "200" ]; then
  BALANCE=$(curl -s -H "Authorization: Bearer $MESHY_API_KEY" https://api.meshy.ai/openapi/v1/balance)
  echo "Clave válida. $BALANCE"
else
  echo "Clave inválida (HTTP $STATUS). Verifica la clave e inténtalo de nuevo."
fi

Para persistir la clave (solo proyecto actual):

# Escribir en .env en el directorio de trabajo actual
echo 'MESHY_API_KEY=msy_PEGA_CLAVE_AQUÍ' >> .env
echo "Guardada en .env"

# IMPORTANTE: agregar .env a .gitignore para evitar filtrar la clave
grep -q "^\.env" .gitignore 2>/dev/null || echo ".env" >> .gitignore
echo ".env agregado a .gitignore"

Recordatorio de seguridad: La clave se almacena solo en .env en el directorio de tu proyecto actual. Nunca confirmes este archivo en el control de versiones. .env se ha agregado automáticamente a .gitignore.


Paso 1: Confirmar plan con el usuario antes de gastar créditos

CRÍTICO: Antes de crear cualquier tarea, presenta al usuario un resumen de costos y espera confirmación:

Generaré un modelo 3D de "<indicación>" usando el siguiente plan:

  1. Vista previa (generación de malla) — 20 créditos
  2. Refinar (texturizado con PBR) — 10 créditos
  3. Descargar como .glb

  Costo total: 30 créditos
  Saldo actual: <N> créditos

  ¿Procedo?

Para pipelines de múltiples pasos (texto a 3D → rigging → animación), muestra el costo TOTAL del pipeline por adelantado.

Nota: El rigging incluye automáticamente animaciones de caminar y correr sin costo adicional. Solo agrega Animar (3 créditos) para animaciones personalizadas más allá de esas.

Mapeo de intención a API

El usuario quiere...APIEndpointCréditos
Modelo 3D desde textoTexto a 3DPOST /openapi/v2/text-to-3d5–20 (vista previa) + 10 (refinar)
Modelo 3D desde una imagenImagen a 3DPOST /openapi/v1/image-to-3d5–30
Modelo 3D desde múltiples imágenesMulti-Imagen a 3DPOST /openapi/v1/multi-image-to-3d5–30
Nuevas texturas en modelo existenteRetexturizarPOST /openapi/v1/retexture10
Cambiar formato/topología de mallaRemallarPOST /openapi/v1/remesh5
Convertir un modelo a otros formatos (sin remallar)ConvertirPOST /openapi/v1/convert1
Reescalar un modelo al tamaño del mundo realRedimensionarPOST /openapi/v1/resize1
Generar UVs nuevas (GLB, ≤40k caras) antes de texturizado externoDesenvolver UVPOST /openapi/v1/uv-unwrap5
Agregar esqueleto a personajeRigging automáticoPOST /openapi/v1/rigging5
Animar un personaje con riggingAnimaciónPOST /openapi/v1/animations3
Imagen 2D desde texto (paso previo recomendado antes de imagen a 3D)Texto a ImagenPOST /openapi/v1/text-to-image3 / 6 / 9 / 9
Optimizar/editar una imagen 2D (paso previo recomendado antes de imagen a 3D)Imagen a ImagenPOST /openapi/v1/image-to-image3 / 6 / 9 / 12
Foto → producto físico estilizado (figura/lámpara/llavero/imán de nevera)Laboratorio CreativoPOST /openapi/creative-lab/{producto}/v1/prototype luego .../build6 + 30
Verificar imprimibilidad FDMAnalizar ImprimibilidadPOST /openapi/v1/print/analyze0 (gratis)
Reparar topología no múltiple/caras degeneradas/agujerosReparar ImprimibilidadPOST /openapi/v1/print/repair10
Impresión 3D multicolorImpresión MulticolorPOST /openapi/v1/print/multi-color10 (+ generación)
Impresión 3D de un modelo (blanco)→ Ver sección Pipeline de Impresión—20
Verificar saldo de créditosSaldoGET /openapi/v1/balance0

Paso 2: Ejecutar el flujo de trabajo

Plantilla de script reutilizable

Usa esto como base para TODOS los flujos de trabajo. Carga la clave API de forma segura desde el entorno o .env solo en el directorio actual:

#!/usr/bin/env python3
"""Ejecutor de tareas de la API de Meshy. Maneja crear → sondear → descargar."""
import requests, time, os, sys, re, json
from datetime import datetime

# --- Carga segura de clave API ---
def load_api_key():
    """Carga MESHY_API_KEY del entorno, luego de .env en el cwd únicamente."""
    key = os.environ.get("MESHY_API_KEY", "").strip()
    if key:
        return key
    env_path = os.path.join(os.getcwd(), ".env")
    if os.path.exists(env_path):
        with open(env_path) as f:
            for line in f:
                line = line.strip()
                if line.startswith("MESHY_API_KEY=") and not line.startswith("#"):
                    val = line.split("=", 1)[1].strip().strip('"').strip("'")
                    if val:
                        return val
    return ""

API_KEY = load_api_key()
if not API_KEY:
    sys.exit("ERROR: MESHY_API_KEY no configurada. Ejecuta el Paso 0a para configurarla.")

# Nunca registrar la clave completa — solo los primeros 8 caracteres para trazabilidad
print(f"Clave API cargada: {API_KEY[:8]}...")

BASE = "https://api.meshy.ai"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
SESSION = requests.Session()
SESSION.trust_env = False  # omitir cualquier configuración de proxy del sistema

def create_task(endpoint, payload):
    resp = SESSION.post(f"{BASE}{endpoint}", headers=HEADERS, json=payload, timeout=30)
    if resp.status_code == 401:
        sys.exit("ERROR: Clave API inválida (401). Re-ejecuta el Paso 0a.")
    if resp.status_code == 402:
        try:
            bal = SESSION.get(f"{BASE}/openapi/v1/balance", headers=HEADERS, timeout=10)
            balance = bal.json().get("balance", "desconocido")
            sys.exit(f"ERROR: Créditos insuficientes (402). Saldo: {balance}. Recarga en https://www.meshy.ai/pricing")
        except Exception:
            sys.exit("ERROR: Créditos insuficientes (402). Verifica saldo en https://www.meshy.ai/pricing")
    if resp.status_code == 429:
        sys.exit("ERROR: Límite de tasa excedido (429). Espera y reintenta.")
    resp.raise_for_status()
    task_id = resp.json()["result"]
    print(f"TAREA_CREADA: {task_id}")
    return task_id

def poll_task(endpoint, task_id, timeout=300):
    """Sondea con retroceso exponencial (5s→30s, fijo 15s al 95%+)."""
    elapsed, delay, max_delay, backoff, finalize_delay, poll_count = 0, 5, 30, 1.5, 15, 0
    while elapsed < timeout:
        poll_count += 1
        resp = SESSION.get(f"{BASE}{endpoint}/{task_id}", headers=HEADERS, timeout=30)
        resp.raise_for_status()
        task = resp.json()
        status = task["status"]
        progress = task.get("progress", 0)
        bar = f"[{'█' * int(progress/5)}{'░' * (20 - int(progress/5))}] {progress}%"
        print(f"  {bar} — {status} ({elapsed}s, sondeo #{poll_count})", flush=True)
        if status == "SUCCEEDED":
            return task
        if status in ("FAILED", "CANCELED"):
            msg = task.get("task_error", {}).get("message", "Desconocido")
            sys.exit(f"TAREA_{status}: {msg}")
        current_delay = finalize_delay if progress >= 95 else delay
        time.sleep(current_delay)
        elapsed += current_delay
        if progress < 95:
            delay = min(delay * backoff, max_delay)
    sys.exit(f"TIEMPO_AGOTADO después de {timeout}s ({poll_count} sondeos)")

def download(url, filepath):
    """Descarga un archivo en un directorio de proyecto (dentro de cwd/meshy_output/)."""
    os.makedirs(os.path.dirname(filepath), exist_ok=True)
    print(f"Descargando {filepath}...", flush=True)
    resp = SESSION.get(url, timeout=300, stream=True)
    resp.raise_for_status()
    with open(filepath, "wb") as f:
        for chunk in resp.iter_content(chunk_size=8192):
            f.write(chunk)
    print(f"DESCARGADO: {filepath} ({os.path.getsize(filepath)/1024/1024:.1f} MB)")

# --- Ayudantes de organización de archivos ---
OUTPUT_ROOT = os.path.join(os.getcwd(), "meshy_output")
os.makedirs(OUTPUT_ROOT, exist_ok=True)
HISTORY_FILE = os.path.join(OUTPUT_ROOT, "history.json")

def get_project_dir(task_id, prompt="", task_type="model"):
    slug = re.sub(r'[^a-z0-9]+', '-', (prompt or task_type).lower())[:30].strip('-')
    folder = f"{datetime.now().strftime('%Y%m%d_%H%M%S')}_{slug}_{task_id[:8]}"
    project_dir = os.path.join(OUTPUT_ROOT, folder)
    os.makedirs(project_dir, exist_ok=True)
    return project_dir

def record_task(project_dir, task_id, task_type, stage, prompt="", files=None):
    meta_path = os.path.join(project_dir, "metadata.json")
    meta = json.load(open(meta_path)) if os.path.exists(meta_path) else {
        "project_name": prompt or task_type, "folder": os.path.basename(project_dir),
        "root_task_id": task_id, "created_at": datetime.now().isoformat(), "tasks": []
    }
    meta["tasks"].append({"task_id": task_id, "task_type": task_type, "stage": stage,
                          "files": files or [], "created_at": datetime.now().isoformat()})
    meta["updated_at"] = datetime.now().isoformat()
    json.dump(meta, open(meta_path, "w"), indent=2)
    history = json.load(open(HISTORY_FILE)) if os.path.exists(HISTORY_FILE) else {"version": 1, "projects": []}
    folder = os.path.basename(project_dir)
    entry = next((p for p in history["projects"] if p["folder"] == folder), None)
    if entry:
        entry.update({"task_count": len(meta["tasks"]), "updated_at": meta["updated_at"]})
    else:
        history["projects"].append({"folder": folder, "prompt": prompt, "task_type": task_type,
            "root_task_id": task_id, "created_at": meta["created_at"],
            "updated_at": meta["updated_at"], "task_count": len(meta["tasks"])})
    json.dump(history, open(HISTORY_FILE, "w"), indent=2)

def save_thumbnail(project_dir, url):
    path = os.path.join(project_dir, "thumbnail.png")
    if os.path.exists(path): return
    try:
        r = SESSION.get(url, timeout=15); r
...

[truncado para traducción]

Paso 3: Descargar y organizar resultados


Paso 4: Preparación para impresión 3D


Paso 5: Manejo de errores y reintentos


Solución de problemas


Referencia de API


Ejemplos


Skills relacionados