{"record":{"id":"69b9af05bc92ac12","repo":"ruvnet/RuView","slug":"three-js-not-loaded","errorCode":null,"errorMessage":"Three.js not loaded","messagePattern":"Three\\.js not loaded","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ui/mobile/src/assets/webview/gaussian-splats.html","lineNumber":126,"sourceCode":"            g = t;\n            b = 1 - t;\n          } else {\n            const t = (clamped - 0.5) * 2;\n            r = t;\n            g = 1 - t;\n            b = 0;\n          }\n          return [r, g, b];\n        }\n\n        // ---- GaussianSplatRenderer -------------------------------------------\n\n        class GaussianSplatRenderer {\n          /** @param {HTMLElement} container - DOM element to attach the renderer to */\n          constructor(container, opts = {}) {\n            const THREE = getThree();\n            if (!THREE) {\n              throw new Error('Three.js not loaded');\n            }\n\n            this.container = container;\n            this.width = opts.width || container.clientWidth || 800;\n            this.height = opts.height || 500;\n\n            // Scene\n            this.scene = new THREE.Scene();\n            this.scene.background = new THREE.Color(0x0a0e1a);\n\n            // Camera — perspective looking down at the room\n            this.camera = new THREE.PerspectiveCamera(45, this.width / this.height, 0.1, 200);\n            this.camera.position.set(0, 10, 12);\n            this.camera.lookAt(0, 0, 0);\n\n            // Renderer\n            this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });\n            this.renderer.setSize(this.width, this.height);","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/ruvnet/RuView/blob/4685618388a5e49fad5b3005806f3bdd6a7c25c3/ui/mobile/src/assets/webview/gaussian-splats.html#L108-L144","documentation":"GaussianSplatRenderer's constructor calls getThree() (defined as () => window.THREE) and throws when it returns undefined. The page loads Three.js r165 and OrbitControls.js from public CDNs (cdnjs.cloudflare.com and cdn.jsdelivr.net, gaussian-splats.html:34-35), so this error means those CDN script tags failed to load before the renderer was constructed.","triggerScenarios":"Android/iOS WebView opening the asset with no network or a blocked CDN (offline device, firewall, DNS failure); a page CSP whose script-src does not include cdnjs.cloudflare.com/cdn.jsdelivr.net; construction running before the CDN scripts finished loading; corporate network MITM blocking third-party CDNs.","commonSituations":"Mobile app WebView in offline or first-launch mode; privacy/adblock tooling blocking CDNs; regional CDN outage; opening the HTML via file:// without connectivity.","solutions":["Bundle three@0.165 and OrbitControls locally next to gaussian-splats.html and reference them with relative paths instead of CDN URLs","Construct the renderer only after window load (or the scripts' onload), not on DOMContentLoaded","Add an availability check before constructing and show a friendly '3D viewer unavailable offline' message","If CSP must stay, add the CDN origins to script-src"],"exampleFix":"<!-- before -->\n<script src=\"https://cdnjs.cloudflare.com/ajax/libs/three.js/r165/three.min.js\"></script>\n<script src=\"https://cdn.jsdelivr.net/npm/three@0.165.0/examples/js/controls/OrbitControls.js\"></script>\n\n<!-- after: local, offline-safe assets -->\n<script src=\"./vendor/three.min.js\"></script>\n<script src=\"./vendor/OrbitControls.js\"></script>","handlingStrategy":"type-guard","validationCode":"// Run before constructing the renderer\nif (!window.THREE || !window.THREE.Scene) {\n  showFallbackMessage('3D viewer requires Three.js, which failed to load. Check connectivity or use the bundled assets.');\n  return;\n}\nconst renderer = new GaussianSplatRenderer(container, opts);","typeGuard":"/** True when the Three.js runtime (and OrbitControls) is available. */\nfunction isThreeLoaded() {\n  return typeof window !== 'undefined'\n    && Boolean(window.THREE)\n    && typeof window.THREE.Scene === 'function'\n    && typeof window.OrbitControls === 'function';\n}","tryCatchPattern":null,"preventionTips":["Vendor three.min.js and OrbitControls.js next to the HTML instead of loading them from CDNs","Construct renderers after window load, not DOMContentLoaded, when scripts are remote","Add script onerror handlers to surface load failures before first use"],"tags":["threejs","webview","cdn","offline","mobile"],"backgroundTag":null,"analyzedSha":"4685618388a5e49fad5b3005806f3bdd6a7c25c3","analyzedAt":"2026-08-16T06:09:40.886Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}