Greasy Fork is available in English.

Insight - Three.js Runtime Analysis Studio

Professional-grade Tampermonkey userscript for runtime analysis, debugging, exploration, and research of Three.js games and applications.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

Advertisement:

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

Advertisement:

// ==UserScript==
// @name         Insight - Three.js Runtime Analysis Studio
// @namespace    https://github.com/insight-tools/insight
// @version      1.0.0
// @description  Professional-grade Tampermonkey userscript for runtime analysis, debugging, exploration, and research of Three.js games and applications.
// @author       Insight Platform & F1xL1T & FunWithScripts & C00lrXX
// @match        *://*/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function () {
    'use strict';

    /**
     * =========================================================================
     * UTILITIES & HELPERS
     * =========================================================================
     */

    class EventEmitter {
        constructor() {
            this.events = {};
        }
        on(event, listener) {
            if (!this.events[event]) this.events[event] = [];
            this.events[event].push(listener);
            return () => this.off(event, listener);
        }
        off(event, listener) {
            if (!this.events[event]) return;
            this.events[event] = this.events[event].filter(l => l !== listener);
        }
        emit(event, ...args) {
            if (this.events[event]) {
                this.events[event].forEach(listener => listener(...args));
            }
        }
        clear() {
            this.events = {};
        }
    }

    class Module extends EventEmitter {
        constructor(insight) {
            super();
            this.insight = insight;
            this.disposables = [];
        }
        init() { /* Hook runtime immediately */ }
        initUI() { /* Setup UI after DOM load */ }
        
        registerCleanup(fn) {
            this.disposables.push(fn);
        }
        
        dispose() {
            this.disposables.forEach(fn => fn());
            this.disposables = [];
            this.clear();
        }
    }

    // Basic OBJ Exporter (Solves export feature without relying on external CDNs)
    const exportToOBJ = (object3D) => {
        let obj = '';
        let vertexOffset = 1;
        object3D.traverse((child) => {
            if (child.isMesh && child.geometry) {
                const geo = child.geometry;
                const positions = geo.attributes.position;
                if (!positions) return;
                
                obj += `o ${child.name || child.type || 'Mesh'}\n`;
                const matrix = child.matrixWorld;
                const vec3 = new window.THREE.Vector3();
                
                for (let i = 0; i < positions.count; i++) {
                    vec3.fromBufferAttribute(positions, i).applyMatrix4(matrix);
                    obj += `v ${vec3.x} ${vec3.y} ${vec3.z}\n`;
                }
                
                if (geo.index) {
                    const indices = geo.index.array;
                    for (let i = 0; i < indices.length; i += 3) {
                        obj += `f ${indices[i]+vertexOffset} ${indices[i+1]+vertexOffset} ${indices[i+2]+vertexOffset}\n`;
                    }
                } else {
                    for (let i = 0; i < positions.count; i += 3) {
                        obj += `f ${i+vertexOffset} ${i+1+vertexOffset} ${i+2+vertexOffset}\n`;
                    }
                }
                vertexOffset += positions.count;
            }
        });
        const blob = new Blob([obj], { type: 'text/plain' });
        const a = document.createElement('a');
        a.href = URL.createObjectURL(blob);
        a.download = `${object3D.name || 'Insight_Export'}.obj`;
        a.click();
        URL.revokeObjectURL(a.href);
    };

    /**
     * =========================================================================
     * UI FRAMEWORK & COMPONENTS (With Persistence)
     * =========================================================================
     */

    class UIWindow {
        constructor(ui, id, title, iconName) {
            this.ui = ui;
            this.id = id;
            this.el = document.createElement('div');
            this.el.className = 'insight-window';
            
            // Restore window state
            const state = JSON.parse(localStorage.getItem(`insight_win_${this.id}`) || 'null');
            this.el.style.left = state?.left || '100px';
            this.el.style.top = state?.top || '100px';
            this.el.style.width = state?.width || 'auto';
            this.el.style.height = state?.height || 'auto';
            this.el.style.zIndex = '1000';

            this.header = document.createElement('div');
            this.header.className = 'insight-header';

            const iconEl = document.createElement('i');
            iconEl.setAttribute('data-lucide', iconName);
            iconEl.style.width = '14px';
            iconEl.style.height = '14px';
            iconEl.style.marginRight = '8px';

            const titleEl = document.createElement('span');
            titleEl.className = 'title';
            titleEl.textContent = title;

            const closeBtn = document.createElement('i');
            closeBtn.setAttribute('data-lucide', 'x');
            closeBtn.className = 'close-btn';

            this.header.appendChild(iconEl);
            this.header.appendChild(titleEl);
            this.header.appendChild(closeBtn);

            this.content = document.createElement('div');
            this.content.className = 'window-content';

            this.el.appendChild(this.header);
            this.el.appendChild(this.content);
            this.ui.shadowRoot.appendChild(this.el);

            this._onCloseCallbacks = [];
            closeBtn.addEventListener('click', () => this.close());

            this.makeDraggableAndResizable();
            this.ui.refreshIcons(this.header);
        }

        saveState() {
            localStorage.setItem(`insight_win_${this.id}`, JSON.stringify({
                left: this.el.style.left,
                top: this.el.style.top,
                width: this.el.style.width,
                height: this.el.style.height
            }));
        }

        makeDraggableAndResizable() {
            let isDragging = false;
            let startX, startY, initialLeft, initialTop;

            const onMouseMove = (e) => {
                if (!isDragging) return;
                const dx = e.clientX - startX;
                const dy = e.clientY - startY;
                this.el.style.left = `${initialLeft + dx}px`;
                this.el.style.top = `${initialTop + dy}px`;
            };

            const onMouseUp = () => {
                isDragging = false;
                document.removeEventListener('mousemove', onMouseMove);
                document.removeEventListener('mouseup', onMouseUp);
                this.saveState();
            };

            this.header.addEventListener('mousedown', (e) => {
                if (e.target.classList.contains('close-btn')) return;
                isDragging = true;
                startX = e.clientX;
                startY = e.clientY;
                initialLeft = parseInt(this.el.style.left || 0, 10);
                initialTop = parseInt(this.el.style.top || 0, 10);

                // Bring to front
                const allWindows = this.ui.shadowRoot.querySelectorAll('.insight-window');
                let maxZ = 1000;
                allWindows.forEach(w => {
                    const z = parseInt(w.style.zIndex || 1000, 10);
                    if (z > maxZ) maxZ = z;
                });
                this.el.style.zIndex = maxZ + 1;

                document.addEventListener('mousemove', onMouseMove);
                document.addEventListener('mouseup', onMouseUp);
            });

            // Save state on resize
            new ResizeObserver(() => this.saveState()).observe(this.el);
        }

        onClose(cb) {
            this._onCloseCallbacks.push(cb);
        }

        close() {
            this.el.remove();
            this._onCloseCallbacks.forEach(cb => cb());
            this._onCloseCallbacks = [];
        }
    }

    class UIFramework {
        constructor(insight) {
            this.insight = insight;
            this.iconsLoaded = false;
        }

        mount() {
            this.host = document.createElement('div');
            this.host.id = 'insight-platform-host';
            this.host.style.cssText = 'position: fixed; top: 0; left: 0; width: 0; height: 0; z-index: 9999999; overflow: visible;';
            
            const target = document.body || document.documentElement;
            target.appendChild(this.host);
            
            this.shadowRoot = this.host.attachShadow({ mode: 'open' });
            
            this.injectStyles();
            this.loadDependencies();
        }

        injectStyles() {
            const style = document.createElement('style');
            style.textContent = `
                @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap');
                
                :host {
                    --bg-base: #18181B;
                    --bg-surface: #27272A;
                    --bg-hover: #3F3F46;
                    --border: #3F3F46;
                    --text-main: #F4F4F5;
                    --text-muted: #A1A1AA;
                    --accent: #3B82F6;
                    --font-sans: 'Inter', system-ui, sans-serif;
                    --font-mono: 'JetBrains Mono', monospace;
                    
                    font-family: var(--font-sans);
                    color: var(--text-main);
                    font-size: 13px;
                }

                * { box-sizing: border-box; }
                
                ::-webkit-scrollbar { width: 8px; height: 8px; }
                ::-webkit-scrollbar-track { background: transparent; }
                ::-webkit-scrollbar-thumb { background: var(--bg-hover); border-radius: 4px; }
                ::-webkit-scrollbar-thumb:hover { background: var(--border); }

                .insight-window {
                    position: absolute;
                    background: rgba(39, 39, 42, 0.95);
                    backdrop-filter: blur(12px);
                    border: 1px solid var(--border);
                    border-radius: 8px;
                    box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
                    display: flex;
                    flex-direction: column;
                    min-width: 320px;
                    min-height: 200px;
                    resize: both;
                    overflow: hidden;
                }

                .insight-header {
                    background: rgba(24, 24, 27, 0.8);
                    padding: 8px 12px;
                    display: flex;
                    align-items: center;
                    border-bottom: 1px solid var(--border);
                    cursor: grab;
                    user-select: none;
                }
                .insight-header .title { font-weight: 500; flex-grow: 1; }
                .insight-header .close-btn { cursor: pointer; color: var(--text-muted); }
                .insight-header .close-btn:hover { color: #F87171; }

                .window-content {
                    flex: 1;
                    overflow: auto;
                    display: flex;
                    flex-direction: column;
                }

                .btn {
                    background: var(--bg-hover);
                    border: 1px solid var(--border);
                    color: var(--text-main);
                    padding: 6px 12px;
                    border-radius: 4px;
                    cursor: pointer;
                    font-size: 12px;
                    font-family: var(--font-sans);
                    display: inline-flex;
                    align-items: center;
                    gap: 6px;
                }
                .btn:hover { background: var(--border); }

                input.dark-input {
                    background: var(--bg-base);
                    border: 1px solid var(--border);
                    color: var(--text-main);
                    padding: 6px 8px;
                    border-radius: 4px;
                    outline: none;
                    width: 100%;
                    font-family: var(--font-sans);
                }
                input.dark-input:focus { border-color: var(--accent); }

                /* Two Way Data Binding Inputs */
                .live-input {
                    background: transparent;
                    border: 1px solid transparent;
                    color: var(--accent);
                    font-family: var(--font-mono);
                    font-size: 12px;
                    width: 60px;
                    outline: none;
                    text-align: right;
                    border-radius: 3px;
                }
                .live-input:focus {
                    border-color: var(--accent);
                    background: var(--bg-base);
                }

                .cmd-overlay {
                    position: fixed; top: 0; left: 0; right: 0; bottom: 0;
                    background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(4px);
                    display: flex; justify-content: center; padding-top: 15vh; z-index: 10000;
                }

                .cmd-palette {
                    width: 600px; background: var(--bg-surface);
                    border: 1px solid var(--border); border-radius: 8px;
                    display: flex; flex-direction: column;
                }
                .cmd-input {
                    width: 100%; background: transparent; border: none; border-bottom: 1px solid var(--border);
                    color: var(--text-main); font-size: 16px; padding: 16px; outline: none;
                }
                .cmd-item {
                    padding: 12px 16px; display: flex; align-items: center; cursor: pointer; color: var(--text-muted);
                }
                .cmd-item.selected { background: var(--bg-hover); color: var(--text-main); }

                .sidebar-layout { display: flex; height: 100%; width: 100%; }
                .sidebar { width: 150px; border-right: 1px solid var(--border); background: rgba(24, 24, 27, 0.5); display: flex; flex-direction: column; }
                .sidebar-item { padding: 10px 12px; cursor: pointer; color: var(--text-muted); display: flex; align-items: center; gap: 8px; border-left: 2px solid transparent; }
                .sidebar-item:hover, .sidebar-item.active { background: var(--bg-hover); color: var(--text-main); }
                .sidebar-item.active { border-left-color: var(--accent); }
                .main-content { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
            `;
            this.shadowRoot.appendChild(style);
        }

        loadDependencies() {
            const script = document.createElement('script');
            script.src = 'https://unpkg.com/lucide@latest';
            script.onload = () => {
                this.iconsLoaded = true;
                this.refreshIcons(this.shadowRoot);
            };
            document.head.appendChild(script);
        }

        refreshIcons(root) {
            if (this.iconsLoaded && window.lucide) {
                window.lucide.createIcons({ 
                    root: root, 
                    attrs: { class: "lucide-icon", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" } 
                });
            }
        }

        createWindow(id, title, iconName) {
            return new UIWindow(this, id, title, iconName);
        }

        showToast(message) {
            const toast = document.createElement('div');
            toast.style.cssText = `
                position: fixed; bottom: 24px; right: 24px;
                background: var(--bg-surface); border: 1px solid var(--border);
                color: var(--text-main); padding: 12px 24px; border-radius: 8px;
                box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2);
                font-weight: 500; z-index: 10000; transition: all 0.3s;
            `;
            toast.innerHTML = `<div style="display: flex; align-items: center; gap: 8px;"><i data-lucide="info" style="width: 16px; height: 16px; color: var(--accent);"></i> ${message}</div>`;
            this.shadowRoot.appendChild(toast);
            this.refreshIcons(toast);
            
            setTimeout(() => {
                toast.style.opacity = '0';
                setTimeout(() => toast.remove(), 300);
            }, 3000);
        }
    }

    /**
     * =========================================================================
     * 1. DETECTOR MODULE (Intelligent Hooks + Safe Mode Fallback)
     * =========================================================================
     */

    class ThreeDetector extends Module {
        init() {
            this.scenes = new Set();
            this.cameras = new Set();
            this.renderers = new Set();
            this.textures = new Set();
            this.materials = new Set();
            this.geometries = new Set();
            
            this.lastCamera = null;
            this.lastScene = null;
            this.lastRenderer = null;
            
            this.setupHooks();
        }

        setupHooks() {
            let _THREE = window.THREE;
            Object.defineProperty(window, 'THREE', {
                get: () => _THREE,
                set: (val) => {
                    _THREE = val;
                    if (val) this.hookThree(val);
                },
                configurable: true
            });

            if (_THREE) this.hookThree(_THREE);
        }

        hookThree(THREE) {
            if (THREE._insightHooked) return;
            
            try {
                // High-performance Proxy hooks
                const proxySubclasses = (baseName, callback) => {
                    Object.keys(THREE).forEach(key => {
                        if (key.includes(baseName) || key === baseName) {
                            if (typeof THREE[key] === 'function') {
                                const Orig = THREE[key];
                                if (!Orig.__insightHooked) {
                                    const hooked = new Proxy(Orig, {
                                        construct(target, args) {
                                            const obj = new target(...args);
                                            callback(obj);
                                            return obj;
                                        }
                                    });
                                    hooked.__insightHooked = true;
                                    THREE[key] = hooked;
                                }
                            }
                        }
                    });
                };

                proxySubclasses('Scene', (o) => { this.scenes.add(o); this.emit('asset-added', { type: 'scene', obj: o }); });
                proxySubclasses('WebGLRenderer', (o) => { this.renderers.add(o); this.emit('asset-added', { type: 'renderer', obj: o }); });
                proxySubclasses('Texture', (o) => { this.textures.add(o); this.emit('asset-added', { type: 'texture', obj: o }); });
                proxySubclasses('Material', (o) => { this.materials.add(o); this.emit('asset-added', { type: 'material', obj: o }); });
                proxySubclasses('Geometry', (o) => { this.geometries.add(o); this.emit('asset-added', { type: 'geometry', obj: o }); });
                proxySubclasses('Camera', (o) => { this.cameras.add(o); this.emit('asset-added', { type: 'camera', obj: o }); });

                // Hook the renderer's loop to catch pre-existing scenes and active cameras
                if (THREE.WebGLRenderer) {
                    const origRender = THREE.WebGLRenderer.prototype.render;
                    const self = this;
                    THREE.WebGLRenderer.prototype.render = function(scene, camera) {
                        self.lastRenderer = this;
                        self.lastScene = scene;
                        self.lastCamera = camera;
                        
                        if (!self.renderers.has(this)) { self.renderers.add(this); self.emit('asset-added', { type: 'renderer', obj: this }); }
                        if (scene && !self.scenes.has(scene)) { self.scenes.add(scene); self.emit('asset-added', { type: 'scene', obj: scene }); }
                        return origRender.apply(this, arguments);
                    };
                }

                THREE._insightHooked = true;
                console.log('[Insight] Intelligent WebGL hooking initialized.');

            } catch (err) {
                // Safe Mode Fallback for heavily obfuscated / frozen objects
                console.warn('[Insight] Proxy Hook failed. Falling back to Safe Mode (Interval Scanning).', err);
                setInterval(() => this.scanGlobal(), 2000);
            }
        }

        scanGlobal() {
            const traverse = (obj) => {
                if (!obj || typeof obj !== 'object') return;
                if (obj.isScene) { this.scenes.add(obj); this.lastScene = obj; }
                if (obj.isCamera) { this.cameras.add(obj); this.lastCamera = obj; }
                if (obj.isTexture) this.textures.add(obj);
                if (obj.isMaterial) this.materials.add(obj);
                if (obj.isBufferGeometry || obj.isGeometry) this.geometries.add(obj);
                if (obj.children) obj.children.forEach(traverse);
            };
            this.scenes.forEach(traverse);
        }
    }

    /**
     * =========================================================================
     * 2. RAYCASTER PICKER TOOL (Interactive Click-to-Select)
     * =========================================================================
     */

    class PickerTool extends Module {
        init() {
            this.active = false;
            this.raycaster = new window.THREE.Raycaster();
        }

        initUI() {
            this.insight.commands.registerCommand('Toggle Raycast Picker', 'crosshair', () => this.toggle());
            document.addEventListener('click', (e) => this.onClick(e), true);
        }

        toggle() {
            this.active = !this.active;
            this.insight.ui.showToast(`Picker Tool ${this.active ? 'Activated (Click an object)' : 'Deactivated'}`);
            if (this.active) {
                document.body.style.cursor = 'crosshair';
            } else {
                document.body.style.cursor = 'default';
            }
        }

        onClick(e) {
            if (!this.active || !this.insight.modules.detector.lastCamera || !this.insight.modules.detector.lastScene) return;
            e.preventDefault();
            e.stopPropagation();
            
            const renderer = this.insight.modules.detector.lastRenderer;
            const canvas = renderer ? renderer.domElement : document.body;
            const rect = canvas.getBoundingClientRect();
            
            const mouse = new window.THREE.Vector2();
            mouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
            mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;

            this.raycaster.setFromCamera(mouse, this.insight.modules.detector.lastCamera);
            const intersects = this.raycaster.intersectObjects(this.insight.modules.detector.lastScene.children, true);
            
            if (intersects.length > 0) {
                this.insight.emit('inspect-object', intersects[0].object);
                this.insight.ui.showToast(`Selected: ${intersects[0].object.name || intersects[0].object.type}`);
            }
            this.toggle(); // Auto-disable after picking
        }
    }

    /**
     * =========================================================================
     * 3. ASSET EXPLORER (Snapshots, Gallery Views, Downloads)
     * =========================================================================
     */

    class AssetExplorer extends Module {
        initUI() {
            this.insight.commands.registerCommand('Asset Explorer', 'package', () => this.openWindow());
        }

        openWindow() {
            const win = this.insight.ui.createWindow('asset_explorer', 'Asset Explorer', 'package');
            if (win.el.style.width === 'auto') {
                win.el.style.width = '750px';
                win.el.style.height = '500px';
            }

            win.content.innerHTML = `
                <div class="sidebar-layout">
                    <div class="sidebar">
                        <div class="sidebar-item active" data-tab="textures"><i data-lucide="image"></i> Textures</div>
                        <div class="sidebar-item" data-tab="materials"><i data-lucide="layers"></i> Materials</div>
                        <div class="sidebar-item" data-tab="geometries"><i data-lucide="box"></i> Geometry</div>
                        
                        <div style="margin-top: auto; padding: 10px; border-top: 1px solid var(--border);">
                            <button id="btn-snapshot" class="btn" style="width: 100%; justify-content: center; margin-bottom: 6px;">
                                <i data-lucide="camera"></i> Snapshot
                            </button>
                            <label style="display: flex; align-items: center; gap: 6px; font-size: 11px;">
                                <input type="checkbox" id="chk-delta" disabled> Show Delta (Leaks)
                            </label>
                        </div>
                    </div>
                    <div class="main-content">
                        <div style="padding: 8px; border-bottom: 1px solid var(--border); display: flex; gap: 8px;">
                            <input type="text" class="dark-input" id="asset-search" placeholder="Search assets..." />
                        </div>
                        <div id="asset-list" style="flex: 1; overflow-y: auto; padding: 12px; display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); align-content: start;">
                        </div>
                    </div>
                </div>
            `;

            let currentTab = 'textures';
            let searchQuery = '';
            let snapshot = null;
            let showDelta = false;
            
            const listEl = win.content.querySelector('#asset-list');

            const renderItems = () => {
                listEl.innerHTML = '';
                const detector = this.insight.modules.detector;
                let items = [];

                if (currentTab === 'textures') items = Array.from(detector.textures);
                if (currentTab === 'materials') items = Array.from(detector.materials);
                if (currentTab === 'geometries') items = Array.from(detector.geometries);

                // Filter by Snapshot Delta
                if (showDelta && snapshot) {
                    items = items.filter(i => !snapshot.has(i.uuid));
                }

                items.forEach(item => {
                    const name = item.name || item.type || 'Unnamed';
                    if (searchQuery && !name.toLowerCase().includes(searchQuery.toLowerCase())) return;

                    const card = document.createElement('div');
                    card.style.cssText = 'background: var(--bg-surface); border: 1px solid var(--border); border-radius: 6px; padding: 10px; display: flex; flex-direction: column; gap: 6px;';
                    
                    let meta = '';
                    let preview = '';
                    
                    if (currentTab === 'textures') {
                        meta = `<div style="font-size: 10px;">${item.image ? item.image.width+'x'+item.image.height : 'No Image'} | ${item.format}</div>`;
                        
                        // Gallery View implementation
                        if (item.image && item.image.src) {
                            preview = `<div style="height: 100px; background: #000 url(${item.image.src}) center/contain no-repeat; border-radius: 4px; margin-bottom: 6px;"></div>`;
                            meta += `<button class="btn dl-btn" data-url="${item.image.src}" style="width: 100%; margin-top: 6px; padding: 4px;">Download Map</button>`;
                        } else if (item.image && item.image instanceof HTMLCanvasElement) {
                            preview = `<div style="height: 100px; background: #000 url(${item.image.toDataURL()}) center/contain no-repeat; border-radius: 4px; margin-bottom: 6px;"></div>`;
                            meta += `<button class="btn dl-btn" data-url="${item.image.toDataURL()}" style="width: 100%; margin-top: 6px; padding: 4px;">Download Map</button>`;
                        }
                    } else if (currentTab === 'materials') {
                        meta = `<div style="font-size: 10px;">Type: ${item.type}<br>Wireframe: ${item.wireframe}</div>`;
                    } else if (currentTab === 'geometries') {
                        const verts = item.attributes?.position?.count || 0;
                        const tris = item.index ? item.index.count / 3 : verts / 3;
                        meta = `<div style="font-size: 10px;">Verts: ${verts.toLocaleString()}<br>Tris: ${Math.floor(tris).toLocaleString()}</div>`;
                        meta += `<button class="btn exp-btn" style="width: 100%; margin-top: 6px; padding: 4px;">Export OBJ</button>`;
                    }

                    card.innerHTML = `
                        ${preview}
                        <div style="font-weight: 600; font-size: 12px; color: var(--accent); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" title="${name}">${name}</div>
                        <div style="color: var(--text-muted); font-family: var(--font-mono);">${meta}</div>
                    `;

                    // Actions
                    const dlBtn = card.querySelector('.dl-btn');
                    if(dlBtn) {
                        dlBtn.onclick = () => {
                            const a = document.createElement('a');
                            a.href = dlBtn.getAttribute('data-url');
                            a.download = `${name}.png`;
                            a.click();
                        };
                    }

                    const expBtn = card.querySelector('.exp-btn');
                    if(expBtn) {
                        expBtn.onclick = () => {
                            const mesh = new window.THREE.Mesh(item, new window.THREE.MeshBasicMaterial());
                            mesh.name = name;
                            exportToOBJ(mesh);
                        };
                    }

                    listEl.appendChild(card);
                });
            };

            // Memory Snapshot Logic
            const snapBtn = win.content.querySelector('#btn-snapshot');
            const chkDelta = win.content.querySelector('#chk-delta');
            
            snapBtn.onclick = () => {
                snapshot = new Set([
                    ...Array.from(this.insight.modules.detector.textures).map(t => t.uuid),
                    ...Array.from(this.insight.modules.detector.materials).map(m => m.uuid),
                    ...Array.from(this.insight.modules.detector.geometries).map(g => g.uuid)
                ]);
                chkDelta.disabled = false;
                chkDelta.checked = true;
                showDelta = true;
                this.insight.ui.showToast(`Memory Snapshot Taken. Identifying Deltas.`);
                renderItems();
            };

            chkDelta.onchange = (e) => {
                showDelta = e.target.checked;
                renderItems();
            };

            win.content.querySelectorAll('.sidebar-item').forEach(el => {
                el.addEventListener('click', (e) => {
                    win.content.querySelectorAll('.sidebar-item').forEach(i => i.classList.remove('active'));
                    e.currentTarget.classList.add('active');
                    currentTab = e.currentTarget.getAttribute('data-tab');
                    renderItems();
                });
            });

            win.content.querySelector('#asset-search').addEventListener('input', (e) => {
                searchQuery = e.target.value;
                renderItems();
            });

            const cleanup = this.insight.modules.detector.on('asset-added', () => {
                if(!showDelta) renderItems();
            });
            win.onClose(cleanup);

            renderItems();
            this.insight.ui.refreshIcons(win.content);
        }
    }

    /**
     * =========================================================================
     * 4. ENTITY INSPECTOR (Live Editing + Two-Way Binding + Shader Viewer)
     * =========================================================================
     */

    class EntityInspector extends Module {
        initUI() {
            this.insight.commands.registerCommand('Entity Inspector', 'sliders', () => this.openWindow());
            this.insight.on('inspect-object', (obj) => {
                this.activeObject = obj;
                if (!this.window) this.window = this.openWindow();
                this.rebuildInspectorDOM();
            });
        }

        openWindow() {
            const win = this.insight.ui.createWindow('entity_inspector', 'Inspector', 'sliders');
            if (win.el.style.width === 'auto') {
                win.el.style.width = '320px';
                win.el.style.height = '600px';
            }
            this.window = win;
            this.liveRefs = {}; 
            
            let rAF;
            const loop = () => {
                if (this.activeObject && this.window) this.updateLiveValues();
                rAF = requestAnimationFrame(loop);
            };
            rAF = requestAnimationFrame(loop);

            win.onClose(() => {
                this.window = null;
                cancelAnimationFrame(rAF);
            });

            this.rebuildInspectorDOM();
            return win;
        }

        rebuildInspectorDOM() {
            if (!this.window) return;
            const content = this.window.content;
            const obj = this.activeObject;
            this.liveRefs = {}; 

            if (!obj) {
                content.innerHTML = '<div style="padding: 12px; color: var(--text-muted); text-align: center;">Select an object.</div>';
                return;
            }

            // Input UI Generators
            const createNum = (key) => {
                this.liveRefs[key] = Math.random().toString(36).substr(2, 9);
                return `<input id="${this.liveRefs[key]}" class="live-input" type="number" step="0.1">`;
            };
            const createBool = (key) => {
                this.liveRefs[key] = Math.random().toString(36).substr(2, 9);
                return `<input id="${this.liveRefs[key]}" type="checkbox">`;
            };
            const createColor = (key) => {
                this.liveRefs[key] = Math.random().toString(36).substr(2, 9);
                return `<input id="${this.liveRefs[key]}" type="color" style="background:transparent;border:none;cursor:pointer;width:24px;height:24px;padding:0;">`;
            };

            const section = (title, inner) => `
                <div style="border-bottom: 1px solid var(--border); padding: 12px;">
                    <div style="font-size: 11px; font-weight: 600; color: var(--text-muted); text-transform: uppercase; margin-bottom: 8px;">${title}</div>
                    ${inner}
                </div>
            `;
            const row = (lbl, val) => `
                <div style="display: flex; justify-content: space-between; align-items:center; margin-bottom: 4px; font-size: 12px;">
                    <span style="color: var(--text-muted);">${lbl}</span>
                    <span style="font-family: var(--font-mono); color: var(--text-main);">${val}</span>
                </div>
            `;

            let html = section('Information', 
                row('Name', `<span style="color: var(--accent);">${obj.name || 'N/A'}</span>`) +
                row('Type', obj.type) +
                row('UUID', `<span style="font-size: 9px;">${obj.uuid}</span>`)
            );

            if (obj.position) {
                html += section('Transform', 
                    row('Position', `${createNum('px')} ${createNum('py')} ${createNum('pz')}`) +
                    row('Rotation', `${createNum('rx')} ${createNum('ry')} ${createNum('rz')}`) +
                    row('Scale', `${createNum('sx')} ${createNum('sy')} ${createNum('sz')}`)
                );
            }

            if (obj.material) {
                const mat = obj.material;
                html += section('Material', 
                    row('Type', mat.type) +
                    (mat.color ? row('Color (Live)', createColor('mCol')) : '') +
                    row('Wireframe', createBool('mWire')) +
                    (mat.isShaderMaterial || mat.vertexShader ? `<button id="btn-shader" class="btn" style="width:100%; margin-top:8px;">Inspect Shader Source</button>` : '')
                );
            }

            html += section('Properties', 
                row('Visible', createBool('visible')) + 
                `<button id="btn-export" class="btn" style="width:100%; margin-top:8px;">Export as OBJ</button>`
            );

            content.innerHTML = html;

            // Bind Event Listeners for Live Editing (Two-Way Data Binding)
            const bindEl = (key, event, handler) => {
                const el = content.querySelector('#' + this.liveRefs[key]);
                if (el) {
                    el.addEventListener(event, handler);
                    this.liveRefs[key] = el; // Store DOM element
                }
            };

            if (obj.position) {
                bindEl('px', 'input', e => obj.position.x = parseFloat(e.target.value));
                bindEl('py', 'input', e => obj.position.y = parseFloat(e.target.value));
                bindEl('pz', 'input', e => obj.position.z = parseFloat(e.target.value));
                bindEl('rx', 'input', e => obj.rotation.x = parseFloat(e.target.value));
                bindEl('ry', 'input', e => obj.rotation.y = parseFloat(e.target.value));
                bindEl('rz', 'input', e => obj.rotation.z = parseFloat(e.target.value));
                bindEl('sx', 'input', e => obj.scale.x = parseFloat(e.target.value));
                bindEl('sy', 'input', e => obj.scale.y = parseFloat(e.target.value));
                bindEl('sz', 'input', e => obj.scale.z = parseFloat(e.target.value));
            }

            bindEl('visible', 'change', e => obj.visible = e.target.checked);

            if (obj.material) {
                bindEl('mWire', 'change', e => { obj.material.wireframe = e.target.checked; obj.material.needsUpdate = true; });
                bindEl('mCol', 'input', e => { if(obj.material.color) obj.material.color.set(e.target.value); });
                
                // Shader Source Viewer
                const btnShader = content.querySelector('#btn-shader');
                if (btnShader) {
                    btnShader.onclick = () => {
                        const win = this.insight.ui.createWindow('shader_view', 'Shader Source', 'code');
                        win.el.style.width = '700px'; win.el.style.height = '500px';
                        win.content.innerHTML = `
                            <div style="display:flex; height:100%;">
                                <textarea style="flex:1; background:#111; color:#10B981; font-family:var(--font-mono); font-size:11px; padding:10px; border:none; outline:none; resize:none;" readonly>// VERTEX SHADER\n${obj.material.vertexShader}</textarea>
                                <textarea style="flex:1; background:#111; color:#3B82F6; font-family:var(--font-mono); font-size:11px; padding:10px; border:none; outline:none; resize:none; border-left:1px solid var(--border);" readonly>// FRAGMENT SHADER\n${obj.material.fragmentShader}</textarea>
                            </div>`;
                    };
                }
            }

            const btnExport = content.querySelector('#btn-export');
            if (btnExport) btnExport.onclick = () => exportToOBJ(obj);
        }

        updateLiveValues() {
            const obj = this.activeObject;
            const refs = this.liveRefs;
            
            const updateNum = (el, val) => { if (el && document.activeElement !== el) el.value = typeof val === 'number' ? val.toFixed(3) : val; };
            const updateBool = (el, val) => { if (el && document.activeElement !== el) el.checked = val; };
            const updateCol = (el, val) => { if (el && document.activeElement !== el && val) el.value = '#' + val.getHexString(); };

            if (obj.position) {
                updateNum(refs.px, obj.position.x); updateNum(refs.py, obj.position.y); updateNum(refs.pz, obj.position.z);
                updateNum(refs.rx, obj.rotation.x); updateNum(refs.ry, obj.rotation.y); updateNum(refs.rz, obj.rotation.z);
                updateNum(refs.sx, obj.scale.x); updateNum(refs.sy, obj.scale.y); updateNum(refs.sz, obj.scale.z);
            }
            updateBool(refs.visible, obj.visible);
            
            if (obj.material) {
                updateBool(refs.mWire, obj.material.wireframe);
                updateCol(refs.mCol, obj.material.color);
            }
        }
    }

    /**
     * =========================================================================
     * 5. SCENE EXPLORER (With Heavy Bottleneck Highlighting)
     * =========================================================================
     */

    class SceneExplorer extends Module {
        initUI() {
            this.insight.commands.registerCommand('Scene Hierarchy', 'layers', () => this.openWindow());
        }

        openWindow() {
            const win = this.insight.ui.createWindow('scene_explorer', 'Hierarchy', 'layers');
            if (win.el.style.width === 'auto') {
                win.el.style.width = '350px';
                win.el.style.height = '500px';
            }
            
            const toolbar = document.createElement('div');
            toolbar.style.padding = '8px';
            toolbar.style.borderBottom = '1px solid var(--border)';
            
            const search = document.createElement('input');
            search.className = 'dark-input';
            search.placeholder = 'Filter nodes...';
            toolbar.appendChild(search);
            win.content.appendChild(toolbar);

            const treeContainer = document.createElement('div');
            treeContainer.style.flex = '1';
            treeContainer.style.overflow = 'auto';
            treeContainer.style.padding = '8px';
            win.content.appendChild(treeContainer);

            search.addEventListener('input', () => this.renderTree(treeContainer, search.value.toLowerCase()));
            const cleanup = this.insight.modules.detector.on('asset-added', (d) => {
                if (d.type === 'scene') this.renderTree(treeContainer, search.value.toLowerCase());
            });
            win.onClose(cleanup);
            this.renderTree(treeContainer, '');
        }

        renderTree(container, filterText) {
            container.innerHTML = '';
            const scenes = Array.from(this.insight.modules.detector.scenes);
            if (scenes.length === 0) return;

            const buildNode = (object) => {
                const name = (object.name || object.type || 'Object3D').toLowerCase();
                let childrenNodes = [];
                let hasMatchingDescendant = false;

                if (object.children && object.children.length > 0) {
                    object.children.forEach(child => {
                        const childResult = buildNode(child);
                        if (childResult) { childrenNodes.push(childResult.el); hasMatchingDescendant = true; }
                    });
                }

                if (filterText !== '' && !name.includes(filterText) && !hasMatchingDescendant) return null;

                const node = document.createElement('div');
                const row = document.createElement('div');
                row.style.cssText = 'display: flex; align-items: center; padding: 4px; cursor: pointer; border-radius: 4px;';
                row.onmouseenter = () => row.style.background = 'var(--bg-hover)';
                row.onmouseleave = () => row.style.background = 'transparent';

                // Performance Bottleneck logic
                let isHeavy = false;
                if (object.geometry) {
                    const verts = object.geometry.attributes?.position?.count || 0;
                    if (verts > 100000) isHeavy = true;
                }

                const hasChildren = childrenNodes.length > 0;
                const chevronHtml = hasChildren ? `<i data-lucide="chevron-down" style="width: 14px; margin-right: 4px; color: var(--text-muted);"></i>` : `<span style="width: 18px; display: inline-block;"></span>`;
                const iconHtml = `<i data-lucide="${object.type === 'Mesh' ? 'box' : 'cuboid'}" style="width: 14px; margin-right: 6px; color: ${isHeavy ? '#EF4444' : 'var(--text-muted)'};"></i>`;
                
                row.innerHTML = `
                    ${chevronHtml}${iconHtml}
                    <span style="font-size: 13px; color: ${isHeavy ? '#EF4444' : (object.visible ? 'var(--text-main)' : 'var(--text-muted)')};">${object.name || object.type || 'Object3D'}</span> 
                    ${isHeavy ? '<span style="font-size:9px;color:#EF4444;margin-left:auto;font-weight:bold;">HEAVY</span>' : ''}
                `;
                node.appendChild(row);

                if (hasChildren) {
                    const childrenContainer = document.createElement('div');
                    childrenContainer.style.cssText = 'padding-left: 14px; border-left: 1px solid var(--border); margin-left: 11px;';
                    childrenNodes.forEach(childEl => childrenContainer.appendChild(childEl));
                    node.appendChild(childrenContainer);
                    row.querySelector('i[data-lucide="chevron-down"]').onclick = (e) => {
                        e.stopPropagation();
                        const isHidden = childrenContainer.style.display === 'none';
                        childrenContainer.style.display = isHidden ? 'block' : 'none';
                        e.target.setAttribute('data-lucide', isHidden ? 'chevron-down' : 'chevron-right');
                        this.insight.ui.refreshIcons(row);
                    };
                }
                row.addEventListener('click', () => this.insight.emit('inspect-object', object));
                return { el: node };
            };

            scenes.forEach(scene => {
                const res = buildNode(scene);
                if (res) container.appendChild(res.el);
            });
            this.insight.ui.refreshIcons(container);
        }
    }

    /**
     * =========================================================================
     * 6. RUNTIME OBJECT EXPLORER (The Graph View)
     * =========================================================================
     */

    class RuntimeObjectExplorer extends Module {
        initUI() {
            this.insight.commands.registerCommand('Runtime Object Graph', 'share-2', () => this.openWindow());
        }

        openWindow() {
            const win = this.insight.ui.createWindow('runtime_graph', 'Runtime Graph', 'share-2');
            if (win.el.style.width === 'auto') {
                win.el.style.width = '800px';
                win.el.style.height = '600px';
            }

            const toolbar = document.createElement('div');
            toolbar.style.padding = '8px';
            toolbar.style.borderBottom = '1px solid var(--border)';
            toolbar.style.display = 'flex';
            toolbar.style.gap = '8px';

            const searchInput = document.createElement('input');
            searchInput.className = 'dark-input';
            searchInput.placeholder = 'Search nodes...';
            searchInput.style.width = '250px';

            const rebuildBtn = document.createElement('button');
            rebuildBtn.className = 'btn';
            rebuildBtn.innerHTML = '<i data-lucide="refresh-cw"></i> Rebuild Graph';

            toolbar.appendChild(searchInput);
            toolbar.appendChild(rebuildBtn);
            win.content.appendChild(toolbar);

            const canvasContainer = document.createElement('div');
            canvasContainer.style.flex = '1';
            canvasContainer.style.overflow = 'hidden';
            canvasContainer.style.position = 'relative';
            canvasContainer.style.background = '#111';
            win.content.appendChild(canvasContainer);

            const canvas = document.createElement('canvas');
            canvas.style.position = 'absolute';
            canvasContainer.appendChild(canvas);

            let ctx = canvas.getContext('2d');
            let nodes = [];
            let edges = [];
            
            let transform = { x: 0, y: 0, scale: 1 };
            let isDragging = false;
            let dragNode = null;
            let lastMouse = { x: 0, y: 0 };

            const resizeCanvas = () => {
                canvas.width = canvasContainer.clientWidth;
                canvas.height = canvasContainer.clientHeight;
                if(transform.x === 0) {
                    transform.x = canvas.width / 2;
                    transform.y = canvas.height / 2;
                }
            };
            new ResizeObserver(resizeCanvas).observe(canvasContainer);
            resizeCanvas();

            const buildGraph = () => {
                nodes = [];
                edges = [];
                const detector = this.insight.modules.detector;
                let idCounter = 0;
                const objMap = new Map();

                const addNode = (obj, label, type) => {
                    if (objMap.has(obj)) return objMap.get(obj);
                    const node = {
                        id: idCounter++, obj, label, type,
                        x: Math.random() * 800 - 400,
                        y: Math.random() * 600 - 300,
                        vx: 0, vy: 0, highlighted: false
                    };
                    nodes.push(node);
                    objMap.set(obj, node);
                    return node;
                };

                const addEdge = (from, to, label) => {
                    edges.push({ from, to, label });
                };

                detector.renderers.forEach((r, i) => {
                    const rNode = addNode(r, `WebGLRenderer ${i}`, 'renderer');
                    detector.scenes.forEach(s => {
                        const sNode = addNode(s, s.name || `Scene ${s.uuid.substr(0,4)}`, 'scene');
                        addEdge(rNode, sNode, 'renders');
                        
                        s.children.forEach(c => {
                            const cNode = addNode(c, c.name || c.type, 'object');
                            addEdge(sNode, cNode, 'child');
                        });
                    });
                });
            };

            buildGraph();

            // Spring Physics Interaction
            canvas.addEventListener('mousedown', (e) => {
                const rect = canvas.getBoundingClientRect();
                const mx = (e.clientX - rect.left - transform.x) / transform.scale;
                const my = (e.clientY - rect.top - transform.y) / transform.scale;
                
                dragNode = nodes.find(n => Math.abs(n.x - mx) < 50 && Math.abs(n.y - my) < 20);
                isDragging = true;
                lastMouse = { x: e.clientX, y: e.clientY };
            });

            canvas.addEventListener('mousemove', (e) => {
                if (!isDragging) return;
                const dx = e.clientX - lastMouse.x;
                const dy = e.clientY - lastMouse.y;
                if (dragNode) {
                    dragNode.x += dx / transform.scale;
                    dragNode.y += dy / transform.scale;
                    dragNode.vx = 0; dragNode.vy = 0;
                } else {
                    transform.x += dx;
                    transform.y += dy;
                }
                lastMouse = { x: e.clientX, y: e.clientY };
            });

            canvas.addEventListener('mouseup', () => { isDragging = false; dragNode = null; });
            canvas.addEventListener('mouseleave', () => { isDragging = false; dragNode = null; });

            canvas.addEventListener('wheel', (e) => {
                e.preventDefault();
                const zoom = Math.exp(-e.deltaY * 0.001);
                transform.scale *= zoom;
            });

            searchInput.addEventListener('input', () => {
                const query = searchInput.value.toLowerCase();
                nodes.forEach(n => { n.highlighted = query && n.label.toLowerCase().includes(query); });
            });

            rebuildBtn.addEventListener('click', buildGraph);

            let rAF;
            const loop = () => {
                if (!ctx) return;
                
                // Layout Physics
                if (!dragNode) {
                    for(let i=0; i<nodes.length; i++) {
                        for(let j=i+1; j<nodes.length; j++) {
                            const n1 = nodes[i], n2 = nodes[j];
                            let dx = n1.x - n2.x, dy = n1.y - n2.y;
                            let distSq = dx*dx + dy*dy || 1;
                            if(distSq < 40000) {
                                let f = 1000 / distSq;
                                n1.vx += dx*f; n1.vy += dy*f;
                                n2.vx -= dx*f; n2.vy -= dy*f;
                            }
                        }
                    }
                    edges.forEach(e => {
                        let dx = e.to.x - e.from.x, dy = e.to.y - e.from.y;
                        let dist = Math.sqrt(dx*dx + dy*dy) || 1;
                        let f = (dist - 100) * 0.005;
                        e.from.vx += (dx/dist)*f; e.from.vy += (dy/dist)*f;
                        e.to.vx -= (dx/dist)*f; e.to.vy -= (dy/dist)*f;
                    });
                    nodes.forEach(n => {
                        n.x += n.vx; n.y += n.vy;
                        n.vx *= 0.85; n.vy *= 0.85;
                    });
                }

                ctx.fillStyle = '#111';
                ctx.fillRect(0, 0, canvas.width, canvas.height);

                ctx.save();
                ctx.translate(transform.x, transform.y);
                ctx.scale(transform.scale, transform.scale);

                // Draw Edges
                ctx.lineWidth = 1;
                edges.forEach(e => {
                    ctx.beginPath();
                    ctx.moveTo(e.from.x, e.from.y);
                    ctx.lineTo(e.to.x, e.to.y);
                    ctx.strokeStyle = 'rgba(100, 100, 100, 0.5)';
                    ctx.stroke();
                });

                // Draw Nodes
                ctx.font = '12px Inter';
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';

                nodes.forEach(n => {
                    ctx.fillStyle = n.highlighted ? '#F59E0B' : (n.type === 'scene' ? '#3B82F6' : '#27272A');
                    ctx.strokeStyle = n.highlighted ? '#FFF' : '#3F3F46';
                    ctx.lineWidth = 2;
                    
                    const w = Math.max(100, ctx.measureText(n.label).width + 20);
                    ctx.fillRect(n.x - w/2, n.y - 15, w, 30);
                    ctx.strokeRect(n.x - w/2, n.y - 15, w, 30);
                    
                    ctx.fillStyle = n.highlighted ? '#000' : '#FFF';
                    ctx.fillText(n.label, n.x, n.y);
                });

                ctx.restore();
                rAF = requestAnimationFrame(loop);
            };

            rAF = requestAnimationFrame(loop);
            win.onClose(() => {
                cancelAnimationFrame(rAF);
                ctx = null;
            });
            this.insight.ui.refreshIcons(toolbar);
        }
    }

    /**
     * =========================================================================
     * 7. NETWORK ANALYZER 
     * =========================================================================
     */

    class NetworkAnalyzer extends Module {
        init() {
            this.requests = [];
            this.hookFetch();
            this.hookXHR();
        }

        initUI() {
            this.insight.commands.registerCommand('Network Analyzer', 'globe', () => this.openWindow());
        }

        hookFetch() {
            const origFetch = window.fetch;
            window.fetch = async (...args) => {
                this.addReq(args[0], args[1]?.method || 'GET', 'fetch');
                return origFetch.apply(window, args);
            };
        }

        hookXHR() {
            const origOpen = XMLHttpRequest.prototype.open;
            const self = this;
            XMLHttpRequest.prototype.open = function(method, url) {
                self.addReq(url, method, 'xhr');
                return origOpen.apply(this, arguments);
            };
        }

        addReq(url, method, type) {
            const req = { url, method, type, time: new Date().toLocaleTimeString() };
            this.requests.push(req);
            if (this.requests.length > 200) this.requests.shift(); // Safety limit
            this.emit('new-request', req);
        }

        openWindow() {
            const win = this.insight.ui.createWindow('network_analyzer', 'Network', 'globe');
            if(win.el.style.width === 'auto') { win.el.style.width = '600px'; win.el.style.height = '400px'; }
            
            const tableContainer = document.createElement('div');
            tableContainer.style.cssText = 'width: 100%; height: 100%; overflow: auto;';
            win.content.appendChild(tableContainer);

            const render = () => {
                let html = `<table style="width: 100%; text-align: left; border-collapse: collapse;">
                    <tr style="border-bottom: 1px solid var(--border); color: var(--text-muted); background: var(--bg-base); position: sticky; top: 0;">
                        <th style="padding: 8px;">Time</th><th style="padding: 8px;">Method</th><th style="padding: 8px;">Type</th><th style="padding: 8px;">URL</th>
                    </tr>`;
                this.requests.slice().reverse().forEach(r => {
                    html += `<tr style="border-bottom: 1px solid var(--border);">
                        <td style="padding: 8px; font-family: var(--font-mono); font-size: 11px;">${r.time}</td>
                        <td style="padding: 8px; color: var(--accent); font-weight: 600;">${r.method}</td>
                        <td style="padding: 8px; color: var(--text-muted);">${r.type}</td>
                        <td style="padding: 8px; max-width: 300px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">${r.url}</td>
                    </tr>`;
                });
                tableContainer.innerHTML = html + '</table>';
            };
            
            render();
            const cleanup = this.on('new-request', render);
            win.onClose(cleanup);
        }
    }

    /**
     * =========================================================================
     * 8. FUNCTION TRACER (With Helper UI)
     * =========================================================================
     */

    class FunctionTracer extends Module {
        initUI() {
            this.insight.commands.registerCommand('Function Hooks', 'activity', () => this.openWindow());
        }
        
        trace(obj, methodName) {
            if(!obj || !obj[methodName]) return;
            const orig = obj[methodName];
            if(orig.__isHooked) return;
            
            const self = this;
            obj[methodName] = function(...args) {
                const start = performance.now();
                const res = orig.apply(this, args);
                self.emit('trace', { method: methodName, duration: performance.now() - start });
                return res;
            };
            obj[methodName].__isHooked = true;
            this.insight.ui.showToast(`Hook attached to ${methodName}`);
        }

        openWindow() {
            const win = this.insight.ui.createWindow('func_tracer', 'Function Hooks', 'activity');
            if (win.el.style.width === 'auto') win.el.style.width = '400px';
            
            const hookBtn = (label, target, method) => {
                const btn = document.createElement('button');
                btn.className = 'btn';
                btn.style.width = '100%';
                btn.style.marginBottom = '8px';
                btn.innerHTML = `<i data-lucide="zap"></i> Hook ${label}`;
                btn.onclick = () => { if(window.THREE && window.THREE[target]) this.trace(window.THREE[target].prototype, method); };
                return btn;
            };

            const container = document.createElement('div');
            container.style.padding = '16px';
            container.appendChild(hookBtn('Renderer.render', 'WebGLRenderer', 'render'));
            container.appendChild(hookBtn('Raycaster.intersectObject', 'Raycaster', 'intersectObject'));
            container.appendChild(hookBtn('Object3D.updateMatrixWorld', 'Object3D', 'updateMatrixWorld'));
            
            win.content.appendChild(container);
            this.insight.ui.refreshIcons(win.content);
        }
    }

    /**
     * =========================================================================
     * 9. PERFORMANCE MONITOR
     * =========================================================================
     */

    class PerformanceMonitor extends Module {
        init() {
            this.fps = 0;
            this.drawCalls = 0;
            this.triangles = 0;
            this.hookWebGL();
            this.startLoop();
        }

        initUI() {
            this.insight.commands.registerCommand('Performance Dashboard', 'cpu', () => this.openWindow());
        }

        hookWebGL() {
            const self = this;
            const origDrawElements = WebGLRenderingContext.prototype.drawElements;
            WebGLRenderingContext.prototype.drawElements = function(mode, count, type, offset) {
                self.drawCalls++;
                if (mode === this.TRIANGLES) self.triangles += count / 3;
                return origDrawElements.apply(this, arguments);
            };
            
            if (window.WebGL2RenderingContext) {
                const origDrawElements2 = WebGL2RenderingContext.prototype.drawElements;
                WebGL2RenderingContext.prototype.drawElements = function(mode, count, type, offset) {
                    self.drawCalls++;
                    if (mode === this.TRIANGLES) self.triangles += count / 3;
                    return origDrawElements2.apply(this, arguments);
                };
            }
        }

        startLoop() {
            let frames = 0, lastTime = performance.now();
            const loop = () => {
                frames++;
                const now = performance.now();
                if (now >= lastTime + 1000) {
                    this.fps = (frames * 1000) / (now - lastTime);
                    this.emit('stats', { fps: this.fps, drawCalls: this.drawCalls, triangles: this.triangles });
                    frames = 0; lastTime = now; this.drawCalls = 0; this.triangles = 0;
                }
                requestAnimationFrame(loop);
            };
            requestAnimationFrame(loop);
        }

        openWindow() {
            const win = this.insight.ui.createWindow('perf_mon', 'Performance', 'cpu');
            const updateUI = (stats) => {
                win.content.innerHTML = `
                    <div style="display: flex; flex-direction: column; gap: 12px; padding: 12px;">
                        <div style="display: flex; justify-content: space-between;"><span style="color: var(--text-muted);">FPS</span><span style="font-family: var(--font-mono); font-size: 18px; color: ${stats.fps > 50 ? '#34D399' : '#FBBF24'};">${Math.round(stats.fps)}</span></div>
                        <div style="display: flex; justify-content: space-between;"><span style="color: var(--text-muted);">Draw Calls / s</span><span style="font-family: var(--font-mono); color: var(--accent);">${stats.drawCalls}</span></div>
                        <div style="display: flex; justify-content: space-between;"><span style="color: var(--text-muted);">Triangles / s</span><span style="font-family: var(--font-mono); color: var(--accent);">${Math.round(stats.triangles).toLocaleString()}</span></div>
                    </div>
                `;
            };
            updateUI({ fps: this.fps, drawCalls: this.drawCalls, triangles: this.triangles });
            win.onClose(this.on('stats', updateUI));
        }
    }

    /**
     * =========================================================================
     * 10. DEVELOPER CONSOLE
     * =========================================================================
     */

    class DeveloperConsole extends Module {
        initUI() {
            this.insight.commands.registerCommand('Developer Console', 'terminal', () => this.openWindow());
        }
        
        openWindow() {
            const win = this.insight.ui.createWindow('dev_console', 'Console', 'terminal');
            if (win.el.style.width === 'auto') { win.el.style.width = '600px'; win.el.style.height = '400px'; }
            
            win.content.innerHTML = `
                <div style="display: flex; flex-direction: column; height: 100%;">
                    <div class="console-output" style="flex: 1; overflow-y: auto; padding: 12px; font-family: var(--font-mono); font-size: 12px; background: #000; margin: 8px;">
                        <div style="color: var(--text-muted);">// Insight Platform API available as 'insight'.</div>
                    </div>
                    <div style="display: flex; align-items: center; border-top: 1px solid var(--border); padding: 8px; background: var(--bg-base);">
                        <span style="color: var(--accent); margin-right: 8px; font-weight: 600;">&gt;</span>
                        <input class="console-input" type="text" style="flex: 1; background: transparent; border: none; color: var(--text-main); font-family: var(--font-mono); outline: none;" placeholder="Evaluate JavaScript..." />
                    </div>
                </div>`;
            
            const output = win.content.querySelector('.console-output');
            const input = win.content.querySelector('.console-input');
            
            input.addEventListener('keydown', (e) => {
                if (e.key === 'Enter' && input.value) {
                    const code = input.value; input.value = '';
                    output.innerHTML += `<div style="color: var(--text-muted); margin-top: 8px;">> ${code}</div>`;
                    try {
                        const result = new Function('insight', `return eval(${JSON.stringify(code)})`)(this.insight);
                        output.innerHTML += `<div style="color: #A78BFA;">< ${String(result)}</div>`;
                    } catch (err) {
                        output.innerHTML += `<div style="color: #F87171;">${String(err)}</div>`;
                    }
                    output.scrollTop = output.scrollHeight;
                }
            });
        }
    }

    /**
     * =========================================================================
     * 11. COMMAND PALETTE & SETTINGS & PLUGINS 
     * =========================================================================
     */

    class CommandPalette extends Module {
        initUI() {
            this.commands = [];
            this.filtered = [];
            this.selectedIndex = 0;

            this.el = document.createElement('div');
            this.el.className = 'cmd-overlay';
            this.el.style.display = 'none';

            this.container = document.createElement('div');
            this.container.className = 'cmd-palette';

            this.input = document.createElement('input');
            this.input.className = 'cmd-input';
            this.input.placeholder = 'Search Insight...';

            this.list = document.createElement('div');
            this.list.className = 'cmd-list';

            this.container.appendChild(this.input);
            this.container.appendChild(this.list);
            this.el.appendChild(this.container);
            this.insight.ui.shadowRoot.appendChild(this.el);

            window.addEventListener('keydown', (e) => {
                if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === 'p') {
                    e.preventDefault();
                    this.toggle();
                }
            }, true);

            this.input.addEventListener('input', () => this.filter(this.input.value));
            this.input.addEventListener('keydown', (e) => {
                if (e.key === 'ArrowDown') { e.preventDefault(); this.selectedIndex = Math.min(this.selectedIndex + 1, this.filtered.length - 1); this.renderList(); } 
                else if (e.key === 'ArrowUp') { e.preventDefault(); this.selectedIndex = Math.max(this.selectedIndex - 1, 0); this.renderList(); } 
                else if (e.key === 'Enter') { e.preventDefault(); const cmd = this.filtered[this.selectedIndex]; if (cmd) { this.hide(); cmd.action(); } } 
                else if (e.key === 'Escape') this.hide();
            });

            this.el.addEventListener('click', (e) => { if (e.target === this.el) this.hide(); });
            
            // Helpful default guide command
            this.registerCommand('Open Developer Guide', 'help-circle', () => {
                const win = this.insight.ui.createWindow('dev_guide', 'Developer Guide', 'help-circle');
                win.el.style.width = '500px';
                win.content.innerHTML = `
                    <div style="padding: 16px; line-height: 1.6; color: var(--text-muted);">
                        <h2 style="color: var(--text-main); margin-top: 0;">Scripting Insight</h2>
                        <p>Interact with applications using the <code style="color: var(--accent);">insight</code> global object via Developer Console.</p>
                        <h3 style="color: var(--text-main);">Quick Tips:</h3>
                        <ul style="padding-left: 20px;">
                            <li>Assets: <code>insight.modules.detector.textures</code></li>
                            <li>Inspect: <code>insight.emit('inspect-object', mesh)</code></li>
                            <li>Commands: <code>insight.modules.commands.registerCommand(...)</code></li>
                        </ul>
                    </div>`;
            });
        }

        registerCommand(name, icon, action) { this.commands.push({ name, icon, action }); }
        toggle() { if (this.el.style.display === 'none') this.show(); else this.hide(); }
        show() { this.el.style.display = 'flex'; this.input.value = ''; this.filter(''); this.input.focus(); }
        hide() { this.el.style.display = 'none'; }
        
        filter(q) {
            this.filtered = this.commands.filter(c => c.name.toLowerCase().includes(q.toLowerCase()));
            this.selectedIndex = 0;
            this.renderList();
        }
        
        renderList() {
            this.list.innerHTML = '';
            this.filtered.forEach((cmd, idx) => {
                const item = document.createElement('div');
                item.className = `cmd-item ${idx === this.selectedIndex ? 'selected' : ''}`;
                item.innerHTML = `<i data-lucide="${cmd.icon}"></i> <span>${cmd.name}</span>`;
                item.onclick = () => { this.hide(); cmd.action(); };
                item.onmouseenter = () => { this.selectedIndex = idx; this.renderList(); };
                this.list.appendChild(item);
            });
            this.insight.ui.refreshIcons(this.list);
            const sel = this.list.children[this.selectedIndex];
            if (sel) sel.scrollIntoView({ block: 'nearest' });
        }
    }

    class SettingsManager extends Module {
        initUI() { this.insight.commands.registerCommand('Settings', 'settings', () => this.openWindow()); }
        openWindow() {
            const win = this.insight.ui.createWindow('settings', 'Settings', 'settings');
            win.content.innerHTML = `
                <div style="padding: 16px; color: var(--text-muted);">
                    <h3 style="margin: 0 0 16px 0; font-size: 14px; font-weight: 500; color: var(--text-main);">Preferences</h3>
                    <label style="display: flex; align-items: center; gap: 8px;"><input type="checkbox" checked disabled /> Dark Theme (Zinc)</label><br>
                    <label style="display: flex; align-items: center; gap: 8px;"><input type="checkbox" checked disabled /> Auto-hook Three.js Prototypes</label><br>
                    <button class="btn" style="margin-top: 16px;" onclick="localStorage.clear(); alert('Local storage cleared. Refresh page to reset windows.');">Reset Window Positions</button>
                </div>`;
        }
    }

    class PluginManager extends Module {
        init() {
            window.InsightAPI = {
                registerPlugin: (plugin) => {
                    if (plugin && typeof plugin.init === 'function') {
                        try {
                            plugin.init(this.insight);
                            console.log(`[Insight] Loaded external plugin: ${plugin.name} v${plugin.version}`);
                            if (this.insight.ui) this.insight.ui.showToast(`Plugin Loaded: ${plugin.name}`);
                        } catch (err) { console.error(`[Insight] Failed to load plugin ${plugin.name}:`, err); }
                    }
                }
            };
        }
    }

    /**
     * =========================================================================
     * CORE ORCHESTRATOR
     * =========================================================================
     */

    class InsightCore extends EventEmitter {
        constructor() {
            super();
            this.modules = {};
            window.insight = this;
            this.ui = new UIFramework(this);
            
            // Register All Modules
            this.registerModule('detector', new ThreeDetector(this));
            this.registerModule('performance', new PerformanceMonitor(this));
            this.registerModule('commands', new CommandPalette(this));
            this.registerModule('raycaster', new PickerTool(this));
            this.registerModule('scene', new SceneExplorer(this));
            this.registerModule('inspector', new EntityInspector(this));
            this.registerModule('assets', new AssetExplorer(this));
            this.registerModule('runtimeGraph', new RuntimeObjectExplorer(this));
            this.registerModule('network', new NetworkAnalyzer(this));
            this.registerModule('console', new DeveloperConsole(this));
            this.registerModule('tracer', new FunctionTracer(this));
            this.registerModule('settings', new SettingsManager(this));
            this.registerModule('plugins', new PluginManager(this));
            
            this.initRuntime();
        }

        registerModule(id, instance) {
            this.modules[id] = instance;
        }

        initRuntime() {
            for (const key in this.modules) {
                if (this.modules[key].init) this.modules[key].init();
            }
        }

        initUI() {
            this.ui.mount();
            for (const key in this.modules) {
                if (this.modules[key].initUI) this.modules[key].initUI();
            }
            this.commands = this.modules.commands;
            
            console.log('%c[Insight Platform] Advanced Editor Mode Ready.', 'color: #3B82F6; font-weight: bold;');
            setTimeout(() => { 
                this.ui.showToast('Insight Platform Ready. Press Ctrl+Shift+P to open Command Palette.'); 
            }, 500);
        }
    }

    // Bootstrap
    const insightPlatform = new InsightCore();
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => insightPlatform.initUI());
    } else {
        insightPlatform.initUI();
    }

})();