Communitygithub.com

Meshy 3D — Geração + Impressão

Habilidades de agente de IA para a plataforma de geração 3D Meshy AI.

O que é Meshy 3D — Geração + Impressão?

Este skill permite que agentes de IA (como Claude Code, Cursor, Codex) interajam diretamente com a API do Meshy AI para gerar, refinar e preparar ativos 3D para impressão. Ele cobre todo o ciclo de vida: configuração de chave de API, criação de tarefas (texto-para-3D, imagem-para-3D, retexturização, rigging, animação, etc.), polling com backoff exponencial, download de modelos, pipelines de múltiplas etapas e integração com slicer para impressão 3D. O skill gerencia credenciais com segurança, organiza downloads em pastas estruturadas por projeto e mantém um histórico de tarefas. É útil para desenvolvedores e artistas 3D que desejam automatizar a criação de ativos 3D, desde a geração até a impressão, reduzindo o trabalho manual e acelerando o fluxo de trabalho.

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

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que Meshy 3D — Geração + Impressão faz?

Comunique-se diretamente com a API do Meshy AI para gerar e imprimir ativos 3D. Abrange o ciclo de vida completo: configuração de chave API, criação de tarefas, polling com backoff exponencial, download, pipelines de várias etapas e preparação para impressão 3D com integração de slicer.


MANIFESTO DE SEGURANÇA

Variáveis de ambiente acessadas:

  • MESHY_API_KEY — Token de autenticação da API enviado apenas no cabeçalho HTTP Authorization: Bearer. Nunca registrado em log, nunca gravado em nenhum arquivo, exceto .env no diretório de trabalho atual quando explicitamente solicitado pelo usuário.

Endpoints de rede externos:

  • https://api.meshy.ai — API do Meshy AI (criação de tarefas, polling de status, downloads de modelo/imagem)

Acesso ao sistema de arquivos:

  • Leitura: .env no diretório de trabalho atual apenas (consulta de chave API)
  • Escrita: .env no diretório de trabalho atual apenas (armazenamento de chave API, somente por solicitação do usuário)
  • Escrita: ./meshy_output/ no diretório de trabalho atual (arquivos de modelo baixados, metadados)
  • Leitura: arquivos fornecidos explicitamente pelo usuário (ex.: imagens locais passadas para conversão imagem-para-3D), acessados apenas no caminho exato especificado pelo usuário
  • Sem acesso a diretórios home, perfis de shell ou qualquer caminho fora dos listados acima

Dados que saem desta máquina:

  • Requisições de API para api.meshy.ai incluem o MESHY_API_KEY no cabeçalho Authorization e prompts de texto fornecidos pelo usuário ou URLs de imagem. Nenhum outro dado local é transmitido. Arquivos de modelo baixados são salvos apenas localmente.

IMPORTANTE: Aviso de Primeiro Uso na Sessão

Quando este skill for ativado pela primeira vez em uma sessão, informe o usuário:

Todos os arquivos gerados serão salvos em meshy_output/ no diretório de trabalho atual. Cada projeto terá sua própria pasta ({YYYYMMDD_HHmmss}_{prompt}_{id}/) com arquivos de modelo, texturas, miniaturas e metadados. O histórico é rastreado em meshy_output/history.json.

Isso só precisa ser dito uma vez por sessão.


IMPORTANTE: Organização de Arquivos

Todos os arquivos baixados DEVEM ir para um diretório estruturado meshy_output/ no diretório de trabalho atual. NÃO espalhe arquivos aleatoriamente.

  • Cada projeto: meshy_output/{YYYYMMDD_HHmmss}_{prompt_slug}_{task_id_prefix}/
  • Tarefas em cadeia (preview → refine → rig) reutilizam o mesmo project_dir
  • Rastreie tarefas em metadata.json por projeto e globalmente em history.json
  • Baixe miniaturas automaticamente junto com os modelos

IMPORTANTE: Regras de Comando Shell

Use apenas ferramentas POSIX padrão. NÃO use rg, fd, bat, exa/eza.


IMPORTANTE: Execute Tarefas Longas Corretamente

A geração do Meshy leva de 1 a 5 minutos. Escreva todo o fluxo create → poll → download como UM script Python e execute em uma única chamada Bash. Use python3 -u script.py para saída sem buffer. Tarefas paradas em 99% por 30–120s é uma finalização normal — NÃO interrompa.


Passo 0: Detecção de Chave API (SEMPRE EXECUTE PRIMEIRO)

Verifique apenas o ambiente da sessão atual e o arquivo .env no diretório de trabalho atual. NÃO escaneie diretórios home ou arquivos de perfil de shell.

echo "=== Detecção de Chave API Meshy ==="

# 1. Verificar variável de ambiente atual
if [ -n "$MESHY_API_KEY" ]; then
  echo "ENV_VAR: ENCONTRADA (${MESHY_API_KEY:0:8}...)"
else
  echo "ENV_VAR: NÃO_ENCONTRADA"
fi

# 2. Verificar .env no diretório de trabalho atual apenas
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. Status final
if [ -n "$MESHY_API_KEY" ]; then
  echo "PRONTO: key=${MESHY_API_KEY:0:8}..."
else
  echo "PRONTO: NENHUMA_CHAVE_ENCONTRADA"
fi

# 4. Verificar requests do Python
python3 -c "import requests; print('PYTHON_REQUESTS: OK')" 2>/dev/null || echo "PYTHON_REQUESTS: AUSENTE (execute: pip install requests)"

echo "=== Detecção Completa ==="

Decisão Após Detecção

  • Chave encontrada → Prossiga para o Passo 1.
  • Chave NÃO encontrada → Vá para o Passo 0a.
  • Requests do Python ausentes → Execute pip install requests.

Passo 0a: Configuração de Chave API (Apenas Se Nenhuma Chave For Encontrada)

Diga ao usuário:

Para usar a API do Meshy, você precisa de uma chave de API:

  1. Vá para https://www.meshy.ai/settings/api
  2. Clique em "Create API Key", dê um nome, e copie a chave (começa com msy_)
  3. A chave é mostrada apenas uma vez — guarde-a em um local seguro

Nota: O acesso à API requer um plano Pro ou superior. Contas do plano gratuito não podem criar chaves de API.

Quando o usuário fornecer a chave, configure-a para a sessão atual e, opcionalmente, persista no .env:

# Configurar apenas para a sessão atual
export MESHY_API_KEY="msy_COLE_A_CHAVE_AQUI"

# Verificar a chave
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 "Chave válida. $BALANCE"
else
  echo "Chave inválida (HTTP $STATUS). Verifique a chave e tente novamente."
fi

Para persistir a chave (apenas no projeto atual):

# Escrever no .env no diretório de trabalho atual
echo 'MESHY_API_KEY=msy_COLE_A_CHAVE_AQUI' >> .env
echo "Salva em .env"

# IMPORTANTE: adicione .env ao .gitignore para evitar vazamento da chave
grep -q "^\.env" .gitignore 2>/dev/null || echo ".env" >> .gitignore
echo ".env adicionado ao .gitignore"

Lembrete de segurança: A chave é armazenada apenas em .env no diretório do seu projeto atual. Nunca comprometa este arquivo no controle de versão. O .env foi adicionado automaticamente ao .gitignore.


Passo 1: Confirmar Plano com o Usuário Antes de Gastar Créditos

CRÍTICO: Antes de criar qualquer tarefa, apresente ao usuário um resumo de custos e aguarde confirmação:

Vou gerar um modelo 3D de "<prompt>" usando o seguinte plano:

  1. Preview (geração de malha) — 20 créditos
  2. Refinar (texturização com PBR) — 10 créditos
  3. Download como .glb

  Custo total: 30 créditos
  Saldo atual: <N> créditos

  Devo prosseguir?

Para pipelines de várias etapas (texto-para-3d → rig → animar), mostre o custo TOTAL do pipeline antecipadamente.

Nota: A rigging inclui automaticamente animações de caminhada e corrida sem custo extra. Adicione Animate (3 créditos) apenas para animações personalizadas além dessas.

Mapeamento Intenção → API

O usuário deseja...APIEndpointCréditos
Modelo 3D a partir de textoTexto para 3DPOST /openapi/v2/text-to-3d5–20 (preview) + 10 (refine)
Modelo 3D a partir de uma imagemImagem para 3DPOST /openapi/v1/image-to-3d5–30
Modelo 3D a partir de múltiplas imagensMulti-Imagem para 3DPOST /openapi/v1/multi-image-to-3d5–30
Novas texturas em modelo existenteRetexturizarPOST /openapi/v1/retexture10
Alterar formato/topologia da malhaRemalharPOST /openapi/v1/remesh5
Converter um modelo para outros formatos (sem remalhagem)ConverterPOST /openapi/v1/convert1
Redimensionar um modelo para tamanho realRedimensionarPOST /openapi/v1/resize1
Gerar UVs novas (GLB, ≤40k faces) antes de texturização externaUV UnwrapPOST /openapi/v1/uv-unwrap5
Adicionar esqueleto a personagemAuto-RiggingPOST /openapi/v1/rigging5
Animar um personagem com rigAnimaçãoPOST /openapi/v1/animations3
Imagem 2D a partir de texto (pré-etapa recomendada antes de imagem-para-3d)Texto para ImagemPOST /openapi/v1/text-to-image3 / 6 / 9 / 9
Otimizar/editar uma imagem 2D (pré-etapa recomendada antes de imagem-para-3d)Imagem para ImagemPOST /openapi/v1/image-to-image3 / 6 / 9 / 12
Foto → produto físico estilizado (figura/luminária/chaveiro/imã de geladeira)Creative LabPOST /openapi/creative-lab/{product}/v1/prototype depois .../build6 + 30
Verificar imprimibilidade FDMAnalisar ImprimibilidadePOST /openapi/v1/print/analyze0 (grátis)
Reparar topologia não-manifold/face degenerada/buracoReparar ImprimibilidadePOST /openapi/v1/print/repair10
Impressão 3D multicolorImpressão Multi-ColorPOST /openapi/v1/print/multi-color10 (+ geração)
Imprimir em 3D um modelo (branco)→ Veja a seção Pipeline de Impressão—20
Verificar saldo de créditosSaldoGET /openapi/v1/balance0

Passo 2: Executar o Fluxo de Trabalho

Template de Script Reutilizável

Use este modelo como base para TODOS os fluxos de trabalho. Ele carrega a chave API com segurança do ambiente ou do .env apenas no diretório atual:

#!/usr/bin/env python3
"""Executor de tarefas da API Meshy. Lida com create → poll → download."""
import requests, time, os, sys, re, json
from datetime import datetime

# --- Carregamento seguro da chave API ---
def load_api_key():
    """Carrega MESHY_API_KEY do ambiente e depois do .env no cwd."""
    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 não definida. Execute o Passo 0a para configurá-la.")

# Nunca registre a chave completa — apenas os primeiros 8 caracteres para rastreabilidade
print(f"Chave API carregada: {API_KEY[:8]}...")

BASE = "https://api.meshy.ai"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
SESSION = requests.Session()
SESSION.trust_env = False  # ignorar configurações de proxy do 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: Chave API inválida (401). Re-execute o Passo 0a.")
    if resp.status_code == 402:
        try:
            bal = SESSION.get(f"{BASE}/openapi/v1/balance", headers=HEADERS, timeout=10)
            balance = bal.json().get("balance", "desconhecido")
            sys.exit(f"ERROR: Créditos insuficientes (402). Saldo: {balance}. Recarregue em https://www.meshy.ai/pricing")
        except Exception:
            sys.exit("ERROR: Créditos insuficientes (402). Verifique o saldo em https://www.meshy.ai/pricing")
    if resp.status_code == 429:
        sys.exit("ERROR: Limite de taxa excedido (429). Aguarde e tente novamente.")
    resp.raise_for_status()
    task_id = resp.json()["result"]
    print(f"TAREFA_CRIADA: {task_id}")
    return task_id

def poll_task(endpoint, task_id, timeout=300):
    """Poll com backoff exponencial (5s→30s, fixo 15s em 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, poll #{poll_count})", flush=True)
        if status == "SUCCEEDED":
            return task
        if status in ("FAILED", "CANCELED"):
            msg = task.get("task_error", {}).get("message", "Desconhecido")
            sys.exit(f"TAREFA_{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"TIMEOUT após {timeout}s ({poll_count} polls)")

def download(url, filepath):
    """Baixa um arquivo para um diretório de projeto (dentro de cwd/meshy_output/)."""
    os.makedirs(os.path.dirname(filepath), exist_ok=True)
    print(f"Baixando {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"BAIXADO: {filepath} ({os.path.getsize(filepath)/1024/1024:.1f} MB)")

# --- Auxiliares de organização de arquivos ---
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

…

Pipeline Completo de Geração

M.1: Texto para 3D com Refinamento

  1. Crie um preview de texto para 3D (POST /openapi/v2/text-to-3d com mode=preview).
  2. Faça polling até SUCCEEDED, capture model_urls (glb, obj, usdz, stl, fbx).
  3. Baixe para project_dir/model.glb, etc. Salve a miniatura.
  4. Crie uma tarefa de refinamento (POST /openapi/v2/text-to-3d com mode=refine).
    • Defina preview_task_id para o ID do preview.
    • Defina texture_quality como ultra (padrão a menos que o usuário peça menor).
    • Defina pbr como true para iluminação realista (padrão).
  5. Faça polling até SUCCEEDED e baixe o .glb PBR refinado.
  6. Atualize metadata.json; registre ambos os IDs de tarefa.

M.2: Imagem para 3D

  1. Determine se o usuário forneceu uma imagem local ou URL.
    • Se o arquivo de imagem for local, leia-o, codifique em base64 e defina na solicitação.
    • Se o arquivo de imagem for uma URL, use a URL como image_url.
    • Para multi-imagem, forneça image_urls.
  2. Crie a tarefa de imagem para 3D (POST /openapi/v1/image-to-3d).
    • Defina enable_pbr como true (padrão para texturas PBR).
  3. Faça polling até SUCCEEDED e baixe os modelos.
  4. Para refinamento, re-texturize com POST /openapi/v1/retexture.

M.3: Retexturização

  1. Crie uma tarefa de retexturização (POST /openapi/v1/retexture) com model_url e um novo prompt de textura.
  2. Faça polling até SUCCEEDED e baixe o modelo retexturizado.

M.4: Remalhagem

  1. Crie uma tarefa de remalhagem (POST /openapi/v1/remesh) com model_url e configuração de destino (ex.: target_count=20000).
  2. Faça polling até SUCCEEDED e baixe o modelo remalhado.

M.5: Rigging de Personagem

  1. Crie uma tarefa de rigging (POST /openapi/v1/rigging) com model_url.
  2. Faça polling até SUCCEEDED e baixe o .glb com rig.

M.6: Animação

  1. Crie uma tarefa de animação (POST /openapi/v1/animations) com model_url.
  2. Defina animações como uma lista (ex.: ["walk", "run"]).
  3. Faça polling até SUCCEEDED e baixe o .glb animado.

M.7: UV Unwrap

  1. Crie uma tarefa de UV Unwrap (POST /openapi/v1/uv-unwrap) com model_url.
  2. Faça polling até SUCCEEDED e baixe o .glb com UVs frescas.

M.8: Conversão de Formato

  1. Crie uma tarefa de conversão (POST /openapi/v1/convert) com model_url e format alvo (ex.: "obj", "stl", "glb").
  2. Faça polling até SUCCEEDED e baixe o modelo convertido.

M.9: Redimensionamento para Tamanho Real

  1. Crie uma tarefa de redimensionamento (POST /openapi/v1/resize) com model_url e scale_factor ou dimensão alvo.
  2. Faça polling até SUCCEEDED e baixe o modelo redimensionado.

Pipeline de Impressão 3D

P.1: Pipeline de Impressão 3D Completo (20 créditos)

Este skill suporta o pipeline completo de impressão:

  1. Solicite o prompt do usuário para o que eles querem imprimir.
  2. Gere um preview 3D (Modo de Malha) — 20 créditos.
  3. Baixe o modelo e salve na pasta do projeto.
  4. Ofereça ao usuário três opções de download:
    • Opção A: Baixar modelo 3D para slicer externo (Cura, PrusaSlicer, Bambu Studio, etc.)
    • Opção B: Usar o serviço de impressão do Meshy (modelo branco, 20 créditos) — construído, impresso e enviado para você.
    • Opção C: Impressão multicolor do Meshy (gera um modelo 3D colorido, 10 créditos + custos de geração).

Nota: Se o usuário escolher modelo para download (Opção A), baixe como .stl para impressão FDM padrão.

P.2: Análise de Imprimibilidade (grátis)

  1. Crie uma tarefa de análise (POST /openapi/v1/print/analyze) com model_url.
  2. Faça polling até SUCCEEDED e exiba:
    • Status de análise (imprimível/não imprimível)
    • Erros de topologia
    • Avisos

P.3: Reparo de Imprimibilidade (10 créditos)

  1. Crie uma tarefa de reparo (POST /openapi/v1/print/repair) com model_url.
  2. Faça polling até SUCCEEDED e baixe o modelo reparado.

P.4: Impressão Multicolor (10 créditos + geração)

  1. Crie uma tarefa de impressão multicolor (POST /openapi/v1/print/multi-color) com model_url.
  2. Faça polling até SUCCEEDED e mostre ao usuário o resultado da pré-visualização.
  3. Se o usuário aprovar, prossiga com a impressão.

Tratamento de Erros

Erros Comuns de API

CódigoSignificadoAção do Agente
401Chave API inválidaInforme o usuário para verificar a chave e executar o Passo 0a
402Créditos insuficientesInforme o saldo e o link para recarga; pare
429Limite de taxa excedidoAguarde 60s e tente novamente (até 3 tentativas)
5xxErro do servidor MeshyAguarde 30s e tente novamente (até 3 tentativas)
Falha de redeConectividade de redeVerifique a conexão de internet do usuário e o acesso ao api.meshy.ai

Erros de Tarefa

Quando status == "FAILED", o campo task_error.message normalmente contém detalhes. Causas comuns:

  • Seu prompt não gerou um resultado utilizável (tente com um prompt mais descritivo)
  • A imagem de entrada não se parece com um objeto 3D (use imagens com fundo limpo e assunto claro)
  • O modelo de entrada para pós-processamento está corrompido ou em formato não suportado

Timeout

Se uma tarefa exceder 300s, o script irá parar. O polling será retomado se você verificar a tarefa diretamente via API. Mantenha o task_id e o project_dir nos metadados para referência posterior.


Informações de Preços e Planos

  • API Keys: Apenas planos Pro ($24/mês) ou superiores podem criar chaves de API.
  • Créditos: 1 crédito ≈ $0,01 (os preços podem variar). O saldo atual pode ser verificado via GET /openapi/v1/balance.
  • Recarga: Adicione créditos em https://www.meshy.ai/pricing
  • Limites de taxa: Dependem do plano. A maioria dos endpoints aceita ~10 solicitações concorrentes.

Exemplos

Exemplo 1: Gema de Dragão

Usuário: "Gere e faça o download de uma gema de dragão"

  1. Detectar chave API
  2. Confirmar: "Preview de texto-para-3D (20 créditos) + Refinamento PBR (10 créditos) = 30 créditos. Prosseguir?"
  3. Criar preview de texto-para-3D com prompt="gema de dragão"
  4. Polling até SUCCEEDED (45s), baixar glb, obj, stl, fbx
  5. Criar refinamento com o preview_task_id
  6. Polling até SUCCEEDED (60s), baixar modelo PBR
  7. Estrutura de diretório:
    meshy_output/
    └─ 20250315_120500_gema-de-dragao_a1b2c3d4/
        ├─ thumbnail.png
        ├─ model.glb
        ├─ model_pbr.glb
        ├─ model.obj
        ├─ model.stl
        └─ metadata.json
    

Habilidades Relacionadas