
Blender Threejs Export
Export the current Blender scene to GLB plus a standalone Three.js HTML viewer with orbit controls and studio lighting.
Install
npx skills add https://github.com/kevinbadi/blender-skills --skill blender-threejs-exportWhat is this skill?
- Exports current Blender scene as GLB via Blender MCP execute_code over localhost socket
- Generates standalone Three.js HTML with orbit controls and studio lighting
- CLI flags: --output, --name, --port, --no-rotate, --bg color, --embed
- Default MCP port 9876 with 120s socket timeout for export operations
- Optional embed mode for dropping the viewer into an existing page
Adoption & trust: 1 installs on skills.sh; 15 GitHub stars; trending (+100% hot-view momentum).
Recommended Skills
Frontend Designanthropics/skills
Vercel React Best Practicesvercel-labs/agent-skills
Remotion Best Practicesremotion-dev/skills
Vercel Composition Patternsvercel-labs/agent-skills
Develop Userscriptsxixu-me/skills
Next Best Practicesvercel-labs/next-skills
Journey fit
Primary fit
Build/frontend is the canonical shelf because the deliverable is a web-viewable 3D asset pipeline from Blender to browser. Frontend subphase fits GLB export, embedded or standalone HTML viewer, and Three.js presentation rather than backend APIs.
SKILL.md
READMESKILL.md - Blender Threejs Export
#!/usr/bin/env node /** * Blender Three.js Export * * Exports the current Blender scene as GLB and generates a standalone * Three.js HTML viewer with orbit controls and studio lighting. */ const net = require('net'); const fs = require('fs'); const path = require('path'); // --- CLI args --- const args = process.argv.slice(2); function getArg(name, def) { const i = args.indexOf(`--${name}`); if (i === -1) return def; return args[i + 1] || def; } const hasFlag = (name) => args.includes(`--${name}`); const outputDir = getArg('output', null); const modelName = getArg('name', 'model'); const port = parseInt(getArg('port', '9876'), 10); const noRotate = hasFlag('no-rotate'); const bgColor = getArg('bg', '#111111'); const embed = hasFlag('embed'); if (!outputDir) { console.error('Usage: node blender-threejs-export.js --output <directory>'); console.error('Options: --name model --port 9876 --no-rotate --bg "#111111" --embed'); process.exit(1); } const absOutput = path.resolve(outputDir); const glbPath = path.join(absOutput, `${modelName}.glb`); const htmlPath = path.join(absOutput, `${modelName}.html`); // --- Blender MCP socket helper --- function sendToBlender(code) { return new Promise((resolve, reject) => { const sock = new net.Socket(); sock.setTimeout(120000); sock.connect(port, 'localhost', () => { const cmd = JSON.stringify({ type: 'execute_code', params: { code } }); sock.write(cmd); }); let data = ''; sock.on('data', (chunk) => { data += chunk.toString(); try { const parsed = JSON.parse(data); sock.destroy(); resolve(parsed); } catch (_) { /* keep reading */ } }); sock.on('timeout', () => { sock.destroy(); reject(new Error('Blender socket timeout')); }); sock.on('error', (err) => reject(err)); sock.on('close', () => { if (data) { try { resolve(JSON.parse(data)); } catch (_) { reject(new Error(`Bad response: ${data}`)); } } }); }); } function generateHTML(glbFile) { const glbSrc = embed ? `data:model/gltf-binary;base64,${fs.readFileSync(glbPath).toString('base64')}` : `./${glbFile}`; return `<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>${modelName}</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } html, body { width: 100%; height: 100%; overflow: hidden; background: ${bgColor}; } canvas { display: block; width: 100%; height: 100%; } </style> <script type="importmap"> { "imports": { "three": "https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js", "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/" } } </script> </head> <body> <script type="module"> import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'; // --- Scene --- const scene = new THREE.Scene(); scene.background = new THREE.Color('${bgColor}'); // --- Camera --- const camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.01, 100); camera.position.set(2.5, 1.8, 2.5); // --- Renderer --- const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMappingExposure = 1.2; renderer.outputColorSpace = THREE.SRGBColorSpace; document.body.appendChild(renderer.domElement); // --- Controls --- const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.06; controls.autoRotate = ${!noRotate}; controls.autoRotateSpeed = 1.5; controls.minDistance = 0.5; controls.maxDistance = 20; // --- Lighting (studio s