WebGL-MCP Server
by grokadegames
Verified
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebGLBuildAnalyzer = void 0;
const fs_1 = require("fs");
const path = __importStar(require("path"));
const zlib = __importStar(require("zlib"));
const util_1 = require("util");
const gzip = (0, util_1.promisify)(zlib.gzip);
class WebGLBuildAnalyzer {
async analyzeBuild(buildPath) {
const analysis = {
totalSize: 0,
compressedSize: 0,
files: [],
suggestions: []
};
try {
const files = await this.getAllFiles(buildPath);
for (const file of files) {
const fileAnalysis = await this.analyzeFile(file, buildPath);
analysis.files.push(fileAnalysis);
analysis.totalSize += fileAnalysis.size;
analysis.compressedSize += fileAnalysis.compressedSize;
}
// Check for HTML template usage
const indexFile = files.find(f => path.basename(f).toLowerCase() === 'index.html');
if (indexFile) {
const htmlAnalysis = await this.analyzeHTMLTemplate(indexFile);
analysis.templateUsed = htmlAnalysis.templateName;
analysis.templateConfig = htmlAnalysis.config;
// Add template-specific suggestions
if (htmlAnalysis.suggestions.length > 0) {
analysis.suggestions.push(...htmlAnalysis.suggestions);
}
}
// Analyze overall build
this.analyzeBuildStructure(analysis);
}
catch (error) {
console.error('Error analyzing build:', error);
throw error;
}
return analysis;
}
async getAllFiles(dirPath) {
const files = [];
const entries = await fs_1.promises.readdir(dirPath, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name);
if (entry.isDirectory()) {
files.push(...await this.getAllFiles(fullPath));
}
else {
files.push(fullPath);
}
}
return files;
}
async analyzeHTMLTemplate(filePath) {
const content = await fs_1.promises.readFile(filePath, 'utf8');
const suggestions = [];
let templateName = 'Unknown';
const config = {};
// Check for Better Minimal WebGL Template
if (content.includes('BetterMinimal') ||
(content.includes('scaleToFit') && content.includes('data-pixel-art'))) {
templateName = 'Better Minimal WebGL Template';
// Check for scaling configuration
config.scaleToFit = !content.includes('scaleToFit = false');
// Check for pixel art optimization
if (content.includes('data-pixel-art="true"')) {
config.optimizeForPixelArt = true;
}
// Check for loading bar
if (content.includes('progressHandler') && content.includes('linear-gradient')) {
config.hasLoadingBar = true;
}
// Check for mobile optimization
if (content.includes('iPhone|iPad|iPod|Android')) {
config.mobileOptimized = true;
}
// Generate template-specific suggestions
if (!config.scaleToFit) {
suggestions.push('Consider enabling scale-to-fit for better user experience on different screen sizes.');
}
if (!config.hasLoadingBar) {
suggestions.push('Enable the loading bar to provide visual feedback during asset loading.');
}
if (!config.mobileOptimized) {
suggestions.push('Enable mobile optimizations for better performance on mobile devices.');
}
}
else if (content.includes('UnityLoader') || content.includes('unityInstance')) {
templateName = 'Unity Default Template';
suggestions.push('Consider using the Better Minimal WebGL Template for improved scaling and mobile support.');
suggestions.push('The Better Minimal WebGL Template provides better canvas scaling and improved mobile device support.');
}
return { templateName, config, suggestions };
}
async analyzeFile(filePath, buildPath) {
const content = await fs_1.promises.readFile(filePath);
const compressedContent = await gzip(content);
const relativePath = path.relative(buildPath, filePath);
const extension = path.extname(filePath).toLowerCase();
const analysis = {
path: relativePath,
size: content.length,
compressedSize: compressedContent.length,
type: this.getFileType(extension),
suggestions: []
};
// Analyze specific file types
switch (analysis.type) {
case 'texture':
this.analyzeTexture(analysis, content);
break;
case 'shader':
this.analyzeShader(analysis, content);
break;
case 'javascript':
this.analyzeJavaScript(analysis, content);
break;
}
return analysis;
}
getFileType(extension) {
switch (extension) {
case '.jpg':
case '.jpeg':
case '.png':
case '.webp':
case '.gif':
return 'texture';
case '.glsl':
case '.vert':
case '.frag':
return 'shader';
case '.js':
return 'javascript';
case '.wasm':
return 'webassembly';
case '.html':
return 'html';
case '.css':
return 'stylesheet';
case '.json':
return 'data';
default:
return 'other';
}
}
analyzeTexture(analysis, content) {
// Check texture size - large textures may need optimization
if (content.length > 1024 * 1024) {
analysis.suggestions.push(`Large texture (${(content.length / (1024 * 1024)).toFixed(2)} MB). Consider using compression or smaller textures.`);
}
// Check compression savings
const compressionRatio = analysis.size / analysis.compressedSize;
if (compressionRatio < 1.2) {
analysis.suggestions.push('Texture has low compression ratio. Consider using WebP format for better compression.');
}
}
analyzeShader(analysis, content) {
const shaderText = content.toString('utf8');
// Check for potential shader optimizations
if (shaderText.includes('pow(') || shaderText.includes('exp(') || shaderText.includes('log(')) {
analysis.suggestions.push('Shader uses expensive operations (pow, exp, log). Consider optimizing for better performance.');
}
// Check for precision qualifiers
if (!shaderText.includes('precision ')) {
analysis.suggestions.push('Shader missing precision qualifiers. Define precision for better performance and consistency.');
}
}
analyzeJavaScript(analysis, content) {
const jsText = content.toString('utf8');
// Check for large JS files
if (content.length > 5 * 1024 * 1024) {
analysis.suggestions.push(`Large JavaScript file (${(content.length / (1024 * 1024)).toFixed(2)} MB). Consider code splitting or minification.`);
}
// Check for WebGL context creation
if (jsText.includes('getContext("webgl")') && !jsText.includes('getContext("webgl2")')) {
analysis.suggestions.push('Using WebGL 1.0. Consider upgrading to WebGL 2.0 for better performance and features.');
}
// Check for memory management issues
if (jsText.includes('new Uint8Array(') || jsText.includes('new Float32Array(')) {
if (!jsText.includes('delete') && !jsText.includes('dispose')) {
analysis.suggestions.push('Creating typed arrays without apparent cleanup. Watch for memory leaks.');
}
}
}
analyzeBuildStructure(analysis) {
// Group files by type
const fileTypes = analysis.files.reduce((types, file) => {
types[file.type] = (types[file.type] || 0) + file.size;
return types;
}, {});
// Check total size
if (analysis.totalSize > 100 * 1024 * 1024) {
analysis.suggestions.push(`Large build size (${(analysis.totalSize / (1024 * 1024)).toFixed(2)} MB). Consider optimizing assets and code splitting.`);
}
// Check texture usage
if (fileTypes['texture'] && fileTypes['texture'] > analysis.totalSize * 0.5) {
analysis.suggestions.push(`Textures account for over 50% of build size. Consider using texture compression or lower resolution textures.`);
}
// Check JavaScript size
if (fileTypes['javascript'] && fileTypes['javascript'] > 20 * 1024 * 1024) {
analysis.suggestions.push(`Large JavaScript size (${(fileTypes['javascript'] / (1024 * 1024)).toFixed(2)} MB). Consider code splitting and tree shaking.`);
}
// Check WebAssembly usage
if (!fileTypes['webassembly']) {
analysis.suggestions.push('No WebAssembly detected. Consider using WebAssembly for performance-critical code.');
}
// Template-specific optimization suggestions
if (analysis.templateUsed === 'Better Minimal WebGL Template') {
analysis.suggestions.push('Using Better Minimal WebGL Template. Good choice for optimal WebGL performance and compatibility.');
}
else if (analysis.templateUsed === 'Unknown') {
analysis.suggestions.push('Using an unknown HTML template. Consider using Better Minimal WebGL Template for optimal WebGL performance.');
}
}
}
exports.WebGLBuildAnalyzer = WebGLBuildAnalyzer;