Spaces:
Running
Running
Download static/3d/szl3d/szl3d_boot.js from SZLHOLDINGS/a11oy: direct link, hf CLI and curl.
- Browser
- Download file 12.6 kB
-
https://huggingface.co/spaces/SZLHOLDINGS/a11oy/resolve/9a08e7c13b7c4e5904853efc8785da8c0dc2e07b/static/3d/szl3d/szl3d_boot.js
- Command line
-
hf download hf://spaces/SZLHOLDINGS/a11oy@9a08e7c13b7c4e5904853efc8785da8c0dc2e07b/static/3d/szl3d/szl3d_boot.js
-
curl -L -o szl3d_boot.js https://huggingface.co/spaces/SZLHOLDINGS/a11oy/resolve/9a08e7c13b7c4e5904853efc8785da8c0dc2e07b/static/3d/szl3d/szl3d_boot.js
12.6 kB
| // SPDX-License-Identifier: Apache-2.0 | |
| // © 2026 Lutar, Stephen P. Jr. — SZL Holdings · ORCID 0009-0001-0110-4173 · Doctrine v11 | |
| // | |
| // szl3d_boot.js — SHARED renderer factory for the holographic estate (Dev0 foundation). | |
| // | |
| // The other 9 surface devs import THIS so every tab shares one renderer setup: | |
| // * WebGPU first (three r170 `three/webgpu` WebGPURenderer), graceful WebGL2 fallback. | |
| // WebGPU is NOT production-safe on Linux/mobile yet (doctrine), so detection is | |
| // defensive: we only use it when navigator.gpu yields a real adapter+device, and | |
| // any failure falls back to WebGLRenderer with NO crash and an honest backend label. | |
| // * Standard scene + perspective camera + OrbitControls + auto-resize. | |
| // * Optional bloom/postprocessing pipeline for the 'holographic' look (UnrealBloomPass). | |
| // | |
| // 0 runtime CDN: all imports resolve through the page's importmap to /static/3d/vendor/. | |
| // Honesty: this module renders pixels only. It NEVER invents data values — values come | |
| // from szl3d_live.poll() and carry doctrine honesty labels (see szl3d_label.js). | |
| // | |
| // Import map every page must include (see VENDOR_MANIFEST.md): | |
| // "three" -> /static/3d/vendor/three/three.module.min.js | |
| // "three/webgpu" -> /static/3d/vendor/three/three.webgpu.min.js | |
| // "three/addons/" -> /static/3d/vendor/three/addons/ | |
| import * as THREE from "three"; | |
| import { OrbitControls } from "three/addons/controls/OrbitControls.js"; | |
| export const SZL3D_VERSION = "1.0.0"; | |
| export const THREE_REVISION = THREE.REVISION; | |
| // Reject if `p` has not settled within `ms`. Used to bound the WebGPU probe: a | |
| // real adapter whose device acquisition hangs (seen on some Linux/driver combos) | |
| // must NOT wedge boot() forever — we time out and fall back to WebGL2 instead. | |
| function _withTimeout(p, ms, tag) { | |
| return new Promise((resolve, reject) => { | |
| let done = false; | |
| const t = setTimeout(() => { if (!done) { done = true; reject(new Error((tag || "op") + " timed out after " + ms + "ms")); } }, ms); | |
| Promise.resolve(p).then( | |
| (v) => { if (!done) { done = true; clearTimeout(t); resolve(v); } }, | |
| (e) => { if (!done) { done = true; clearTimeout(t); reject(e); } }, | |
| ); | |
| }); | |
| } | |
| // --------------------------------------------------------------------------- | |
| // WebGPU capability probe. Returns a real WebGPURenderer (already init()'d) when | |
| // the platform supports it, else null. Never throws, and never hangs: each await | |
| // is bounded by a timeout so a stalled adapter/device falls back to WebGL2. | |
| // --------------------------------------------------------------------------- | |
| async function _tryWebGPU(canvas, opts) { | |
| if (typeof navigator === "undefined" || !("gpu" in navigator)) return null; | |
| const tmo = opts.webgpuTimeoutMs || 2500; | |
| try { | |
| const adapter = await _withTimeout(navigator.gpu.requestAdapter(), tmo, "requestAdapter"); | |
| if (!adapter) return null; | |
| // three r170 ships WebGPURenderer in the dedicated webgpu build only. | |
| const mod = await import("three/webgpu"); | |
| const WebGPURenderer = mod.WebGPURenderer || (mod.default && mod.default.WebGPURenderer); | |
| if (!WebGPURenderer) return null; | |
| const renderer = new WebGPURenderer({ canvas, antialias: opts.antialias !== false, alpha: !!opts.alpha }); | |
| await _withTimeout(renderer.init(), tmo, "renderer.init"); // acquires the device; hang/throw -> caught below | |
| renderer._szlBackend = "webgpu"; | |
| return renderer; | |
| } catch (e) { | |
| // Honest fallback path — log once, do not crash the surface. | |
| if (typeof console !== "undefined") console.warn("[szl3d] WebGPU unavailable, falling back to WebGL2:", e && e.message); | |
| return null; | |
| } | |
| } | |
| function _makeWebGL(canvas, opts) { | |
| const renderer = new THREE.WebGLRenderer({ | |
| canvas, | |
| antialias: opts.antialias !== false, | |
| alpha: !!opts.alpha, | |
| powerPreference: opts.powerPreference || "high-performance", | |
| }); | |
| renderer._szlBackend = "webgl2"; | |
| return renderer; | |
| } | |
| // --------------------------------------------------------------------------- | |
| // boot(container, opts) -> Promise<Stage> | |
| // | |
| // container : DOM element (or canvas). If an element, a <canvas> is created inside. | |
| // opts: | |
| // webgpu (bool, default true) attempt WebGPU first | |
| // forceWebGL (bool, default false) skip WebGPU entirely (used by the fallback selftest) | |
| // bloom (bool|object, default false) enable the holographic bloom pass | |
| // object: {strength, radius, threshold} | |
| // background (THREE.Color|number|null) scene background (default 0x05070d) | |
| // cameraFov, cameraNear, cameraFar, cameraPos:[x,y,z] | |
| // antialias, alpha, powerPreference, pixelRatioCap (default 2) | |
| // orbit (bool, default true) attach OrbitControls | |
| // | |
| // Returns a Stage object: | |
| // { renderer, scene, camera, controls, backend, composer|null, bloomPass|null, | |
| // start(loop?), stop(), resize(), render(), dispose(), setBloom(on), onFrame(fn) } | |
| // --------------------------------------------------------------------------- | |
| export async function boot(container, opts = {}) { | |
| if (!container) throw new Error("szl3d.boot: container is required"); | |
| const isCanvas = (typeof HTMLCanvasElement !== "undefined") && (container instanceof HTMLCanvasElement); | |
| const host = isCanvas ? container.parentElement || document.body : container; | |
| const canvas = isCanvas ? container : document.createElement("canvas"); | |
| if (!isCanvas) { | |
| canvas.style.display = "block"; | |
| canvas.style.width = "100%"; | |
| canvas.style.height = "100%"; | |
| host.appendChild(canvas); | |
| } | |
| let renderer = null; | |
| if (!opts.forceWebGL && opts.webgpu !== false) { | |
| renderer = await _tryWebGPU(canvas, opts); | |
| } | |
| if (!renderer) renderer = _makeWebGL(canvas, opts); | |
| const backend = renderer._szlBackend; | |
| const pixelRatioCap = opts.pixelRatioCap || 2; | |
| renderer.setPixelRatio(Math.min((typeof window !== "undefined" ? window.devicePixelRatio : 1) || 1, pixelRatioCap)); | |
| const scene = new THREE.Scene(); | |
| if (opts.background !== null) { | |
| scene.background = new THREE.Color(opts.background == null ? 0x05070d : opts.background); | |
| } | |
| const camera = new THREE.PerspectiveCamera( | |
| opts.cameraFov || 55, 1, opts.cameraNear || 0.1, opts.cameraFar || 4000, | |
| ); | |
| const cp = opts.cameraPos || [0, 6, 18]; | |
| camera.position.set(cp[0], cp[1], cp[2]); | |
| camera.lookAt(0, 0, 0); | |
| let controls = null; | |
| if (opts.orbit !== false && typeof renderer.domElement !== "undefined") { | |
| try { | |
| controls = new OrbitControls(camera, renderer.domElement); | |
| controls.enableDamping = true; | |
| controls.dampingFactor = 0.08; | |
| } catch (_) { controls = null; } | |
| } | |
| // Default holographic lighting so a freshly-booted scene is never pitch black. | |
| const amb = new THREE.AmbientLight(0xffffff, 0.35); | |
| const key = new THREE.DirectionalLight(0x8fd7ff, 1.1); | |
| key.position.set(8, 16, 10); | |
| scene.add(amb, key); | |
| // -------- optional bloom/postprocessing (holographic glow) -------- | |
| // Bloom uses the WebGL EffectComposer. On the WebGPU backend three exposes a | |
| // different post pipeline (PostProcessing/TSL); to keep the foundation honest and | |
| // identical across the fallback we only wire EffectComposer bloom on WebGL2 and | |
| // expose setBloom() as a no-op-safe toggle elsewhere. | |
| let composer = null, bloomPass = null, renderPass = null, outputPass = null; | |
| const bloomReq = !!opts.bloom; | |
| async function _buildComposer() { | |
| if (backend !== "webgl2") return; // see note above; WebGPU bloom is a per-surface opt-in TODO | |
| const { EffectComposer } = await import("three/addons/postprocessing/EffectComposer.js"); | |
| const { RenderPass } = await import("three/addons/postprocessing/RenderPass.js"); | |
| const { UnrealBloomPass } = await import("three/addons/postprocessing/UnrealBloomPass.js"); | |
| const { OutputPass } = await import("three/addons/postprocessing/OutputPass.js"); | |
| composer = new EffectComposer(renderer); | |
| renderPass = new RenderPass(scene, camera); | |
| composer.addPass(renderPass); | |
| const b = (typeof opts.bloom === "object" && opts.bloom) || {}; | |
| bloomPass = new UnrealBloomPass( | |
| new THREE.Vector2(1, 1), | |
| b.strength != null ? b.strength : 0.9, | |
| b.radius != null ? b.radius : 0.5, | |
| b.threshold != null ? b.threshold : 0.15, | |
| ); | |
| composer.addPass(bloomPass); | |
| outputPass = new OutputPass(); | |
| composer.addPass(outputPass); | |
| } | |
| if (bloomReq) { try { await _buildComposer(); } catch (e) { if (console) console.warn("[szl3d] bloom unavailable:", e && e.message); } } | |
| // -------- sizing -------- | |
| // `window.resize` alone misses layout-only changes (drawer expansion, dvh | |
| // updates, split-pane resizing, font/tool-bar reflow). Observe the element | |
| // that actually owns the canvas as well. The observer is deliberately | |
| // coalesced to one animation-frame callback and `_size` deduplicates equal | |
| // dimensions, preventing renderer.setSize() from creating a resize loop. | |
| let _disposed = false; | |
| let _lastWidth = 0, _lastHeight = 0; | |
| let _observerRaf = 0; | |
| let _resizeObserver = null; | |
| function _dimensions() { | |
| const w = Math.max(1, host.clientWidth || canvas.clientWidth || 1); | |
| const h = Math.max(1, host.clientHeight || canvas.clientHeight || 1); | |
| return { w, h }; | |
| } | |
| function _size() { | |
| if (_disposed) return; | |
| const { w, h } = _dimensions(); | |
| _lastWidth = w; | |
| _lastHeight = h; | |
| renderer.setSize(w, h, false); | |
| if (composer) composer.setSize(w, h); | |
| if (bloomPass && bloomPass.resolution) bloomPass.resolution.set(w, h); | |
| camera.aspect = w / h; | |
| camera.updateProjectionMatrix(); | |
| } | |
| function _queueObservedSize() { | |
| if (_disposed || _observerRaf) return; | |
| const { w, h } = _dimensions(); | |
| if (w === _lastWidth && h === _lastHeight) return; | |
| if (typeof requestAnimationFrame === "function") { | |
| _observerRaf = requestAnimationFrame(() => { | |
| _observerRaf = 0; | |
| _size(); | |
| }); | |
| return; | |
| } | |
| // Non-browser/headless fallback: ResizeObserver itself is already async. | |
| _size(); | |
| } | |
| const _frameCbs = []; | |
| function onFrame(fn) { if (typeof fn === "function") _frameCbs.push(fn); } | |
| function render() { | |
| if (controls) controls.update(); | |
| for (let i = 0; i < _frameCbs.length; i++) { try { _frameCbs[i](stage); } catch (_) {} } | |
| if (composer) composer.render(); | |
| else renderer.render(scene, camera); | |
| } | |
| let _raf = 0, _running = false; | |
| function start(loopFn) { | |
| if (loopFn) onFrame(loopFn); | |
| _running = true; | |
| const tick = () => { | |
| if (!_running) return; | |
| render(); | |
| _raf = (typeof requestAnimationFrame !== "undefined") ? requestAnimationFrame(tick) : 0; | |
| }; | |
| tick(); | |
| } | |
| function stop() { | |
| _running = false; | |
| if (_raf && typeof cancelAnimationFrame !== "undefined") cancelAnimationFrame(_raf); | |
| _raf = 0; | |
| } | |
| function setBloom(on) { | |
| if (bloomPass) bloomPass.enabled = !!on; | |
| } | |
| function dispose() { | |
| _disposed = true; | |
| stop(); | |
| if (_observerRaf && typeof cancelAnimationFrame !== "undefined") { | |
| cancelAnimationFrame(_observerRaf); | |
| _observerRaf = 0; | |
| } | |
| try { if (_resizeObserver) _resizeObserver.disconnect(); } catch (_) {} | |
| _resizeObserver = null; | |
| try { if (controls) controls.dispose(); } catch (_) {} | |
| try { if (composer && composer.dispose) composer.dispose(); } catch (_) {} | |
| try { renderer.dispose(); } catch (_) {} | |
| if (typeof window !== "undefined") window.removeEventListener("resize", _size); | |
| } | |
| if (typeof window !== "undefined") window.addEventListener("resize", _size); | |
| if (typeof ResizeObserver !== "undefined") { | |
| try { | |
| _resizeObserver = new ResizeObserver(_queueObservedSize); | |
| _resizeObserver.observe(host); | |
| } catch (_) { | |
| // Unsupported/non-Element hosts retain the existing window resize path. | |
| _resizeObserver = null; | |
| } | |
| } | |
| _size(); | |
| const stage = { | |
| renderer, scene, camera, controls, backend, | |
| composer, bloomPass, | |
| THREE, | |
| start, stop, render, resize: _size, dispose, setBloom, onFrame, | |
| hasBloom: () => !!bloomPass, | |
| }; | |
| return stage; | |
| } | |
| // Synchronous capability hint (no device acquisition) for UIs that want to show | |
| // the likely backend before boot resolves. Honest: presence of navigator.gpu is | |
| // necessary-not-sufficient; boot() may still fall back. | |
| export function probeBackend() { | |
| const gpu = (typeof navigator !== "undefined") && ("gpu" in navigator); | |
| return { webgpuLikely: !!gpu, three: THREE.REVISION, szl3d: SZL3D_VERSION }; | |
| } | |
| export default { boot, probeBackend, SZL3D_VERSION, THREE_REVISION, THREE }; | |