Back to list
Gravesjacob778

gltf-structure-analyzer

by Gravesjacob778

0🍴 0📅 Jan 20, 2026

SKILL.md


name: gltf-structure-analyzer description: Expert in analyzing and validating GLTF/GLB file structure for 3D robot models, identifying mesh hierarchies, joint configurations, and preparing models for Three.js integration

GLTF Structure Analyzer Skill

This skill specializes in analyzing GLTF/GLB file structures to validate model hierarchies, identify mesh organization, and diagnose issues before importing into Three.js/React Three Fiber applications.

Quick Diagnosis: Structure Inspector

Use this utility to analyze any GLTF file and understand its internal hierarchy:

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';

const loader = new GLTFLoader();

loader.load('source/scene.gltf', (gltf) => {
  const model = gltf.scene;
  
  console.log('=== 🔍 GLTF Structure Analysis ===');
  console.log(`File: scene.gltf`);
  console.log(`Total Objects: ${countObjects(model)}`);
  console.log(`Total Meshes: ${countMeshes(model)}`);
  console.log('\n=== 📊 Object Hierarchy ===\n');
  
  let indent = '';
  model.traverse((child) => {
    const depth = getDepth(child);
    indent = '  '.repeat(depth);
    
    let info = `${indent}├─ ${child.name || '(unnamed)'}`;
    info += ` [${child.type}]`;
    
    if (child.isMesh) {
      info += ` 📦 Geometry: ${child.geometry.attributes.position.count} vertices`;
      if (child.material) {
        info += ` | Material: ${child.material.name || child.material.type}`;
      }
    }
    
    if (child.children.length > 0) {
      info += ` (${child.children.length} children)`;
    }
    
    console.log(info);
  });
  
  console.log('\n=== 🔗 Joint Candidates ===');
  analyzeJoints(model);
});

function getDepth(object) {
  let depth = 0;
  let current = object;
  while (current.parent) {
    depth++;
    current = current.parent;
  }
  return depth;
}

function countObjects(object) {
  let count = 0;
  object.traverse(() => count++);
  return count;
}

function countMeshes(object) {
  let count = 0;
  object.traverse((child) => {
    if (child.isMesh) count++;
  });
  return count;
}

function analyzeJoints(model) {
  const jointPatterns = ['joint', 'bone', 'armature', 'link', 'axis'];
  const candidates = [];
  
  model.traverse((child) => {
    const name = child.name.toLowerCase();
    if (jointPatterns.some(pattern => name.includes(pattern))) {
      candidates.push({
        name: child.name,
        type: child.type,
        children: child.children.length,
        depth: getDepth(child)
      });
    }
  });
  
  if (candidates.length === 0) {
    console.log('⚠️ No obvious joint names detected (e.g., no "joint", "bone", etc.)');
    console.log('📋 Recommendation: Model may need renaming in Blender');
  } else {
    candidates.forEach((joint) => {
      console.log(`  ✓ ${joint.name} [${joint.type}] - ${joint.children} children`);
    });
  }
}

3 Common Structure Scenarios

🔴 Scenario A: Single Monolithic Mesh (❌ Problem!)

Output Example:

Scene
 └─ RobotArm_Mesh [Mesh] 📦 (50000 vertices)

Problem: Entire robot is one mesh → Cannot control individual joints

Severity: 🔴 Critical - Must rebuild in Blender

Solution: Separate mesh into components by loose parts or manual selection


🟡 Scenario B: Hierarchical but Unclear Names (⚠️ Difficult)

Output Example:

Scene
 └─ Object_0 [Group]
     ├─ Object_1 [Group] (2 children)
     │   ├─ Mesh_0 📦 (8000 vertices)
     │   └─ Mesh_1 📦 (6000 vertices)
     └─ Object_2 [Group] (1 child)
         └─ Mesh_2 📦 (5000 vertices)

Problem: Cannot identify which mesh belongs to which joint

Severity: 🟡 Medium - Requires detective work or re-export

Solution: Use Blender to rename objects and rebuild hierarchy


🟢 Scenario C: Perfect Structure (✅ Lucky!)

Output Example:

Scene
 └─ Base [Group]
     ├─ Joint1 [Group]
     │   ├─ Link1 [Mesh] 📦 (4000 vertices)
     │   └─ Joint2 [Group]
     │       ├─ Link2 [Mesh] 📦 (3500 vertices)
     │       └─ Joint3 [Group]

Problem: None! ✅

Severity: 🟢 Ready to use

Solution: Load directly and map to joint controllers


Step 1: Import GLTF File

1. Open Blender
2. File → Import → glTF 2.0 (.glTf/.glb)
3. Select your scene.gltf file
4. Click Import

Step 2: Inspect Model Structure

1. Select the model (click on it in viewport)
2. Press Z → Wireframe (see skeleton)
3. Right side panel → Outliner (see hierarchy)
4. Expand all objects to understand structure

Step 3: Separate Mesh into Components

Method A: By Loose Parts (Best if components are already separated)

1. Select the main mesh object
2. Press Tab → Enter Edit Mode
3. Press A → Select All
4. Mesh → Separate → By Loose Parts
5. Press Tab → Return to Object Mode
Result: One mesh becomes multiple objects

Method B: Manual Selection (For connected meshes)

1. Select main mesh → Press Tab (Edit Mode)
2. Press Alt+A to deselect all
3. Move mouse to the first component (e.g., base)
4. Press L → Select this component
5. Press P → Separate → Selection
6. Repeat for each component

Step 4: Rename Objects Clearly

In Outliner on the right:
1. Double-click object name
2. Rename to meaningful names:
   - Base (mount)
   - Joint1 (base rotation axis)
   - Link1 (arm segment 1)
   - Joint2 (shoulder)
   - Link2 (arm segment 2)
   - Joint3 (elbow)
   - Link3 (forearm)
   - Joint4 (wrist roll)
   - Joint5 (wrist pitch)
   - Joint6 (wrist yaw)
   - EndEffector (gripper)

Step 5: Build Proper Hierarchy

In Outliner (drag to create parent-child relationships):

Base (will be root)
 └─ Joint1
     └─ Link1
         └─ Joint2
             └─ Link2
                 └─ Joint3
                     └─ Link3
                         └─ Joint4
                             └─ Joint5
                                 └─ Joint6
                                     └─ EndEffector

Drag order:
1. Drag Link1 → onto Joint1 (makes Link1 child of Joint1)
2. Drag Joint2 → onto Link1
3. Drag Link2 → onto Joint2
... continue for all joints

Critical: Each joint's origin must be at its rotation axis!

Fix Joint Origins:

1. Select Joint1
2. Object Mode (Tab)
3. Set 3D Cursor to rotation center:
   - Shift+S → Cursor to Selection (temporary)
   - Manually position cursor with Shift+RMB
4. Right-click → Set Origin → Origin to 3D Cursor
5. Repeat for all joints

Step 6: Export to GLB

File → Export → glTF 2.0 (.glTF Binary)

Settings:
✅ Format: glTF Binary (.glb)     ← Recommended (smaller file)
✅ Include → Animations           ← If robot has animations
✅ Include → All Bone Influences
✅ Transform → Y Up
✅ Geometry → Apply Modifiers
✅ Geometry → Apply Mesh
❌ Uncheck: Include → All Influences (unneeded for static)

Save as: robot_arm_rigged.glb

Solution 2: Verify Structure with Debugging Utility

Create a React component to inspect loaded models:

// components/GLTFDebugger.tsx
import { useEffect } from 'react';
import { useGLTF } from '@react-three/drei';

export function GLTFDebugger({ modelPath }: { modelPath: string }) {
  const gltf = useGLTF(modelPath);
  
  useEffect(() => {
    console.log('=== GLTF Model Debug Info ===');
    console.log('Path:', modelPath);
    console.log('Scene:', gltf.scene);
    console.log('Animations:', gltf.animations);
    
    // Build hierarchy string
    let hierarchyStr = '';
    gltf.scene.traverse((obj) => {
      const depth = getDepth(obj);
      const indent = '  '.repeat(depth);
      hierarchyStr += `\n${indent}${obj.name || '(unnamed)'} [${obj.type}]`;
    });
    
    console.log('\n=== Hierarchy ===', hierarchyStr);
    
    // Find all meshes
    const meshes: any[] = [];
    gltf.scene.traverse((obj) => {
      if (obj.isMesh) meshes.push(obj.name);
    });
    console.log('Meshes found:', meshes);
    
  }, [gltf, modelPath]);
  
  return null; // Invisible debug component
}

function getDepth(object: any) {
  let depth = 0;
  let current = object;
  while (current.parent) {
    depth++;
    current = current.parent;
  }
  return depth;
}

Usage:

<Canvas>
  <GLTFDebugger modelPath="/models/robot.glb" />
  <RobotModel />
</Canvas>

Diagnostic Checklist

Use this checklist to validate your GLTF structure:

  • Model loads without errors
  • Scene has meaningful hierarchy (not flat)
  • Objects are named clearly (not "Object_0", "Mesh_1", etc.)
  • Mesh count matches expected components
  • No single mesh contains all geometry
  • Parent-child relationships make sense
  • Joint names indicate rotation axes
  • Origins are positioned correctly for rotation
  • Animations are preserved (if applicable)
  • File size is reasonable for target platform

When to Use This Skill

✅ Loading a new GLTF robot model
✅ Debugging why joints don't rotate correctly
✅ Identifying mesh organization issues
✅ Preparing models for kinematic chains
✅ Validating Blender exports


  • 3d-robot-model: Creating high-fidelity robot models with proper materials
  • 3d-physics-visualization: Rendering GLTF models in Three.js/R3F

Score

Total Score

50/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon