ruvnet/RuView · error · Error

Three.js not loaded

Error message

Three.js not loaded

What it means

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.

Source

Thrown at ui/mobile/src/assets/webview/gaussian-splats.html:126

            g = t;
            b = 1 - t;
          } else {
            const t = (clamped - 0.5) * 2;
            r = t;
            g = 1 - t;
            b = 0;
          }
          return [r, g, b];
        }

        // ---- GaussianSplatRenderer -------------------------------------------

        class GaussianSplatRenderer {
          /** @param {HTMLElement} container - DOM element to attach the renderer to */
          constructor(container, opts = {}) {
            const THREE = getThree();
            if (!THREE) {
              throw new Error('Three.js not loaded');
            }

            this.container = container;
            this.width = opts.width || container.clientWidth || 800;
            this.height = opts.height || 500;

            // Scene
            this.scene = new THREE.Scene();
            this.scene.background = new THREE.Color(0x0a0e1a);

            // Camera — perspective looking down at the room
            this.camera = new THREE.PerspectiveCamera(45, this.width / this.height, 0.1, 200);
            this.camera.position.set(0, 10, 12);
            this.camera.lookAt(0, 0, 0);

            // Renderer
            this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
            this.renderer.setSize(this.width, this.height);

View on GitHub (pinned to 4685618388)

Solutions

  1. Bundle three@0.165 and OrbitControls locally next to gaussian-splats.html and reference them with relative paths instead of CDN URLs
  2. Construct the renderer only after window load (or the scripts' onload), not on DOMContentLoaded
  3. Add an availability check before constructing and show a friendly '3D viewer unavailable offline' message
  4. If CSP must stay, add the CDN origins to script-src

Example fix

<!-- before -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r165/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.165.0/examples/js/controls/OrbitControls.js"></script>

<!-- after: local, offline-safe assets -->
<script src="./vendor/three.min.js"></script>
<script src="./vendor/OrbitControls.js"></script>
Defensive patterns

Strategy: type-guard

Validate before calling

// Run before constructing the renderer
if (!window.THREE || !window.THREE.Scene) {
  showFallbackMessage('3D viewer requires Three.js, which failed to load. Check connectivity or use the bundled assets.');
  return;
}
const renderer = new GaussianSplatRenderer(container, opts);

Type guard

/** True when the Three.js runtime (and OrbitControls) is available. */
function isThreeLoaded() {
  return typeof window !== 'undefined'
    && Boolean(window.THREE)
    && typeof window.THREE.Scene === 'function'
    && typeof window.OrbitControls === 'function';
}

Prevention

When it happens

Trigger: 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.

Common situations: Mobile app WebView in offline or first-launch mode; privacy/adblock tooling blocking CDNs; regional CDN outage; opening the HTML via file:// without connectivity.


AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16). Data as JSON: /api/errors/69b9af05bc92ac12. Report an issue: GitHub.